32

This may be a very basic question, I don't know why but I am unable to find correct solution to how can I call my contract's method using sendTransaction. I have a transfer(address, uint256) function which I want to call using sendTransaction and callTransaction. I have my contract compiled and I have it's abi and address. Now, how can I call different metrhods of the contract using sendTransaction?
I was reading the question Syntax for calling contract state changing methods, and I got explanations for function having single parameter but what if it has more than a parameter of different types, like here transfer() function accepts 2 parameters.

Prashant Prabhakar Singh
  • 8,026
  • 5
  • 40
  • 79

5 Answers5

43

Posting solution to my own question for anyone who needs it. To call a contract function from geth:

const contractAbi = eth.contract(AbiOfContract);
const myContract = contractAbi.at(contractAddress);
// suppose you want to call a function named myFunction of myContract
const getData = myContract.myFunction.getData(function_parameters);
// finally pass this data parameter to send Transaction
web3.eth.sendTransaction({ to:Contractaddress, from:Accountaddress, data: getData });

Note: You can add other fields in sendTransaction like value etcetera, I have skipped that for simplicity to new use users.


To all the users who face challanges with signing data using private key. The pseudo code for signing and sending a transaction to contract using private key:

const Tx = require('ethereumjs-tx')
const web3 = new Web3()
web3.setProvider(new web3.providers.HttpProvider(web3RpcAddr))
const yourContract = new web3.eth.Contract(yourContract.abi, yourContract.address)

