Solidity质押合约ERC20转账余额不足异常求助
问题分析与解决方案
核心错误原因
你在质押合约的stake函数里调用ercToken.transfer(address(ercToken), _amount)时犯了关键逻辑错误:
- ERC20标准的
transfer函数,是从调用该函数的地址(也就是你的质押合约地址)转出代币到目标地址,而非用户地址。 - 你之前检查的是用户余额
ercToken.balanceOf(msg.sender),但实际转账时系统会校验质押合约的余额——而质押合约并没有用户的代币,因此触发"ERC20: transfer amount exceeds balance"错误。
另外,原代码里的require(_amount < ercToken.balanceOf(msg.sender))用了<,应该改为<=,否则用户刚好持有等于_amount的代币时也会触发错误。
正确实现步骤
用户质押代币必须遵循用户授权→合约划转的流程:
1. 前端补充授权操作
用户需要先授权质押合约操作自己的代币,再执行质押:
async function approveAndStake() { const stakeAmount = 1; // 先授权质押合约划转指定数量的代币 await ercTokenContract.approve(stakeContract.address, stakeAmount); // 再执行质押 await stakeContract.stake(stakeAmount); }
2. 修改质押合约的stake函数
使用ERC20的transferFrom函数,从用户地址直接划转代币到目标地址(这里以质押合约自身为例,可根据业务需求调整目标地址):
function stake(uint256 _amount) public { require(_amount > 0, "You must stake more than 0"); uint256 userBalance = ercToken.balanceOf(msg.sender); require(userBalance >= _amount, "The amount exceeds your balance"); // 检查用户给质押合约的授权额度是否足够 uint256 allowance = ercToken.allowance(msg.sender, address(this)); require(allowance >= _amount, "Allowance not enough"); // 记录质押信息 addressToStaked[msg.sender].push(Stakes(block.timestamp, _amount)); totalStakes[msg.sender] += 1; // 从用户地址划转代币至目标地址 bool transferSuccess = ercToken.transferFrom(msg.sender, address(this), _amount); require(transferSuccess, "Stake transfer failed"); }
补充说明
transferFrom的逻辑是:从from地址(用户地址)转出代币到to地址,前提是from已授权调用该函数的地址(质押合约)足够额度。- 你可以根据业务需求,将
transferFrom的目标地址改为专门的质押池地址,而非质押合约自身。
内容的提问来源于stack exchange,提问作者user18541404
相关产品推荐
相关产品推荐

