1

I am trying to deploy smart contract using web3 1.2.6 , my smart contract accepts 2 argument in constructor : id , name. I dont know what i am doing wrong , but both approaches are not working. Error (Approach 1 - You must provide the json interface of the contract when instantiating a contract object || myContract.new.getData is not a function) Error (Approach 2 - The method eth_sendTransaction not found or does not exist.)

Approach - 1

var priKey = Buffer.from(config.private_key_sender.slice(2), 'hex');

    var myContract = new web3.eth.Contract(abi.data);
    var contractData = myContract.new.getData(
        'id12345',
        'John Shelby'
        {
            data: bytecode.data,
        });

    web3.eth.getTransactionCount(config.send_add, (err, txCount) => {
        if (txCount) {
            var txObject = {
                nonce: web3.utils.toHex(txCount),
                gasLimit: web3.utils.toHex('1000000'),
                gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')),
                data: contractData
            };
        } else if (err && err.message) {
            next(err.message, null);
        }

        // sign the transaction 
        const tx = new Tx(txObject);
        tx.sign(priKey);

        // serialize the transaction 
        const serializeTransaction = tx.serialize();
        const raw = '0x' + serializeTransaction.toString('hex')

        web3.eth.sendSignedTransaction(raw, (err, txHash) => {
            if (txHash) {
                console.log("transaction hash : ", txHash)
                next(null, txHash);
            }
            else if (err && err.message) {
                next(err.message, null);
            }
            else {
                next('Unable to sendRawTransaction', null);
            }
        });
    })

Approach - 2

exports.deployContract = async (next) => {
    var priKey = Buffer.from(config.private_key_sender.slice(2), 'hex');
    const sourceCode = fs.readFileSync('/home/puneet/puneet/projects/EstateBlocks/estateBlocks/contract/17april_1.sol', 'utf8').toString();
    const compiledCode = compiler.compile(sourceCode, 1).contracts[':EstateBlock']
    const interface = JSON.parse(compiledCode.interface);
    const bytecode = compiledCode.bytecode;
    function deploy_contract(){
        const myContract = new web3.eth.Contract(interface);
        myContract.deploy({data:bytecode,arguments:['id12345' , 'John Shelby']}).send({
            from: config.send_add,
            gas: web3.utils.toHex('1000000'),
            gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei'))
        },(err,res) => {
            if(err){
                console.log(err);
            }
            if(res){
                console.log(res);
            }
        })

    }
    deploy_contract()
}
1
  • For approach #1, why don't you start by changing myContract.new.getData to something which conforms to the syntax? A web3.eth.Contract instance does not have a field new AFAIK. Apr 22 '20 at 10:45
2

For approach #2, sending a transaction without signing it first is supported only if you unlock your account on the node that you're communicating with beforehand (for example, when you run your tests on Ganache).

On public nodes, this is obviously not feasible (neither would you want it to be, of course).

You'll need to sign the transaction first, and then send the signed-transaction instead.

For example (tested with web3.js v1.2.1):

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

const NODE_ADDRESS  = "YourNodeAddress";
const PRIVATE_KEY   = "0xYourPrivateKey";
const ARTIFACTS_DIR = "PathToYourAbiAndBinFolder";
const CONTRACT_NAME = "EstateBlock";
const CONTRACT_ARGS = ["id12345", "John Shelby"];

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 deploy() {
    const web3        = new Web3(NODE_ADDRESS);
    const account     = web3.eth.accounts.privateKeyToAccount(PRIVATE_KEY);
    const path        = 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 address:", receipt.contractAddress);
    console.log("encoded arguments:", transaction.encodeABI().slice(options.data.length));
    if (web3.currentProvider.constructor.name == "WebsocketProvider")
        web3.currentProvider.connection.close();
}

deploy();
5
  • For Approach 2 - I signed the transaction , but still getting same error : Returned error: The method eth_sendTransaction does not exist/is not available. Apr 22 '20 at 10:58
  • Hi ! In your solution , i am not able to understand what is ARTIFACTS_DIR , i have .sol file only. I have stored abi array in json file and contract data in js file. Apr 22 '20 at 11:14
  • @PuneetKumar: See at the bottom of my suggestion to variables const abi and const bin? Just set the abi variable to the value of the abi in your json file, and the bin variable to the value of the bytecode in your json file excluding the 0x. Apr 22 '20 at 11:44
  • Thanks a lot. This worked for me. Able to deploy contract and also checked the deployed data. Apr 23 '20 at 5:04
  • @PuneetKumar: You're welcome. Apr 23 '20 at 5:05

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.