简体   繁体   English

如何转移 ERC721 代币

[英]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方法尝试过thispayable(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.senderapprove在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 .由于ERC721internal可见性。 _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合约和从它派生的合约(在你的情况下MainAuction )调用,但不能从外部合约或最终用户地址调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM