调用setApprovalForAll后,NFT市场transferFrom仍报错问题排查
问题排查方案
核心问题定位
报错'Only the owner of NFT can transfer or burn it'说明执行transferFrom时,NFT合约判定调用方既不是NFT所有者,也未获得合法授权。
逐一排查要点
1. 确认setApprovalForAll授权有效性
- 检查NFT合约中
setApprovalForAll的实现是否正确修改了_operatorApprovals[owner][operator]状态,符合ERC721标准 - 在Remix中调用NFT合约的
isApprovedForAll方法,传入调用listNFT的用户地址和市场合约地址,确认返回值为true - 注意:
setApprovalForAll必须由对应NFT的所有者发起,不能用其他地址执行授权操作
2. 检查transferFrom调用逻辑
市场合约中调用ERCNFT.transferFrom(msg.sender, address(this), _tokenId)时,需确认:
ERCNFT指向的是正确的AliveNatureERC721合约地址,无引用错误msg.sender确实是该_tokenId的NFT所有者,可通过NFT合约的ownerOf(_tokenId)方法验证- 若市场合约为代理合约,需确认代理正确转发了
msg.sender(禁止用tx.origin替代msg.sender)
3. 排查NFT合约的权限校验逻辑
查看AliveNatureERC721中_beforeTokenTransfer或自定义权限校验代码:
- 若重写了
transferFrom或_transfer方法,需确保同时兼容所有者直接转移和授权操作者转移两种场景 - 错误示例(仅校验所有者,忽略授权):
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override { super._beforeTokenTransfer(from, to, tokenId); if (from != ownerOf(tokenId)) { revert("Only the owner of NFT can transfer or burn it"); } }
- 正确逻辑需同时校验授权:
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override { super._beforeTokenTransfer(from, to, tokenId); address owner = ownerOf(tokenId); bool isAuthorized = (msg.sender == owner) || isApprovedForAll(owner, msg.sender) || getApproved(tokenId) == msg.sender; if (!isAuthorized) { revert("Only the owner of NFT can transfer or burn it"); } }
4. 市场合约内调用授权无效的原因
市场合约无法替用户执行setApprovalForAll——该方法需要用户签名触发,市场合约调用时msg.sender是合约自身,无法修改用户的授权状态。
验证操作步骤
- 在Remix中调用NFT合约的
ownerOf(_tokenId),确认当前所有者为测试用的用户地址 - 调用
setApprovalForAll(市场合约地址, true),再调用isApprovedForAll(用户地址, 市场合约地址)确认授权成功 - 调用市场合约的
listNFT方法,开启Remix调试模式,查看执行到transferFrom时的msg.sender、ownerOf(_tokenId)、isApprovedForAll返回值,定位具体异常点
内容的提问来源于stack exchange,提问作者Ewerton Pereira
相关产品推荐
相关产品推荐

