4

I'm using a function in my NodeJS app to deploy contracts. The user inputs the contract he wishes to deploy and the app deploys it. The structure of the app is

.
├── app
│   ├── models
│   │   └── user.js
│   └── routes.js
├── cert.pem
├── config
│   ├── auth.js
│   ├── database.js
│   └── passport.js
├── contracts
│   ├── Registry.sol
│   ├── TrustEntity.sol
│   └── User.sol
├── key.pem
├── modules
│   ├── contracts.js
│   └── helpers.js

TrustEntity.sol is

pragma solidity ^0.4.11;
import "./User.sol";

contract TrustEntity {
    address owner;
    address registry;
    address[] pendingRequests;

    function pushPending(address requester) {
        pendingRequests.push(requester);
    }
}

and User.sol is

pragma solidity ^0.4.11;
import "./TrustEntity.sol";

contract User {
    // State variables
    TrustEntity trustEntity;
    address owner = msg.sender;
    bool verified = false;
    uint creationTime = now;
    uint level = 0;
    address[] public pendingRequests;

    // Set trustEntity's deployed contract address
    function User(address _trustEntity) {
        trustEntity = TrustEntity(_trustEntity);
    }

    function requestValidation() {
        trustEntity.pushPending(owner);
    }
}

Finally, the relevant part of the deploy function is

function deploy(contractName, publicAddress, _gas) {
    // Get the contract code from contracts
    const input = fs.readFileSync('contracts/' + contractName + '.sol').toString();
    const output = solc.compile(input);
    // The trailing ':' is needed otherwise it crashes
    const bytecode = output.contracts[':' + contractName].bytecode;
    const abi = JSON.parse(output.contracts[':' + contractName].interface);
    console.log(abi[0].inputs[0]);
    const contract = web3.eth.contract(abi);
    console.log("Contract:" + contract);
    const contractInstance = contract.new({
    .
    .
    .
}

When I try it, the following error is returned

{ contracts: {},
  errors: [ ':2:1: ParserError: Source "User.sol" not found: File not supplied initially.\nimport "./User.sol";\n^------------------^\n' ],
  sourceList: [ '' ],
  sources: {} }
TypeError: Cannot read property 'bytecode' of undefined

even though the docs say (as expected) that . refers to the current directory. Specifically, they say: "To import a file x from the same directory as the current file, use import "./x" as x;". Also, it was working fine in Remix so I'm not sure where the error is.

mcansado
  • 841
  • 8
  • 25

3 Answers3

0

you need to tell the app where is the directory that contains your contracts.

try this code:

const contractPath = 'contracts/';

const input = fs.readFileSync(contractPath + contractName + '.sol').toString(); const output = solc.compile(input, 1, fileResolver);

function fileResolver(path) { return { contents: fs.readFileSync(contractPath + path).toString() }; }

the fileResolver function is used to specify the contracts/ directory . The solc.compile method is then called with the fileResolver function as the third argument.

have a try, and good luck.

david fnck
  • 135
  • 2
0

You need to import each contract as a string and then pass them all to solidity https://github.com/ethereum/solc-js#from-version-016

0

This works for me:

    fs.readFile(fullFileName, 'utf8', (err, data) => {

    const compiled = solc.compile(data);

    const bytecode = compiled.contracts[':' + name].bytecode
    const abi = JSON.parse(compiled.contracts[':' + name].interface)

    ...

    const contractData = '0x' + bytecode

    const rawTx = {
        nonce: nonceHex,
        gasPrice: gasPriceHex,
        gasLimit: gasLimitHex,
        data: contractData,
        from: mainAccount
    };


    const tx = new EthTx(rawTx)
    tx.sign(new Buffer(pKey, 'hex'))
    const txHex = tx.serialize().toString('hex')

    web3.eth.sendSignedTransaction(`0x${txHex}`).on('receipt', (receipt) => {

        ...
Renaud
  • 349
  • 2
  • 11