You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Web3.js和私钥发送ERC-20代币时EVM回滚错误排查

问题分析与修复方案

你的代码存在多个核心错误,导致EVM回滚交易,以下是具体问题和修正方案:


核心错误点

  • 交易目标地址错误:ERC20代币转账需要调用代币合约的transfer方法,而非直接给接收方地址转ETH,因此to字段应填ERC20代币合约地址,不是接收人地址。
  • Data字段完全误用:你直接将ABI数组赋值给data,但data需要是编码后的合约方法调用数据,且当前ABI缺少transfer方法定义,无法编码转账逻辑。
  • Value字段错误:value字段用于转ETH,ERC20代币转账不需要转ETH,必须设为0,你当前填入的代币金额会导致尝试转ETH,大概率因余额不足或逻辑错误被回滚。
  • 缺失transfer方法ABI:你的最小ABI仅包含balanceOf,必须添加ERC20标准的transfer方法ABI才能编码转账调用。

修正后的代码

1. 更新最小ABI(添加transfer方法)

// 包含balanceOf和transfer的ERC20最小ABI
const minABI = [
    {
        "constant": true,
        "inputs": [{"name": "_owner", "type": "address"}],
        "name": "balanceOf",
        "outputs": [{"name": "balance", "type": "uint256"}],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            {"name": "_to", "type": "address"},
            {"name": "_value", "type": "uint256"}
        ],
        "name": "transfer",
        "outputs": [{"name": "", "type": "bool"}],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    }
];

2. 修正sendToken函数

async function sendToken(tokenHolder, walletSecret, tokenContractAddress, toAddress, amount, tokenDecimals = 18) { 
    const nonce = await web3.eth.getTransactionCount(tokenHolder);
    const gasPrice = await web3.eth.getGasPrice();
    const gasLimit = 200000;

    // 编码transfer方法的调用数据
    const contract = new web3.eth.Contract(minABI, tokenContractAddress);
    // 处理代币小数位数:如果是18位直接用toWei,其他位数需对应调整
    const transferAmount = tokenDecimals === 18 
        ? web3.utils.toWei(amount, 'ether')
        : web3.utils.toBN(amount * Math.pow(10, tokenDecimals)).toString();
    const data = contract.methods.transfer(toAddress, transferAmount).encodeABI();

    const params = {
        from: tokenHolder,
        to: tokenContractAddress, // 目标地址改为代币合约地址
        nonce: web3.utils.toHex(nonce),
        data: data, // 填入编码后的转账调用数据
        value: web3.utils.toHex(0), // ERC20转账无需转ETH,设为0
        gasPrice: web3.utils.toHex(gasPrice),
        gasLimit: web3.utils.toHex(gasLimit),
    };

    const signedTx = await web3.eth.accounts.signTransaction(params, walletSecret);

    try { 
        web3.eth.sendSignedTransaction(signedTx.rawTransaction)
        .on('transactionHash', (hash) => console.log("txHash", hash))
        .on('receipt', (receipt) => console.log("receipt", receipt))
        .on('confirmation', (confirmationNumber, receipt) => console.log("confirmationNumber", confirmationNumber, "receipt", receipt))
        .on('error', console.error); 
    } catch(error) {
        console.log(error);
    } 
}

3. 修正调用方式(新增代币合约地址参数)

sendToken(
    "0x0000_SENDER_PUBLIC_KEY", 
    "0x0000_SENDER_SECRET_KEY", 
    "0x0000_TOKEN_CONTRACT_ADDRESS", // 必填:ERC20代币合约地址
    "0x0000_RECIPIENT_PUBLIC_KEY", 
    "0.005",
    18 // 可选:代币小数位数,默认18(如USDT需改为6)
);

额外注意事项

  • 确认发送方的ERC20代币余额足够覆盖转账金额
  • 若代币合约有特殊逻辑(如转账手续费),需调整gasLimit或预留足够余额
  • 代币小数位数必须与实际合约一致,否则金额计算错误

内容的提问来源于stack exchange,提问作者Antonio Da Silva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 22:08:11