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

合约调用ERC20 transfer/transferFrom触发revert错误求助

ERC20转账触发revert错误排查与修复

问题现象

每次调用合约的bet函数尝试转账ERC20代币时,都会触发如下revert错误:
Note: The called function should be payable if you send value and the value you send should be less than your current balance.

合约代码

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

interface IERC20 {
    function totalSupply() external view returns (uint);

    function balanceOf(address account) external view returns (uint);

    function transfer(address recipient, uint amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint amount) external returns (bool);

    function transferFrom(
        address sender,
        address recipient,
        uint amount
    ) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}

contract Hilo {
    uint public fee;
    uint256 public maxBet;
    uint256 public minBet;
    address public owner;
    IERC20 public immutable token;


    constructor(address _tradeToken, uint initialFee, uint256 initalMaxBet, uint256 initalMinBet) {
        fee = initialFee;
        maxBet = initalMaxBet;
        minBet = initalMinBet;
        owner = msg.sender;
        token = IERC20(_tradeToken);
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }

    function changeFee(uint newFee) public onlyOwner  {
        fee = newFee;
    }

    function changeMaxBet(uint newMaxBet) public onlyOwner  {
        maxBet = newMaxBet;
    }

    function changeMinBet(uint newMinBet) public onlyOwner {
        maxBet = newMinBet;
    }

    function bet(uint card, string memory choice, uint256 amount, uint256 multiplier) external returns (uint nextCard) {
        require(amount <= maxBet, "amount is greater than the maxBet");
        require(amount >= minBet, "amount is smaller than minBet");
        uint256 newAmount = amount * (fee / 1000);
        require(token.balanceOf(msg.sender) >= newAmount, "Token transfer failed.");
        token.transferFrom(msg.sender, address(this), newAmount);
        uint next = uint(keccak256(abi.encodePacked(block.timestamp, block.difficulty,  
        msg.sender))) % 13 + 1; 
        if (keccak256(abi.encodePacked(choice)) == keccak256(abi.encodePacked('L'))) {
            if (card > next) {
                token.transfer(msg.sender, amount * (multiplier / 100));
                return next;
            } 
        } else if (keccak256(abi.encodePacked(choice)) == keccak256(abi.encodePacked('H'))) {
            if (card < next) {
                token.transfer(msg.sender, amount * (multiplier / 100));
                return next;
            }
        }

        return next;
    }
}

环境说明

使用Remix虚拟机环境,ERC20代币已成功部署。移除合约中的transfer或transferFrom调用后代码可正常运行;直接调用ERC20合约的transferFrom方法(完成授权后)能正常工作,排除单纯的授权错误(授权错误有专属提示)。


问题根源

  1. 整数除法精度丢失:
    代码中uint256 newAmount = amount * (fee / 1000);的计算顺序错误,fee通常是小于1000的数值(比如5代表0.5%手续费),fee / 1000会因Solidity整数除法向下取整得到0,最终newAmount为0。部分ERC20合约会拒绝0金额转账,触发异常。
  2. 缺失授权额度检查:
    transferFrom执行的前提是用户已授权合约足够额度,当前代码仅检查用户余额,未验证allowance(msg.sender, address(this)) >= newAmount,若授权不足会导致转账失败。
  3. changeMinBet函数笔误:
    该函数内错误地修改了maxBet变量而非minBet,导致最小投注额配置失效,可能引发后续逻辑异常。

修复方案

  1. 修正手续费计算逻辑:
    调整计算顺序为先乘后除,避免精度丢失:
    uint256 newAmount = amount * fee / 1000;
    
  2. 添加授权检查:
    在transferFrom调用前增加授权验证:
    require(token.allowance(msg.sender, address(this)) >= newAmount, "Insufficient allowance");
    
  3. 修复changeMinBet函数:
    将函数内的maxBet = newMinBet;改为:
    minBet = newMinBet;
    
  4. 显式检查转账返回值:
    部分ERC20合约转账失败时返回false而非revert,建议显式检查返回值:
    require(token.transferFrom(msg.sender, address(this), newAmount), "TransferFrom failed");
    require(token.transfer(msg.sender, amount * multiplier / 100), "Transfer failed");
    

内容的提问来源于stack exchange,提问作者fwara07

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 03:16:15