5

I am new to solidity and am following a tutorial that uses solidity compiler version 0.4.25. In the tutorial, solc.compile is used in a compile.js file followed by extract abi and bytecode and generating json files by using the following codes:

const output = solc.compile(contractSource, 1);

for (let contract in output.contracts){
    fileSystem.outputJSONSync(
        path.resolve(exportPath,"Interface.json"),
        output.contracts[contract].interface
    );

    fileSystem.outputJSONSync(
        path.resolve(exportPath,"ByteCode.json"),
        output.contracts[contract].bytecode
    );
}

I am trying to compile a contract using solidity compiler version 0.5.3 instead and am able to get the output from the compiler by changing the codes to:

var input = {
    language: 'Solidity',
    sources: {
        'Voting.sol': {
            content: votingSource
        }
    },
    settings: {
        outputSelection: {
            '*': {
                '*': [ '*' ]
            }
        }
    }
}

const output = JSON.parse(solc.compile(JSON.stringify(input)),1);

However, I am unable to find the abi and bytecode using:

output.contracts[contract].interface
output.contracts[contract].bytecode

I think it is because the output structure is different from the output compiled using version 0.4.25 and that there isn't interface in the structure compiled using version 0.5.3. I would like to know what do I use instead to get the same json file outputs using the newer compiler version as well as how to get pass the error I encountered which I will show below.

I run compile.js in terminal and get the following error

TypeError: Cannot read property 'replace' of undefined at stringify (...\node_modules\fs-extra\node_modules\jsonfile\index.js:88:14) at Object.writeFileSync (...\node_modules\fs-extra\node_modules\jsonfile\index.js:115:13) at Object.outputJsonSync (...\node_modules\fs-extra\lib\json\output-json-sync.js:15:12) at Object. (...\smartContract\compile.js:35:20) at Module._compile (internal/modules/cjs/loader.js:722:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:733:10) at Module.load (internal/modules/cjs/loader.js:620:32) at tryModuleLoad (internal/modules/cjs/loader.js:560:12) at Function.Module._load (internal/modules/cjs/loader.js:552:3) at Function.Module.runMain (internal/modules/cjs/loader.js:775:12)

Here's my codes. Voting.sol

pragma solidity ^0.5.3;

contract Voting {

    address chairPersonAddress;

    struct Candidate {
        address candidateAddress;
        uint votes;
    }

    struct Vote{
        uint votedCandidateIndex;
        bool alreadyVoted;
    }

    modifier onlyChairPerson(){
        require(msg.sender == chairPersonAddress);
        _;
    }

    mapping(address => Vote) public voterAddressToTheirVote;

    Candidate[] public candidates;

    constructor(address _chairPersonAddress) public {
        chairPersonAddress = _chairPersonAddress;
    }

    function nominateCandidate(address _candidateAddress) onlyChairPerson public {
        Candidate memory newCandidate = Candidate({
            candidateAddress: _candidateAddress,
            votes: 0
        });

        candidates.push(newCandidate);
    }

    function vote(uint _candidateIndex) public {
        Vote memory existingVote = voterAddressToTheirVote[msg.sender];
        //If voter vote for the first candidate in the list - the index is always 0
        if(_candidateIndex == 0){
            require(existingVote.alreadyVoted == false, "You already voted for the first candidate");
            _addNewVote(_candidateIndex);
        }
        else{
            require(existingVote.votedCandidateIndex != _candidateIndex && existingVote.alreadyVoted == false, "You already voted for this candidate");
            _addNewVote(_candidateIndex);
        }
    }

    function _addNewVote(uint _candidateIndex) private {
        Vote memory newVote = Vote({
            votedCandidateIndex: _candidateIndex,
            alreadyVoted: true
        });

        voterAddressToTheirVote[msg.sender] = newVote;

        candidates[_candidateIndex].votes++;
    }

    function numberOfCandidates() public view returns(uint){
        return candidates.length;
    }
}

compile.js

const path = require("path");
const solc = require("solc");
const fileSystem = require("fs-extra");

//Preparing for bin folder
const exportPath = path.resolve(__dirname, "bin");
fileSystem.removeSync(exportPath);

//Get contract path
const votingContract = path.resolve(__dirname, "contracts", "Voting.sol");

//Read the contract from voting path
const votingSource = fileSystem.readFileSync(votingContract, "utf8");

var input = {
    language: 'Solidity',
    sources: {
        'Voting.sol': {
            content: votingSource
        }
    },
    settings: {
        outputSelection: {
            '*': {
                '*': [ '*' ]
            }
        }
    }
}

try{
    const output = JSON.parse(solc.compile(JSON.stringify(input)),1);

    for (let contract in output.contracts){
        fileSystem.outputJSONSync(
            path.resolve(exportPath,"VotingABI.json"),
            output.contracts[contract].interface
        );

        fileSystem.outputJSONSync(
            path.resolve(exportPath,"VotingBytecode.json"),
            output.contracts[contract].bytecode
        ); 
    }  

}catch(error){
    console.log(error);
}

4 Answers 4

4

Replace your for loop with this

    for (let contract in output.contracts["Voting.sol"]) {
    fileSystem.outputJSONSync(
      path.resolve(exportPath, "VotingABI.json"),
      output.contracts["Voting.sol"][contract].abi
    );

    fileSystem.outputJSONSync(
      path.resolve(exportPath, "VotingBytecode.json"),
      output.contracts["Voting.sol"][contract].evm.bytecode.object
    );
  }

For reference usage of solcjs , please check https://www.npmjs.com/package/solc

I strongly recommend using Truffle for compiling and deploying such contracts because it is easy and awesome.

Disclaimer - I work for Consensys

5

Solution to get the interface and bytecode:

  • "solc": "^0.8.3",
  • "web3": "^1.3.5"
const path = require('path');
const fs = require('fs');
const solc = require('solc');

const inboxPath = path.resolve(__dirname, 'contracts', 'inbox.sol');
const source = fs.readFileSync(inboxPath, 'utf-8');

var input = {
    language: 'Solidity',
    sources: {
        'inbox.sol' : {
            content: source
        }
    },
    settings: {
        outputSelection: {
            '*': {
                '*': [ '*' ]
            }
        }
    }
}; 

const output = JSON.parse(solc.compile(JSON.stringify(input)));

const interface = output.contracts['inbox.sol'].Inbox.abi;
const bytecode = output.contracts['inbox.sol'].Inbox.evm.bytecode.object;

module.exports = {
    interface,
    bytecode,
};
0
0

I have a simpler solution for accomplishing your task:

const fs = require('fs');
const solc = require('solc');
const input = fs.readFileSync('/path/to/.sol/file');
const output = solc.compile(input.toString(), 1);
const bytecode = output.contracts[':ContractName'].bytecode;
const abi = JSON.parse(output.contracts[':ContractName'].interface);

console.log('\nBytecode: ', bytecode, '\nABI: ', abi);

This will give you the bytecode and abi for your contract.

0

0.5.3 does not generate interface in JSON - I think docs say so ...

to get abi and bytecode from your newly formatted JSON - I do following JSON.stringify(compiledFactory.abi) compiledFactory.evm.bytecode

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.