1

I am trying to call a smart contract but i am getting error : The function eth_sendTransaction does not exist. I think it is because of transaction not signed , but how can i sign the transaction when i am calling .send() method. Please tell me what am i doing wrong here?

My smart contract function does not accept any argument but when executed it changes a bool value so i am assuming it is changing the state of contract. So can anyone please guide me how to call functions to alter contract data and also transaction to get data.

    const sourceCode = fs.readFileSync('contract_path', 'utf8').toString();
    const compiledCode = compiler.compile(sourceCode, 1).contracts[':Contract_Name']
    const abi = JSON.parse(compiledCode.interface);
    const bin = compiledCode.bytecode;
    var contractInstance = new web3.eth.Contract(abi, data.contractAddr);
    // build the transaction 
    web3.eth.getTransactionCount(data.signerPubKey, (err, txCount) => {
        if (txCount) {            
            // using the callback
            contractInstance.methods.signAgreement().send({ nonce: web3.utils.toHex(txCount), from: 'my_public_key', gasLimit: web3.utils.toHex('2100000'), gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')) }, function (error, transactionHash) {
                if (error) {
                    next(error, null)
                } else if (transactionHash){
                    next(null, transactionHash)
                }
            });
        } else if (err && err.message) {
            next(err.message, null);
        }
    })

1 Answer 1

1

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 Web3 = require("web3");

const NODE_ADDRESS = "YourNodeAddress";
const PRIVATE_KEY  = "0xYourPrivateKey";

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 = {
                to      : transaction._parent._address,
                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 contract    = new web3.eth.Contract(abi, data.contractAddr);
    const transaction = contract.methods.signAgreement();
    const receipt     = await send(web3, account, transaction);
    console.log(JSON.stringify(receipt, null, 4));
    if (web3.currentProvider.constructor.name == "WebsocketProvider")
        web3.currentProvider.connection.close();
}

run();
7
  • The transaction is getting failed. Also i noticed , it is deploying new contract but i want to call a function of existing contract. "receipt": { "blockHash": "0x31353e05586e9be19269039c542dacc473be72ec1a564561b46a8d546a644030", "blockNumber": 6366383, "contractAddress": "0xFFeA318315C49E26223BEc7721D24bEd56226462", "status": false, .... } why new contract address is appearing ? Apr 23, 2020 at 14:14
  • @PuneetKumar: My code does not deploy any new contract! Please find the issue by looking into how you've used this code. It expects the parameters abi and data.contractAddr which I have taken from your code, in order to create a logical contract object (i.e., not in order to deploy a new contract instance to the blockchain). If either one of these two parameters is wrong (in particularly, the address one), then the transaction will obviously become prone to failure. Apr 23, 2020 at 14:21
  • Thanks , i know problem is in my function. Actually function is working perfectly in JVM environment on remix , but when i switched to WEB3 provider it is giving me following error - Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? gas required exceeds allowance (10000000) or always failing transaction . I am looking what is the issue . Apr 23, 2020 at 15:16
  • @PuneetKumar: If estimateGas gives you that then it's because your transaction reverts under the given input parameters, the given state of your contract, and the given state of any other contract that your contract function interacts with. So estimateGas essentially tells you that there is no point in executing this transaction to begin with. Check your function for what and where it could revert (for example, if it has any require statement which is not satisfied). Apr 23, 2020 at 16:20
  • i am unable to identify the issue, function is : struct Person { string name; ` address account; ` bool signature; ` } // buyer and seller are struct Person ` modifier onlyBuyerSeller() {` ` require(msg.sender == buyer.account || msg.sender == seller.account);` ` _;` ` }` ` function signAgreement(address _addr) public onlyBuyerSeller {` ` if (_addr == buyer.account) {` ` buyer.signature = true;` ` } else if (_addr == seller.account) {` ` seller.signature = true;` ` }` ` }` Apr 23, 2020 at 16:44

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.