Hardhat测试中Ethers.js向Payable函数发1 Wei失败求助
问题:调用带payFee修饰器的Payable函数时发送1 Wei失败,触发回滚
我在Hardhat测试环境中,使用Ethers.js调用带有payFee修饰器的payable类型executeTrade函数,尝试发送1 Wei,但触发修饰器回滚,抛出“Didn't receive fee.”错误。
合约代码如下:
modifier payFee() { bool sent = payable(address(this)).send(msg.value); require(sent, "Didn't receive fee."); _; } function executeTrade( address _tokenA, address _tokenB, uint _tokensFromFlashLoan, bool _startOnUniswap ) external payable payFee { uint balanceBefore = IERC20(_tokenA).balanceOf(_tokenA); bytes memory data = abi.encode( _startOnUniswap, _tokenA, _tokenB, _tokensFromFlashLoan, balanceBefore ); flashloan(_tokenA, _tokensFromFlashLoan, data); }
尝试过两种调用方式:
方式一:
const options = { gasLimit: 3000000, value: ethers.utils.parseUnits("1.0", "wei"), }; trade = await contract.executeTrade( tokenA, tokenB, ethers.utils.parseEther("10.0"), false, options );
方式二:
const options = { gasLimit: 3000000, value: ethers.utils.parseUnits("1.0", "wei"), }; trade = await contract.executeTrade( tokenA, tokenB, ethers.utils.parseEther("10.0"), false, { ...options } );
问题根源
你的payFee修饰器逻辑存在根本错误:
- 调用
payable函数时,msg.value已经直接转入合约地址,不需要再执行payable(address(this)).send(msg.value)——这相当于让合约给自己转钱,完全多余。 send()函数仅提供2300 gas,若合约存在fallback或receive函数且消耗gas超过2300,哪怕是1 Wei的转账也会失败,进而触发require回滚。
解决方案
直接修改payFee修饰器,去掉无效的转账逻辑,仅验证费用合规性即可:
场景1:仅验证用户发送了至少1 Wei
modifier payFee() { require(msg.value >= 1, "Must send at least 1 Wei fee"); _; }
场景2:要求用户发送恰好1 Wei
modifier payFee() { require(msg.value == 1, "Fee must be exactly 1 Wei"); _; }
Ethers.js调用优化
你当前的两种调用方式均正确,发送1 Wei的写法没问题,可简化为更直观的写法:
const trade = await contract.executeTrade( tokenA, tokenB, ethers.utils.parseEther("10.0"), false, { gasLimit: 3000000, value: 1 // 直接写1,ethers会自动识别为Wei单位 } );
内容的提问来源于stack exchange,提问作者Shadq
相关产品推荐
相关产品推荐

