我正在尝试传输一个ERC721令牌,但是我得到了transferToken方法的错误ERC721: transfer caller is not owner nor approved。
Main.sol
import "./ERC721.sol";
import "./Counters.sol";
contract Main is ERC721 {
using Counters for Counters.Counter;
Counters.Counter internal _tokenIds;
address payable internal admin;
constructor() ERC721("MyToken", "TOKEN") {
admin = payable(msg.sender);
}
}Auction.sol
import "./Main.sol";
contract Auction is Main {
struct AuctionInfo {
uint256 tokenId;
address highestBidder;
uint highestBid;
}
mapping(string => AuctionInfo) private _auctionInfo;
function createAuction(string memory id) public {
_tokenIds.increment();
uint256 newTokenId = _tokenIds.current();
_mint(msg.sender, newTokenId);
_auctionInfo[id].tokenId = newTokenId;
}
function transferToken(string memory id) public {
require(msg.sender == _auctionInfo[id].highestBidder, "You are not the highest bidder");
safeTransferFrom(address(this), _auctionInfo[id].highestBidder, _auctionInfo[id].tokenId);
}
// other methods...
}造币合同是this,如果我没有弄错的话,令牌的所有者就是造币方法的msg.sender。在传输之前,我每次都要使用approve (或setApprovalForAll)作为this吗?我已经尝试过this、payable(this)和address(this)的safeTransferFrom方法,但似乎没有一种方法起作用。
例如,我尝试了以下方法,但得到了相同的还原消息:
approve(address(this), _auctionInfo[id].tokenId);
this.safeTransferFrom(address(this), _auctionInfo[id].highestBidder, _auctionInfo[id].tokenId);发布于 2021-10-28 17:04:56
任何Blockchain背后的主要原则是,区块链网络上的任何人都不应该被信任,而且这些交易仍然应该发生愚蠢的证明,不存在任何欺骗的可能性(当然,某些黑客除外)。
如果您从Auction契约中调用msg.sender方法,那么ERC721令牌契约中的ERC721函数的msg.sender就是您的拍卖契约地址。因此,换句话说,你的拍卖合同是试图批准自己出售别人的NFT,这不是很值得信赖。
真正应该发生的是,NFT的所有者应该调用ERC721契约的ERC721方法,即您为approve函数调用发送的事务应该由NFT所有者钱包地址签名。这样,msg.sender契约中的approve函数将成为NFT的所有者。根据ERC721标准,NFT的所有者可以批准任何他们想要的东西,出售他们的NFT,因为网络中的不信任仍然存在(至少我应该能够信任自己)。在从DAPP调用approve函数之前,应该在DAPP中调用transferToken方法。
希望这解释了为什么您无法传输您的ERC721令牌。
发布于 2021-10-29 08:29:58
由于internal的ERC721._approve()函数的可见性,您可以有效地为用户执行审批。
然后您将能够从您的合同执行safeTransferFrom(tokenOwner, receiver, tokenId),因为您的合同地址被批准来操作这个特定的令牌,即使它属于tokenOwner。
此代码段创建令牌,将所有权分配给msg.sender。但是,它还调用不包含任何验证的_approve()函数,并简单地将令牌的批准分配给Auction地址。
pragma solidity ^0.8;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol";
contract Auction is ERC721 {
constructor() ERC721("CollectionName", "Symbol") {}
function createAuction() public {
uint256 newTokenId = 1;
_mint(msg.sender, newTokenId);
_approve(address(this), newTokenId);
}
}您可以从屏幕截图中看到,所有者是0x5B... (用户地址),令牌被批准为0xd9... (契约地址)。

注意:_approve()函数是internal --它可以从ERC721契约及其派生的契约(在您的例子中是Main和Auction__)调用,但是不能从外部契约或最终用户地址调用它。
https://stackoverflow.com/questions/69751069
复制相似问题