已授权BUSD额度后,如何使BigContract的sendToken调用生效?
如何成功执行BigContract的sendToken函数完成BUSD转账?
问题背景
- AddressA已向
BigContract授权100 BUSD的转账额度 - 合约所有者调用
sendToken函数时消耗了0.65BNB Gas,但转账未生效 - 目标:将1 BUSD从AddressA转账至合约所有者地址
合约原代码
pragma solidity ^0.8; interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, address indexed spender, uint256 value ); } contract BigContract { address owner = 0xFAD69bCefb704c1803A9Bf8f04BC314E78838F88; //address public sender; function withdrawToken(address tokenContract, uint256 amount) external { // send `amount` of tokens // from the balance of this contract // to the `owner` address IERC20(tokenContract).transfer(owner, amount); } function sendToken(address tokenContract, address sender ,uint256 amount) external { IERC20(tokenContract).transferFrom( sender, owner, amount ); } }
问题原因分析
调用未生效的核心原因:
- 未处理ERC20转账返回值:BUSD等部分ERC20代币在转账失败时不会自动触发revert,仅返回
false。原合约直接调用transferFrom但不校验返回值,导致转账失败时合约仍执行完成,Gas被消耗但无实际效果。 - 无权限校验与参数风险:
sendToken允许任意地址调用,若调用时传入的sender参数不是AddressA,会因授权额度不足导致转账失败;同时缺乏权限控制也增加了误操作风险。
解决方案
1. 修改合约逻辑
更新sendToken函数,添加权限控制、返回值校验与预检查逻辑,避免无效Gas消耗:
pragma solidity ^0.8; interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, address indexed spender, uint256 value ); } contract BigContract { address public immutable owner = 0xFAD69bCefb704c1803A9Bf8f04BC314E78838F88; // 仅允许合约所有者调用的修饰器 modifier onlyOwner() { require(msg.sender == owner, "Caller is not owner"); _; } function withdrawToken(address tokenContract, uint256 amount) external onlyOwner { bool success = IERC20(tokenContract).transfer(owner, amount); require(success, "Withdraw transfer failed"); } function sendToken(address tokenContract, address sender, uint256 amount) external onlyOwner { // 预检查授权额度是否充足 uint256 availableAllowance = IERC20(tokenContract).allowance(sender, address(this)); require(availableAllowance >= amount, "Insufficient allowance"); // 执行转账并校验结果 bool success = IERC20(tokenContract).transferFrom(sender, owner, amount); require(success, "TransferFrom failed"); } }
2. 调用时的注意事项
- 确保调用
sendToken时传入的sender参数为AddressA(已完成授权的地址) - 确认AddressA的BUSD余额≥1 BUSD
- 确认AddressA给
BigContract的剩余授权额度≥1 BUSD(原授权100 BUSD未使用则满足) - 调用时设置合理的Gas上限(之前的0.65BNB Gas已足够,无需调整)
内容的提问来源于stack exchange,提问作者qiaokeli dbz
相关产品推荐
相关产品推荐

