NFT Marketplace二次售卖触发SetApprovalForAll权限错误排查求助
解决NFT Marketplace二次售卖的"Caller not owner nor approved"错误
我帮你排查了代码,问题的根源很清晰:首次交易后,新的代币所有者没有给Marketplace合约授予操作NFT的权限。
问题细节拆解
- 在
NFTS合约的createNFT函数里,铸造者(地址A)调用了setApprovalForAll(marketPlace, true),给Marketplace合约开了操作自己所有NFT的权限,所以第一次从A到B的售卖能顺利执行transferFrom。 - 但当地址B成为新所有者后,他并没有给Marketplace合约授权。虽然你的上架函数只检查B是代币所有者,所以B能成功上架,但当C尝试购买时,Marketplace需要调用
transferFrom(B, C, tokenId)——这时候Marketplace既不是代币所有者,也没有得到B的授权,自然会抛出权限错误。
具体解决方案
1. 上架时强制检查授权(最直接的修复)
修改Marketplace合约的itemInMarketplace函数,添加一个检查:确保代币所有者已经给Marketplace合约授权,允许操作他的NFT。这样就能在用户上架阶段就把问题拦住,避免后续购买失败。
在itemInMarketplace函数的require语句中添加这一行:
require(NFTS(_nftContract).isApprovedForAll(tokenOwner, address(this)), "Marketplace needs approval to manage your NFTs");
修改后的完整itemInMarketplace函数关键部分:
function itemInMarketplace( address _nftContract, uint _tokenId, uint _price, uint _royalties )external payable nonReentrant{ address tokenOwner = NFTS(_nftContract).ownerOf(_tokenId); address tokenCreator = NFTS(_nftContract).tokenCreator(_tokenId); require(_price > 0, "Cannot set a price less or equal to 0!"); require(msg.value == listingPrice, "You have to pay 1 wei to list your token!"); require(msg.sender == tokenOwner, "Cannot list a token if is not yours!" ); require(_royalties > 5 && _royalties < 20, "You can set royalties between 5% and 20 % !"); // 新增的授权检查 require(NFTS(_nftContract).isApprovedForAll(tokenOwner, address(this)), "Marketplace needs approval to manage your NFTs"); _itemId.increment(); uint newId = _itemId.current(); // ... 剩余代码保持不变 }
2. 引导用户完成授权
在你的前端交互流程中,需要提示用户:在NFT上架前,先调用NFTS合约的setApprovalForAll(marketplaceAddress, true)函数,给Marketplace合约授予操作权限。这是ERC721标准的常规操作,用户在主流NFT平台也会遇到类似的授权步骤。
额外的代码优化建议
- 你的
purchase函数里,_buyer = payable(_tokenOwner);这行代码是多余的,因为_tokenOwner已经被赋值为payable(msg.sender)了,可以删掉。 - 不要使用
_itemId.decrement();——当你删除一个上架项后递减计数器,会导致新上架的项复用之前的ID,容易引发数据冲突。建议让计数器一直递增,删除的项可以用一个状态标记为已下架,而不是直接删除mapping里的数据。
内容的提问来源于stack exchange,提问作者Matteo Gigli
相关产品推荐
相关产品推荐

