Hardhat测试时ERC20合约deposit方法transferFrom调用失败如何解决
ERC20 transferFrom执行失败问题分析
核心错误成因
- 授权逻辑完全错误:
ERC20(token).approve(address(this), amount)这行代码是合约自身给自身授予了token的操作权限,而transferFrom要求的是token的实际持有者(也就是调用deposit的外部地址msg.sender)给当前合约授权转账额度,这步授权完全没有生效,所以transferFrom触发ERC20的额度校验失败报错。 - 测试逻辑缺失授权步骤:Hardhat测试代码里只给arb合约转了WETH,没有让owner账号给arb合约授权对应数量的WETH转账额度,也没有调整合约里的错误授权逻辑,直接调用deposit必然失败。
- 额外的逻辑瑕疵:require判断里用的是
balance > amount,如果用户余额刚好等于要存的数量也会报错,建议改成balance >= amount更符合常规业务逻辑。
补充说明:ERC20的transferFrom机制设计就是为了让第三方代付转账,必须由资金持有方主动给第三方授予额度,任何第三方都无法主动给自己授予操作他人资产的权限,这是ERC20的安全基础设计。
修复方案
第一步:修改Solidity合约代码
去掉合约里无效的self-approve逻辑,调整后的deposit代码如下:
function deposit(address token, uint256 amount) external onlyOwner { uint256 balance = ERC20(token).balanceOf(msg.sender); console.log(token, balance); // 调整判断条件为大于等于,避免刚好相等时报错 require(balance >= amount, "not enough money to deposit"); ERC20(token).transferFrom(msg.sender, address(this), amount); }
第二步:调整Hardhat测试代码,提前执行授权操作
在调用arb.deposit之前,先让owner账号给arb合约授权对应额度的WETH,调整后的测试代码如下:
await WETH.transfer(arb.address, ethers.utils.parseUnits("2", "ether")); await IWETH.deposit({ value: ethers.utils.parseUnits("100.0", "ether"), }); // 新增授权步骤:owner给arb合约授权2个WETH的转账额度 await WETH.connect(owner).approve(arb.address, ethers.utils.parseUnits("2", "ether")); await arb .connect(owner) .deposit( "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", ethers.utils.parseUnits("2", "ether") );
内容的提问来源于stack exchange,提问作者Dadan
相关产品推荐
相关产品推荐

