Remix中实现ERC721质押合约时调用transferFrom出现Gas估算错误
问题回顾
实现ERC721质押合约时,添加MarineBluesContract(_nftContract).transferFrom(msg.sender, address(this), _tokenId);后出现Gas Estimation Error,已完成以下排查仍未解决:
- 确认自身持有足够ETH
- 确认质押合约持有足够ETH
- 通过
setApprovalForAll授权质押合约转移NFT
完整stake函数代码:
function stake(uint256 _tokenId, address _nftContract) external nonReentrant { require(ntfContractList[_nftContract], "Not allowed NFT contract"); require(msg.sender != address(0), "Invalid staker address"); require(_tokenId != 0, "Invalid token id"); require(MarineBluesContract(_nftContract).ownerOf(_tokenId) == msg.sender, "Not token owner"); // Staking start time uint48 timestamp = uint48(block.timestamp); // Staking to contract MarineBluesContract(_nftContract).transferFrom(msg.sender, address(this), _tokenId); // Save staking information stakedTokens.push( StakedToken(msg.sender, _tokenId, _nftContract, timestamp, false) ); // Increase in staking count totalStaked++; emit Stake(msg.sender, _tokenId, _nftContract, timestamp); }
针对性排查方向
修正
ntfContractList拼写错误
代码中require(ntfContractList[_nftContract], ...)的变量名少了字母o(应为nftContractList),变量名错误会导致映射查询失败,触发require revert进而引发Gas估算错误。先修正变量名,再确认目标NFT合约地址已正确添加到允许列表中。验证NFT授权实际生效状态
不要仅依赖setApprovalForAll的调用记录,直接调用目标NFT合约的isApprovedForAll(msg.sender, address(this))查询全局授权状态,或调用getApproved(_tokenId)查询单代币授权状态。部分钱包可能存在授权调用未上链、授权地址填错的情况。确认
MarineBluesContract接口兼容性
检查你定义的MarineBluesContract接口是否与目标NFT合约的transferFrom函数签名完全一致。比如部分自定义ERC721合约会在transferFrom中添加额外参数,或返回值类型与标准ERC721不同(标准为void,部分合约返回bool),接口不匹配会导致调用失败,触发Gas估算错误。排查NFT合约的转移限制
部分NFT合约会在transferFrom中加入自定义逻辑:比如代币是否处于锁定状态、是否仅允许特定角色转移等。可以直接在测试网手动调用目标NFT合约的transferFrom,将该代币转移到质押合约,若手动调用失败,说明问题出在NFT合约的转移限制上。检查Solidity版本与ABI兼容性
确保质押合约与目标NFT合约的Solidity版本差异在合理范围内(避免用0.8.x合约调用0.4.x旧合约),版本差异过大可能导致ABI编码/解码错误,引发Gas估算失败。验证nonReentrant修饰符状态
如果之前的质押调用出现过异常,nonReentrant的锁可能未正常释放,导致后续调用被拒绝。可在测试环境中检查锁状态(若合约暴露相关变量),或重新部署合约测试。
内容的提问来源于stack exchange,提问作者LSH

