Search code examples
ethereummetamask

How to send some custom tokens with MetaMask API?


It seems the example code on the MetaMask documentation page, sends ETH only. How should I customize the sample code to send some custom tokens?

const transactionParameters = {
  nonce: '0x00', // ignored by MetaMask
  gasPrice: '0x09184e72a000', // customizable by user during MetaMask confirmation.
  gas: '0x2710', // customizable by user during MetaMask confirmation.
  to: '0x0000000000000000000000000000000000000000', // Required except during contract publications.
  from: ethereum.selectedAddress, // must match user's active address.
  value: '0x00', // Only required to send ether to the recipient from the initiating external account.
  data:
    '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', // Optional, but used for defining smart contract creation and interaction.
  chainId: '0x3', // Used to prevent transaction reuse across blockchains. Auto-filled by MetaMask.
};

// txHash is a hex string
// As with any RPC call, it may throw an error
const txHash = await ethereum.request({
  method: 'eth_sendTransaction',
  params: [transactionParameters],
});

Solution

  • A transaction sending an ERC-20 token needs to have the token contract as the recipient (the to field), and the data field containing encoded instructions to execute its transfer() function along with address of the token receiver and amount.

    const transactionParameters = {
        from: accounts[0],
        to: tokenContractAddress,
        data: getDataFieldValue(tokenRecipientAddress, tokenAmount),
    };
    await ethereum.request({
        method: 'eth_sendTransaction',
        params: [transactionParameters],
    });
    

    You can use for example the web3js library (docs) to encode the data field value. The transfer() function is standardized - so assuming the token contract follows the standard, it's going to be the same for any token contract.

    function getDataFieldValue(tokenRecipientAddress, tokenAmount) {
        const web3 = new Web3();
        const TRANSFER_FUNCTION_ABI = {"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"};
        return web3.eth.abi.encodeFunctionCall(TRANSFER_FUNCTION_ABI, [
            tokenRecipientAddress,
            tokenAmount
        ]);
    }