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

如何解决ERC721调用transferToken时出现caller is not owner报错

问题根因

你的报错核心是调用safeTransferFrom时的from地址和NFT实际所有者不匹配,且合约没有获得对应NFT的操作权限:

  1. 你在createAuction方法中执行_mint(msg.sender, newTokenId),该NFT的所有者是调用createAuction的用户,不是Auction合约本身(即address(this))。
  2. 你调用safeTransferFrom时第一个参数填的是address(this),相当于尝试从合约地址转走不属于它的NFT,自然触发权限报错。
  3. 你之前尝试在合约内部执行approve(address(this), _auctionInfo[id].tokenId)也不生效,是因为approve只能由NFT所有者本人或者所有者已授权的地址调用,合约本身不是NFT所有者,没有权限给自己授权操作用户的NFT,这是ERC721的标准安全规则。
解决方案

你可以根据业务需求选择以下两种方案之一:

方案1:NFT由合约托管(推荐用于拍卖场景)

直接修改铸造逻辑,把铸造的NFT直接给到合约地址持有,不需要额外授权即可转移:
修改createAuction方法中的mint逻辑:

// 原代码:_mint(msg.sender, newTokenId);
// 改为:
_mint(address(this), newTokenId);

修改后你原来的transferToken方法不需要其他改动,直接调用safeTransferFrom(address(this), highestBidder, tokenId)即可正常执行。

方案2:NFT仍由用户持有,无需托管

如果业务要求NFT不进入合约地址,需要用户提前主动授权合约操作他的NFT:

  1. 首先修改AuctionInfo结构体,新增字段存储NFT的所有者(即卖家地址):
struct AuctionInfo {
    uint256 tokenId;
    address highestBidder;
    uint highestBid;
    address seller; // 新增字段存储NFT所有者
}
  1. 在createAuction方法中新增赋值逻辑:
_auctionInfo[id].seller = msg.sender;
  1. 前端流程新增引导步骤:要求调用createAuction的用户,先在链上签名执行NFT合约的approve(Auction合约地址, 对应tokenId),或者执行setApprovalForAll(Auction合约地址, true)授权合约操作他所有的NFT,这一步必须由用户主动发起,不能在合约内部自动完成。
  2. 修改transferToken方法中的转移逻辑,from参数改为实际的NFT所有者:
safeTransferFrom(_auctionInfo[id].seller, _auctionInfo[id].highestBidder, _auctionInfo[id].tokenId);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 01:15:07