You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Solidity ERC721调用walletOfOwner报Internal JSON-RPC回滚错误

问题根因

调用回滚的核心原因如下:

  • 你的合约仅导入了IERC721Enumerable接口,没有实际继承ERC721Enumerable的实现逻辑。基础版ERC721、ERC721URIStorage都没有实现tokenOfOwnerByIndex这类持仓枚举方法,你在代码中强行将合约地址转换为IERC721Enumerable类型调用未实现的方法,EVM执行时会直接触发回滚,返回execution reverted错误。
  • 自定义的walletOfOwner函数额外传入了contractAddress参数,一旦传入的地址不是当前NFT合约地址、或者对应地址合约没有实现枚举逻辑,也会直接触发调用回滚。
修复方案
  1. 调整合约导入与继承关系
    把原有导入IERC721Enumerable的代码替换为导入ERC721Enumerable实现:
    import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
    
    修改合约声明,加入ERC721Enumerable继承:
    contract TestNFT is ERC721URIStorage, ERC721Enumerable, Ownable {
    
  2. 重写多继承冲突的方法
    ERC721、ERC721Enumerable、ERC721URIStorage存在同名函数冲突,必须在合约内显式重写才能正常编译:
    // 重写接口支持查询,兼容所有父合约逻辑
    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable, ERC721URIStorage)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
    
    // 重写转账前置钩子,同步更新枚举模块的持仓索引数据
    function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
        internal
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId, batchSize);
    }
    
    // 重写tokenURI查询,解决URI存储与基础ERC721的逻辑冲突
    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }
    
    // 重写销毁逻辑,同步清理URI存储与枚举模块的对应数据
    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }
    
  3. 简化walletOfOwner实现
    移除多余的contractAddress参数,直接调用当前合约继承的枚举方法:
    function walletOfOwner(address owner_) public view returns (uint256[] memory){
        uint256 _tokenCount = balanceOf(owner_);
        uint256[] memory _tokens = new uint256[](_tokenCount);
        for(uint256 i=0; i < _tokenCount; i++){
            _tokens[i] = tokenOfOwnerByIndex(owner_, i);
        }
        return _tokens;
    }
    
注意事项
  • 修改完成后需要重新编译部署合约,已经部署上线的旧合约无法通过升级补全枚举逻辑:ERC721Enumerable需要在铸造、转账、销毁时同步更新持仓索引映射,旧合约没有存储这部分链上数据,无法追溯历史持仓。
  • 新合约部署后,先铸造测试NFT,再调用walletOfOwner传入对应持仓地址,即可正常返回该地址持有的全部token ID列表,不会再出现JSON-RPC执行回滚错误。

内容的提问来源于stack exchange,提问作者PKS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 16:30:43