[英]How to transfer an ERC721 token
I'm trying to transfer an ERC721 token, but I'm getting the error ERC721: transfer caller is not owner nor approved
for the transferToken
method.我正在尝试转移一个 ERC721 令牌,但我收到错误
ERC721: transfer caller is not owner nor approved
用于transferToken
方法。
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拍卖.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...
}
The minting contract is this
and the owner of the token is the msg.sender
of the minting method if I'm not mistaken.铸币合约是
this
,如果我没记错的话,代币的所有者是铸币方法的msg.sender
。 Am I to use the approve
(or setApprovalForAll
) for this
each time before transferring?我在使用
approve
(或setApprovalForAll
)对于this
每次转移前? I've tried this
, payable(this)
, and address(this)
for the safeTransferFrom
method, but none seem to be working.我已经为
safeTransferFrom
方法尝试过this
、 payable(this)
和address(this)
,但似乎都没有工作。
For example, I tried the following, but get the same revert message:例如,我尝试了以下操作,但得到相同的恢复消息:
approve(address(this), _auctionInfo[id].tokenId);
this.safeTransferFrom(address(this), _auctionInfo[id].highestBidder, _auctionInfo[id].tokenId);
The main principle behind any Blockchain is that nobody on the blockchain network should be trusted, and still the transactions should happen fool proof, with no possibility of any cheating being done (barring of course of some hacking).任何区块链背后的主要原则是区块链网络上的任何人都不应该被信任,并且交易仍然应该发生万无一失,没有任何作弊的可能性(当然,除非有一些黑客行为)。
If you invoke the approve method from the Auction
contract, then the msg.sender
for the approve function in the ERC721 token contract is your auction contract address.如果你在
Auction
合约中调用了approve方法,那么msg.sender
代币合约中approve函数的msg.sender就是你的拍卖合约地址。 So, in other words, your Auction Contract is trying to approve itself to sell someone else's NFTs, which is not very trustworthy.所以,换句话说,你的拍卖合约试图批准自己出售别人的 NFT,这不是很值得信赖。
What should really happen is that owner of the NFT should invoke the approve
method of the ERC721 contract - ie the transaction that you send for the approve
function call, should be signed by the NFT owner wallet address.真正应该发生的是,NFT 的所有者应该调用 ERC721 合约的
approve
方法——即您为approve
函数调用发送的交易,应该由 NFT 所有者的钱包地址签名。 This way, the msg.sender
for the approve
function in the ERC721 contract will be the owner of the NFT.这样,
msg.sender
的approve
在ERC721合同功能将是NFT的所有者。 As per the ERC721 standards, the owner of the NFT can approve anyone they want, to sell their NFT(s), as the no-trust in the network is still maintained (At least I should be able to trust myself).根据 ERC721 标准,NFT 的所有者可以批准他们想要的任何人出售他们的 NFT,因为对网络的不信任仍然存在(至少我应该能够相信自己)。 The
approve
method should be invoked from within your DAPP, before the transferToken
function is invoked from the DAPP.在从 DAPP 调用
transferToken
函数之前,应从您的 DAPP 中调用approve
方法。
Hope that explains why you are unable to transfer your ERC721 tokens.希望这能解释为什么您无法转移您的 ERC721 代币。
Because of the internal
visibility of the ERC721
.由于
ERC721
的internal
可见性。 _approve()
function, you can effectively perform the approval for the user. _approve()
函数,可以有效地对用户进行审批。
Then you'll be able to execute the safeTransferFrom(tokenOwner, receiver, tokenId)
from your contract, because your contract address is approved to operate this specific token even though it belongs to the tokenOwner
.然后你就可以从你的合约中执行
safeTransferFrom(tokenOwner, receiver, tokenId)
,因为你的合约地址被批准操作这个特定的代币,即使它属于tokenOwner
。
This snippet mints the token, assigning the ownership to the msg.sender
.此代码段
msg.sender
令牌,将所有权分配给msg.sender
。 But then it also calls the _approve()
function that doesn't contain any validations and simply assigns the approval of the token to the Auction
address.但随后它还会调用不包含任何验证的
_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);
}
}
You can see from the screenshot that the owner is 0x5B...
(the user address) and that the token is approved for 0xd9...
(the contract address).从截图中可以看出,拥有者是
0x5B...
(用户地址),代币被批准为0xd9...
(合约地址)。
Note: The _approve()
function is internal
- it can be called from the ERC721
contract and contracts deriving from it (in your case Main
and Auction
), but it can't be called from external contracts or end user addresses.注意:
_approve()
函数是internal
- 它可以从ERC721
合约和从它派生的合约(在你的情况下Main
和Auction
)调用,但不能从外部合约或最终用户地址调用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.