如何使用 MetaMask API 发送一些自定义令牌?

How to send some custom tokens with MetaMask API?

MetaMask 文档页面上的示例代码似乎只发送 ETH。我应该如何自定义示例代码以发送一些自定义令牌?

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],
});

发送 ERC-20 代币的交易需要将代币合约作为接收者(to 字段),并且 data 字段包含执行其 transfer() 函数以及令牌接收者的地址和数量。

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

您可以使用例如 web3js 库 (docs) 对 data 字段值进行编码。 transfer() 函数是标准化的——所以假设代币合约遵循标准,它对任何代币合约都是一样的。

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
    ]);
}

对于使用 encodeABI 函数的 Petr 解决方案的更简洁版本。

await window.ethereum
    .request({
      method: "eth_sendTransaction",
      params: [
        {
          from: accounts[0],
          to: TOKEN_CONTRACT_ADDRESS,
          data: tokenContract.methods
            .transfer(receiverAddress, amount)
            .encodeABI(),
        },
      ],
    })
    .then((result) =>  console.log(result))
    .catch((error) => console.error(error));