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

如何检测ERC20代币转入合约并兑换游戏能量?

实现ERC20代币自动兑换能量的合约方案

首先明确:ERC20代币的转账不会像ETH那样触发合约的receive()或fallback()函数,因为ERC20转账是调用代币合约的transfer/transferFrom方法,而非直接向合约地址转原生代币。你的示例代码存在两个核心问题:一是sentToken变量未定义,二是没有实际处理代币的转账逻辑,会导致合约未收到代币就给用户增加能量,存在严重漏洞。

下面是最通用的ERC20实现方案:

完整合约代码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// 导入ERC20标准接口
interface IERC20 {
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
}

contract GameEnergySystem {
    // 自研X代币的合约地址
    address public immutable X_TOKEN_ADDRESS;
    // 兑换比例:1000 X = 1 能量
    uint256 public constant EXCHANGE_RATIO = 1000;

    // 记录每个用户累计转入的X代币数量
    mapping(address => uint256) public xTokenInfo;
    // 记录每个用户的能量余额
    mapping(address => uint256) public energyBalance;

    // 构造函数初始化X代币地址
    constructor(address _xTokenAddress) {
        X_TOKEN_ADDRESS = _xTokenAddress;
    }

    /**
     * 用户调用此函数兑换能量
     * 前提:用户已调用X代币合约的approve方法,授权本合约转走指定数量的X代币
     */
    function exchangeEnergy(uint256 _xAmount) external {
        // 检查转入的代币数量是否符合兑换门槛(至少1000枚)
        require(_xAmount >= EXCHANGE_RATIO, "X amount too low for energy");

        // 从用户地址转X代币到合约
        bool success = IERC20(X_TOKEN_ADDRESS).transferFrom(msg.sender, address(this), _xAmount);
        require(success, "Token transfer failed");

        // 更新用户累计转入的X代币数量
        xTokenInfo[msg.sender] += _xAmount;

        // 计算可兑换的能量并更新余额(整数除法,余数忽略,若要保留余数可额外记录)
        uint256 addedEnergy = _xAmount / EXCHANGE_RATIO;
        energyBalance[msg.sender] += addedEnergy;
    }

    // 可选:查询用户当前可兑换的能量(基于已授权但未兑换的X代币)
    function getAvailableEnergy(address _user) external view returns (uint256) {
        uint256 allowedAmount = IERC20(X_TOKEN_ADDRESS).allowance(_user, address(this));
        return allowedAmount / EXCHANGE_RATIO;
    }
}

关键逻辑说明

  • ERC20授权机制:用户必须先调用X代币合约的approve(address spender, uint256 amount),授权本合约可以转走指定数量的X代币,否则transferFrom会失败。
  • 代币转账验证:通过transferFrom完成代币的实际转移,并检查返回值确保转账成功,避免出现用户未转币却获得能量的漏洞。
  • 数据记录与能量计算:累计用户转入的X代币数量到xTokenInfo,按比例计算能量并累加(原代码用=会覆盖原有余额,正确写法是+=)。
  • 兑换门槛控制:通过require确保用户转入的X代币至少满足1点能量的兑换要求,避免无效操作。

替代方案(ERC777钩子)

如果你的X代币采用ERC777标准,可以利用tokensReceived钩子实现类似"自动到账兑换"的效果,无需用户主动调用兑换函数:

// 仅展示核心钩子函数,需结合ERC777接口实现
function tokensReceived(
    address operator,
    address from,
    address to,
    uint256 amount,
    bytes calldata userData,
    bytes calldata operatorData
) external {
    require(msg.sender == X_TOKEN_ADDRESS, "Only X token allowed");
    xTokenInfo[from] += amount;
    energyBalance[from] += amount / EXCHANGE_RATIO;
}

这种方案只要用户向合约转ERC777代币,就会自动触发兑换逻辑,但前提是X代币必须实现ERC777标准。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 04:30:30