如何通过MetaMask RPC API发送代币 解决tokenContract未定义问题
通过MetaMask RPC API发送USDC等ERC20代币实现方案
常见误区纠正
- MetaMask并未停止对web3.js、ethers.js等库的支持,只是不再默认向页面注入
web3全局变量,相关库需要自行安装依赖后,用MetaMask注入的window.ethereum对象初始化即可使用。 - 旧示例中未定义的
tokenContract是ERC20代币合约的实例对象,需要通过对应链上SDK初始化后才能调用方法生成交易参数。 - Ropsten测试网已正式停止运行,测试USDC建议使用Sepolia、Goerli测试网;你示例中填写的
to地址0x07865c6E87B9F70255377e024ace6630C1Eaa37F为Goerli测试网USDC合约地址,与Ropsten网络不匹配,是交易失败的常见诱因。 - ERC20代币转账的核心逻辑是调用合约的
transfer方法,交易的to字段必须填代币合约地址,接收方地址和转账金额都编码在data字段中,不要把接收方地址填在to字段里。
方案一:无第三方依赖原生实现(无版本兼容问题,最稳定)
不需要初始化合约实例,直接按照ERC20标准手动构造交易data字段即可:
// 可根据实际需求修改配置 const PARAMS = { tokenContract: "0x07865c6E87B9F70255377e024ace6630C1Eaa37F", // Goerli测试网USDC合约地址 receiver: "0x替换为实际接收方钱包地址", amount: 100, // 对应0.0001 USDC,USDC精度为6位,0.0001 * 10^6 = 100 } // 先请求连接钱包 await ethereum.request({ method: 'eth_requestAccounts' }); // transfer(address,uint256)方法的函数选择器为keccak256哈希前4字节,固定值0xa9059cbb const functionSelector = '0xa9059cbb'; // 接收方地址去掉0x前缀,左侧补0至64位 const paddedReceiver = PARAMS.receiver.toLowerCase().replace('0x', '').padStart(64, '0'); // 转账金额转十六进制,去掉0x前缀,左侧补0至64位 const paddedAmount = PARAMS.amount.toString(16).padStart(64, '0'); // 拼接为完整交易data const txData = functionSelector + paddedReceiver + paddedAmount; // 发起交易 const txHash = await ethereum.request({ method: "eth_sendTransaction", params: [ { from: ethereum.selectedAddress, to: PARAMS.tokenContract, data: txData, value: '0x0' // 转ERC20代币时value必须为0 } ] }); console.log('交易发起成功,交易哈希:', txHash);
方案二:使用ethers.js初始化合约实例(匹配旧示例的写法)
首先安装依赖:
npm install ethers@6
代码实现:
import { ethers } from 'ethers'; // 用MetaMask注入的provider初始化签名器 const provider = new ethers.BrowserProvider(window.ethereum); const signer = await provider.getSigner(); // ERC20标准最小ABI,仅保留transfer方法即可 const MIN_ERC20_ABI = [ "function transfer(address to, uint256 amount) returns (bool)" ]; // 初始化代币合约实例,即旧示例中缺失的tokenContract变量 const tokenContract = new ethers.Contract( "0x07865c6E87B9F70255377e024ace6630C1Eaa37F", // 对应代币合约地址 MIN_ERC20_ABI, signer ); // 发起转账,金额自动按USDC 6位精度换算为最小单位 const tx = await tokenContract.transfer( "0x替换为实际接收方钱包地址", ethers.parseUnits("0.0001", 6) ); console.log('交易发起成功,交易哈希:', tx.hash);
常见踩坑点
- 转账金额必须按对应代币的精度换算为最小单位整数,USDC精度为6位,不要直接传入小数,也不要误用以太坊原生币的18位精度换算。
- 发起交易前需确认MetaMask已切换到对应网络,网络与合约地址不匹配会直接报错。
- 旧教程中直接使用的全局
web3对象已被MetaMask移除,如需使用web3.js需自行安装依赖后,传入window.ethereum初始化,不存在MetaMask不支持web3.js的情况。 transfer方法的第一个参数必须是合法的0x开头42位十六进制钱包地址,不能传入自定义别名、"My Wallet"这类非地址字符串。
内容的提问来源于stack exchange,提问作者Zac Feng
相关产品推荐
相关产品推荐

