ERC721报错transfer caller is not owner nor approved问题求解
ERC721转账报错问题定位与修复方案
根因定位
共存在3处核心错误导致报错:
- 授权逻辑执行主体错误:NFT合约
createToken中调用的setApprovalForAll执行上下文是NFT合约本身,并非NFT持有者(铸造用户),相当于NFT合约地址给市场地址授权,对属于用户的NFT完全不生效。 - 市场合约逻辑顺序错误:
createItem中先执行transferFrom转账,再调用approve授权,逻辑完全倒置。且市场合约不是NFT持有者,没有权限调用approve对该NFT进行授权,这行代码完全无效。 - 前端调用参数错误:调用
createItem时from参数写为{owners},实际传入的是嵌套对象,调用者并非NFT持有者,不符合转账校验要求。
修复步骤
- 修改NFT合约代码:删除
createToken中无效的setApprovalForAll调用,授权操作改为由用户在前端主动发起。 - 修改市场合约代码:删除无效的
approve调用,增加调用者身份校验,修改后代码如下:
function createItem( address nftContract, uint256 tokenId ) public payable{ address _owner = IERC721(nftContract).ownerOf(tokenId); // 校验调用者为NFT持有者,防止恶意挂单 require(msg.sender == _owner, "Only owner can list NFT"); // 持有者已提前授权的前提下直接转账 IERC721(nftContract).transferFrom(_owner, address(this),tokenId); }
- 修改前端调用代码:增加主动授权步骤,修正
from参数,修改后代码如下:
const getItems=async()=>{ // 铸造NFT await contracts.nft.methods.createToken("https://i.ytimg.com/vi/nYxGhQYi0s4/maxresdefault.jpg").send({from: accounts[0]}); // 由NFT持有者主动给市场合约授权操作权限 await contracts.nft.methods.setApprovalForAll(contracts.stripeMarket._address, true).send({from: accounts[0]}); // 调用挂单接口,调用者为NFT持有者 await contracts.stripeMarket.methods.createItem(contracts.nft._address,1).send({from: accounts[0]}); }
内容的提问来源于stack exchange,提问作者sun_dance
相关产品推荐
相关产品推荐