function sendCoin(toAddress, amount) { const nonce = await web3.eth.getTransactionCount(fromAddress, 'pending') const extraData = await yourContract.methods.transfer(toAddress, amount) const data = extraData.encodeABI() const txObj = { from: adminAddress, to: yourContractAddress, data, value: '0', gas: gasSent, // calculation of gas and gas Price is skipped here gasPrice: gasPriceSent, privKey: adminPvtKey, nonce }

let signedTx = await signTx(txObj) signedTx = "0x" + signedTx.serialize().toString('hex') await submitSignedTx(signedTx) }

async function signTx(payload) { let { from, to, data, value, gas, gasPrice, privKey, nonce } = payload let txParams = { to, data, value: web3.utils.toHex(value), gasPrice: web3.utils.toHex(gasPrice), gas: web3.utils.toHex(gas), nonce: web3.utils.toHex(nonce) } const tx = new Tx(txParams) privKey = await _validatePrivKey(privKey) privKey = new Buffer(privKey, 'hex') tx.sign(privKey) privKey = null return tx }

async function submitSignedTx(serializedTx) { return new Promise((fullfill, reject) => { web3.eth.sendSignedTransaction(serializedTx) .on('transactionHash', txHash => { l.info('transaction sent. hash =>', txHash) return fullfill({success: true, txHash : txHash}) }) .on('error', e => { // console.log('unable to send tx', e) l.error(logmsg, e.message) return fullfill({success: false, message: e}) }) }) }

YakovL
  • 123
  • 7
Prashant Prabhakar Singh
  • 8,026
  • 5
  • 40
  • 79
  • 1
    this is an excellent answer! worked for me- remember to put the addresses in quotes. – smatthewenglish Jul 31 '17 at 21:29
  • it is not clear what is getData() method doing. is it a builtin method or has to be created by the developer who wrote the contract? – Nulik Oct 16 '17 at 15:24
  • You need not implement getData method.It is used to retrieve the value of data in state storage. You can read more here: http://solidity.readthedocs.io/en/develop/contracts.html#visibility-and-getters – Prashant Prabhakar Singh Oct 17 '17 at 04:09
  • Do you need to specify the IP of the Ethereum node that you're sending this transaction to? – RagHaven Jan 20 '18 at 04:27
  • Yes, you need to specify that. That is while making the connection to web3. Keep in mind not to expose personal over RPC – Prashant Prabhakar Singh Jan 20 '18 at 06:43
  • @PrashantPrabhakarSingh getData() is the function that generates input variable that is being sent to evm.Call(). getData() does not access the storage at State, it uses the ABI of the contract to generate the input, particulary, using abi.Pack() located in accounts/abi/abi.go . But in transaction scope , this input is called data – Nulik Jun 26 '18 at 14:48
  • Can you post a similar solution but using Infura and returning the contract function output, please? – kitsune Feb 16 '19 at 04:51
  • @kitsune Added details for using the same solution with Infura. The output depends on the type of event you choose to be triggered like transacationHash, confirmation, receipt, error etc. See example here – Prashant Prabhakar Singh Feb 17 '19 at 05:03
  • @PrashantPrabhakarSingh thanks for your explanation, I have not clear with the data comes from, is it from the extraData? – Sigit Apr 30 '21 at 17:06
  • yes. Let me update the answer as well :) – Prashant Prabhakar Singh Apr 30 '21 at 17:34
  • let contract = new web3.eth.Contract(require(./contracts/abi.json), contractAddress);

    let adventurersLogParameters = [2236813];

    let getData = contract.methods.adventurers_log.getData(funtion adventurersLogParameters);

    It's showing syntax error at "adventurersLogParameters".

    – emeraldhieu Sep 19 '21 at 17:35
  • @emeraldhieu You don't need to write the "function" keyword before passing args. let data = contract.methods.adventurers_log.getData(adventurersLogParameters) should work. – Prashant Prabhakar Singh Sep 20 '21 at 12:52
  • Could you update your answer for web3 1.x? It has many breaking changes. Like emeraldhieu mentioned, a contract is accessed via const contract = new web3.eth.Contract(abi, contractAddress); there's no getData, but we can do const call = universeContract.methods[methodName](callParameters), but I'm not sure how to sign the call and send it correctly. – YakovL May 11 '22 at 15:55
7

Have you tried:

// In Javascript
myContract.transfer(otherAddress, aNumber, { from: myAccount });
// Or
myContract.transfer.sendTransaction(otherAddress, aNumber, { from: myAccount });
// Or
myContract.transfer.call(otherAddress, aNumber, { from: myAccount });

See the whole documentation.

2

Improving @Prashant Prabhakar Singh answer:

var contractAbi = eth.contract(AbiOfContract);
var myContract = contractAbi.at(contractAddress);
// suppose you want to call a function named myFunction of myContract
var getData = myContract.myFunction.getData("1","boy");//just parameters you pass to myFunction
// And that is where all the magic happens
web3.eth.sendTransaction({
    to:ContractAddress,//contracts address
    from:web3.eth.accounts[0],
    data: getData,
    value: web3.toWei(EtherAmount, 'ether')//EtherAmount=>how much ether you want to move
},function (error, result){ 
            if(!error){
                console.log(result);//transaction successful
            } else{
                console.log(error);//transaction failed
            }
    });
1
var abi=[//your abi array];
var contractAddress = "//your contract address";
var contract = web3.eth.contract(abi).at(contractAddress);

contract.functionName.sendTransaction(parameter_1,parameter_2,parameter_n,{
            from:web3.eth.accounts[0],
            gas:4000000},function (error, result){ //get callback from function which is your transaction key
                if(!error){
                    console.log(result);
                } else{
                    console.log(error);
                }
        });

you can then try to get transaction receipt by using

var receipt=web3.eth.getTransactionReceipt(trHash);

-if you get receipt as null that means your transaction is not mined, you can keep trying after some time until you get receipt values. -You can check in the receipt that all the provided gas is used or not, all gas used indicated your transaction is failed

SwapnilKumbhar
  • 763
  • 1
  • 11
  • 31
0

With Etherjs utilities data can be created as follows which can be directly sent to sendTransaction function.

//ethereum provider instance creation
let ethereum = window.ethereum;
// Request account access if needed
await ethereum.enable();
let provider = new ethers.providers.Web3Provider(ethereum);

//Get method id (transfer function method id) const METHOD_ID = "0x05555555"; //replace with actual transfer function method id

//creating encoded data let encodedData = ethers.utils.hexConcat([ METHOD_ID, ethers.utils.defaultAbiCoder.encode( ["address", "uint256"], [receiverAddress, amount] //replace with receiver and amount to be transferred ), ]);

//Create raw transaction param const param = { from: sender, //replace with sender wallet address to: ERC20_CONTRACT_ADDRESS, //replace with your contract address data: encodedData };

//Send Transaction using etherjs const transactionHash = await provider.send('eth_sendTransaction', params)

Vineeta
  • 45
  • 6