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

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持有者,不符合转账校验要求。

修复步骤

  1. 修改NFT合约代码:删除createToken中无效的setApprovalForAll调用,授权操作改为由用户在前端主动发起。
  2. 修改市场合约代码:删除无效的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);
}
  1. 修改前端调用代码:增加主动授权步骤,修正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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 19:48:04