已授权但Allowance仍为0,transferFrom提示余额不足问题
问题根源
你代码里的核心bug是approveUser函数误用了delegatecall调用USDC的approve方法。delegatecall的特性是让目标合约的代码在当前合约的上下文执行,也就是说,调用approve时的msg.sender是你的基金合约地址,而非调用approveUser的用户地址。这等于让合约自己给自己授权,根本没给用户地址设置有效allowance,所以transferFrom时始终显示授权不足。
修复步骤
1. 替换approveUser里的delegatecall
把delegatecall改成普通call或直接用接口调用,确保approve的上下文是用户地址:
方案一(推荐,类型更安全):用接口调用
function approveUser(uint256 amount) public returns(bool){ bool success = IProperSubsetUSDC(usdcAddress).approve(address(this), amount); if(success){ contractIsApproved[msg.sender] = true; } return success; }
方案二:用普通call
function approveUser(uint256 amount) public returns(bool){ (bool success,) = usdcAddress.call(abi.encodeWithSignature('approve(address,uint256)', address(this), amount)); if(success){ contractIsApproved[msg.sender] = true; } return success; }
2. 测试时新增授权验证步骤
在测试用例里,approve之后直接查询用户对合约的allowance,确认授权成功再执行deposit:
it("Verify allowance after approval", async function() { await deployFunds.connect(signers[1]).approveUser(1000); const allowance = await deployUSDC.allowance(signers[1].address, deployFunds.address); expect(allowance).to.equal(1000); }) it("Try depositing and the price of the pool tokens should be equal to one since it is new", async function() { const tx = await deployFunds.connect(signers[1]).deposit(1000, 2); const receipt = await tx.wait(); filter = receipt.events?.filter((x) => {return x.event == "Deposit"}); poolId = filter.length > 0 ? filter[0].args[1] : '0x000'; tokensForUser = filter.length > 0 ? filter[0].args[2]: "0"; mintedTokens = await deployERC20.balanceOf(user1); expect(filter.length).above(0); expect(poolId).to.equal(2); expect(tokensForUser).to.equal(1000); })
3. 优化deposit函数的transferFrom检查
transferFrom调用后要判断返回值,失败时直接revert,避免后续逻辑无效执行:
bool transferSuccess = IProperSubsetUSDC(usdcAddress).transferFrom(msg.sender, address(this), depositAmount); if(!transferSuccess) revert TransferFailed();
内容的提问来源于stack exchange,提问作者Samijoe Hayek
相关产品推荐
相关产品推荐

