如何查询智能合约调用过程中发送的ERC20代币数量
现有代码问题先说明
你当前的代码里第三行require(msg.value == _price*amount)是校验原生代币(如ETH)转账金额的规则,如果你完全使用ERC20作为支付介质,这行校验是冗余的,还会导致用户调用时额外转原生代币才能成功,同时payable修饰符也可以直接删掉。
获取实际发送ERC20数量的实现方法
分链上合约内获取、链下查询两类场景:
链上合约内获取
- 方法一:通过转账前后余额差计算实际到账金额
如果使用的ERC20存在转账手续费、扣税等特殊逻辑,转账金额和实际到账金额可能不一致,可以通过余额差值得到准确的实际到账数:
// 把硬编码的ERC20地址提为状态变量更易维护 address public constant PAYMENT_TOKEN = 0x0789fF5bA37f72ABC4D561D00648ac0000970000; function mint(uint amount) public { // 原有其他校验逻辑保留 require(amount <= 10, "token: max of 10 token per mint"); require(_openMint == true, "token: minting is closed"); require(_tokenIdTracker.current() + amount <= _max, "token: not enough token left to be mint amount"); // 转账前查询owner的ERC20余额 uint256 ownerBalanceBefore = IERC20(PAYMENT_TOKEN).balanceOf(owner()); IERC20(PAYMENT_TOKEN).safeTransferFrom(msg.sender, owner(), amount); // 转账后再查余额,差值就是实际到账的ERC20数量 uint256 actualReceived = IERC20(PAYMENT_TOKEN).balanceOf(owner()) - ownerBalanceBefore; // 原有NFT铸造逻辑保留 for(uint i = 0; i < amount; i++) { _mint(msg.sender, _tokenIdTracker.current()); _tokenIdTracker.increment(); } }
- 方法二:新增事件记录转账金额
如果你只需要记录金额供链下查询,可以直接定义事件在转账后触发即可:
event ERC20MintPayment(address indexed payer, address indexed receiver, uint256 paymentAmount, uint256 mintCount); function mint(uint amount) public { // 原有校验、转账、铸造逻辑保留 IERC20(PAYMENT_TOKEN).safeTransferFrom(msg.sender, owner(), amount); // 触发事件记录转账金额 emit ERC20MintPayment(msg.sender, owner(), amount, amount); // 铸造逻辑... }
链下查询已发生交易的ERC20转账金额
- 如果你已经部署了合约没有新增事件,可以直接查询对应ERC20代币的
Transfer事件,过滤条件为from是mint调用者地址、to是合约owner地址,事件中的value字段就是实际转账的ERC20数量。 - 如果没有特殊ERC20扣税逻辑,也可以直接解码mint交易的input参数,拿到调用时传入的
amount参数值,就是对应支付的ERC20数量。 - 如果你已经新增了自定义的支付事件,直接过滤解析你自定义的事件即可拿到对应金额,比查通用ERC20事件更精准。
内容的提问来源于stack exchange,提问作者Pol
相关产品推荐
相关产品推荐

