1

I succeeded creating transaction from node's account(created by ganache) to a contract using web3.js .

const contract = new web3.eth.Contract(abi, contractAddress, {
    from: from,
    gasPrice: 200000000
});
contract.methods.sendCoin(receiverAddress, '1').send() // succeeded

However, how to send transaction to a contract from address which is not node's account.

Does Contract Instance have any methods to sign transaction?? or, Contract Instance cannot be used to sign Transaction and need to use another way ??

1

You need to sign the transaction with the private key of the account, and then send it to the node.

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

async function send(web3, privateKey, gasPrice, contract, receiverAddress, numOfCoins) {
    const account = web3.eth.accounts.privateKeyToAccount(privateKey).address;
    const transaction = contract.methods.sendCoin(receiverAddress, numOfCoins);
    const options = {
        to      : transaction._parent._address,
        data    : transaction.encodeABI(),
        gas     : await transaction.estimateGas({from: account}),
        gasPrice: gasPrice
    };
    const signed  = await web3.eth.accounts.signTransaction(options, privateKey);
    const receipt = await web3.eth.sendSignedTransaction(signed.rawTransaction);
    return receipt;
}

You can generalize this function by passing transaction to it as input instead of initializing this variable internally:

async function send(web3, privateKey, gasPrice, transaction) {
    ...
}

async function main() {
    ...
    const transaction = contract.methods.sendCoin(receiverAddress, numOfCoins);
    const receipt = await send(web3, privateKey, gasPrice, transaction);
    ...
}

Thus you can call it with any other transaction.

6
  • Thank you! your code worked. Then, I want to ask one thing. What is transaction._parent._address and why is it neccesary ? I thought "to" is contract's address, but to is transaction._parent._address. why? – 久保圭司 Jan 21 '20 at 10:16
  • 1
    @engineerk: You're welcome. transaction._parent._address is indeed the contract address in all cases except for when the transaction is contract.deploy(...), in which case, the contract doesn't have an address yet. So you can indeed simply use contract._address or contract.options.address. – goodvibration Jan 21 '20 at 10:23
  • 1
    But please note the suggestion for a more generalized function which I added at the bottom of the answer, where instead of passing the contract and the parameters of the function that you want to execute, you pass the transaction itself. In this case, you don't have the contract address at hand, hence transaction._parent._address becomes useful. – goodvibration Jan 21 '20 at 10:23
  • 1
    @engineerk: You're welcome (spelled "Great" I believe). – goodvibration Jan 21 '20 at 10:27
  • 1
    @engineerk: BTW, I think that those guys at Web3 dev team did not intend for transaction._parent or transaction._parent._address to be used at all (hence the underscore prefixes in those variable names). So it is possible that these variables will not be available in future versions of this module. – goodvibration Jan 21 '20 at 10:29

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.