0

So I have this codes

  const MultiSigWalletFactory = fs.readFileSync(path.resolve(__dirname, "MultiSigWalletFactory.sol"), "utf8");
  const Factory = fs.readFileSync(path.resolve(__dirname, "Factory.sol"), "utf8");
  const MultiSigWallet = fs.readFileSync(path.resolve(__dirname, "MultiSigWallet.sol"), "utf8");
  const input = {
    language: "Solidity",
    sources: {
      "Factory.sol": Factory,
      "MultiSigWallet.sol": MultiSigWallet,
      "MultiSigWalletFactory.sol": MultiSigWalletFactory,
    },
    settings: {
      outputSelection: {
        '*': {
          '*': ['*'],
        },
      },
    },
  };
  const output = solc.compile(input);

it will output bytecode and ABI for each file.

How can I deploy this to the blockchain using web3?

4
  • What version of web3.js are you using? Mar 24 '20 at 10:49
  • the latest version from npm install web3
    – bbnn
    Mar 24 '20 at 10:50
  • Please run npm ls web3 and tell us what you get. Mar 24 '20 at 10:51
  • it's web3@1.2.6
    – bbnn
    Mar 24 '20 at 10:55
0

You can try this for each contract (tested with web3.js v1.2.1):

const fs   = require("fs");
const Web3 = require("web3");

const NODE_ADDRESS  = "your ethereum node URL";
const PRIVATE_KEY   = "your private key";
const CONTRACT_NAME = "your contract name (not file name)";
const CONTRACT_ARGS = ["constructor argument 1", "constructor argument 2", ...];
const ARTIFACTS_DIR = "<the relative path from this script to your abi & bin folder>";

async function scan(message) {
    process.stdout.write(message);
    return await new Promise(function(resolve, reject) {
        process.stdin.resume();
        process.stdin.once("data", function(data) {
            process.stdin.pause();
            resolve(data.toString().trim());
        });
    });
}

async function getGasPrice(web3) {
    while (true) {
        const nodeGasPrice = await web3.eth.getGasPrice();
        const userGasPrice = await scan(`Enter gas-price or leave empty to use ${nodeGasPrice}: `);
        if (/^\d+$/.test(userGasPrice))
            return userGasPrice;
        if (userGasPrice == "")
            return nodeGasPrice;
        console.log("Illegal gas-price");
    }
}

async function getTransactionReceipt(web3) {
    while (true) {
        const hash = await scan("Enter transaction-hash or leave empty to retry: ");
        if (/^0x([0-9A-Fa-f]{64})$/.test(hash)) {
            const receipt = await web3.eth.getTransactionReceipt(hash);
            if (receipt)
                return receipt;
            console.log("Invalid transaction-hash");
        }
        else if (hash) {
            console.log("Illegal transaction-hash");
        }
        else {
            return null;
        }
    }
}

async function send(web3, account, transaction) {
    while (true) {
        try {
            const options = {
                data    : transaction.encodeABI(),
                gas     : await transaction.estimateGas({from: account.address}),
                gasPrice: await getGasPrice(web3),
            };
            const signed  = await web3.eth.accounts.signTransaction(options, account.privateKey);
            const receipt = await web3.eth.sendSignedTransaction(signed.rawTransaction);
            return receipt;
        }
        catch (error) {
            console.log(error.message);
            const receipt = await getTransactionReceipt(web3);
            if (receipt)
                return receipt;
        }
    }
}

async function run() {
    const web3        = new Web3(NODE_ADDRESS);
    const account     = web3.eth.accounts.privateKeyToAccount(PRIVATE_KEY);
    const path        = __dirname + "/" + ARTIFACTS_DIR + "/" + CONTRACT_NAME;
    const abi         = fs.readFileSync(path + ".abi", {encoding: "utf8"});
    const bin         = fs.readFileSync(path + ".bin", {encoding: "utf8"});
    const contract    = new web3.eth.Contract(JSON.parse(abi));
    const options     = {data: "0x" + bin, arguments: CONTRACT_ARGS};
    const transaction = contract.deploy(options);
    const receipt     = await send(web3, account, transaction);
    console.log(CONTRACT_NAME, "deployed at", receipt.contractAddress);
    if (web3.currentProvider.constructor.name == "WebsocketProvider")
        web3.currentProvider.connection.close();
}

run();
12
  • Thank you for your answer, so I have to deploy each compiled dependency?
    – bbnn
    Mar 24 '20 at 11:06
  • @bbnn: What does "compiled dependency" mean? You need to deploy each contract. Mar 24 '20 at 11:08
  • The solidity files I have are MultiSigWalletFactory.sol, Factory.sol, and MultiSigWallet.sol. I compiled them with solc.js and for each file it has different interface and bytecode.
    – bbnn
    Mar 24 '20 at 11:10
  • @bbnn: You can take your output.abi and output.bytecode, and use them as the values of abi and bin in my script (or alternatively, place them inside two files named YourContractName.abi and YourContractName.bin, and then set ARTIFACTS_DIR to point to the folder were you place these two files). Mar 24 '20 at 11:15
  • Thank you for your answer, I have another question about the interface and bytecode output footprint. Should I keep them safe? or it doesn't matter as long as I have the private key of the contract creator address?
    – bbnn
    Mar 24 '20 at 13:57
0
  • Create a Web3 Instance
const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider("http://SERVER_IP:PORT"));
  • From the compiled input i.e. output extract bytecode and abi
const FactoryABI = JSON.parse(output.contracts[':Factory'].interface);
const MultiSigWalletABI = JSON.parse(output.contracts[':MultiSigWallet'].interface);
const MultiSigWalletFactoryABI = JSON.parse(output.contracts[':MultiSigWalletFactory'].interface);

const FactoryBytecode = output.contracts[':Factory'].bytecode;
const MultiSigWalletBytecode = output.contracts[':MultiSigWallet'].bytecode;
const MultiSigWalletFactoryBytecode = output.contracts[':MultiSigWalletFactory'].bytecode;
  • Deploy the contracts using web3
const FactoryContract = new web3.eth.Contract(FactoryABI);
// Deploy FactoryContract
FactoryContract.deploy({
    data: FactoryBytecode,
    arguments: ["If it takes arguments in constructor pass those over here"]
}).send({
    from: "ACCOUNT THROUGH WHICH IT SHOULD BE DEPLOYED",
    gas: "GAS_LIMIT"
});

Similarly, MultisigWallet & MultisigwalletFactory can be deployed.
1
  • Prior to executing this script, ACCOUNT THROUGH WHICH IT SHOULD BE DEPLOYED has to be unlocked on the node that this user is communicating with (via an RPC request to the node, assuming that this API is enabled on the node). Note this unlocking your account on a node is not recommend, since anyone hacking that node may exploit your account at will. So while this method may be good enough when testing on your private network (e.g., via Truffle & Ganache), it is not recommended for operational mode. Mar 24 '20 at 11:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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