簡體   English   中英

如何將 NFT 轉移到另一個智能合約?

[英]How to transfer a NFT to another smart contract?

我正在嘗試設置一個托管合同,該合同將存款作為 NFT 存入合同。 我正在努力將 NFT 存入合約。

我首先有一個簡單的 NFT,它被鑄造到帶有 ID 的地址。

contract MyEpicNFT is ERC721URIStorage {
  // Magic given to us by OpenZeppelin to help us keep track of tokenIds.
  using Counters for Counters.Counter;
  Counters.Counter private _tokenIds;

  // We need to pass the name of our NFTs token and its symbol.
  constructor() ERC721 ("SquareNFT", "SQUARE") {
    console.log("This is my NFT contract. Woah!");
    console.log(address(this));
  }

  // A function our user will hit to get their NFT.
  function makeNft() public {
    uint256 newItemId = _tokenIds.current();

    _safeMint(msg.sender, newItemId);

    _setTokenURI(newItemId, "https://jsonkeeper.com/b/1LHH");
    console.log("An NFT w/ ID %s has been minted to %s", newItemId, msg.sender);


    _tokenIds.increment();
  }
}

在這種情況下,合約的 msg.sender 已生成 ID 為 0 的 NFT:0xdD870fA1b7C4700F2BD7f44238821C26f7392148

我現在知道我需要批准托管合同才能“花費”此令牌。 為了在 MyEpicNft 合約上執行此操作,我調用 approve function,其中包含 MyEpicNft 的合約地址和鑄造的 NFT 的 ID。

console.log:
 This is my NFT contract. Woah!
 0x5fc7Dc95b4Bb48dbC9894fCaE417482cb8A6A45a

在我的例子中,我用 (0x5fc7Dc95b4Bb48dbC9894fCaE417482cb8A6A45a, 0) 調用批准 - 這似乎有效。 現在我需要在 NftEscrow 合約中做的是存入 NFT。

我使用的 approve function 來自 ERC721 lib

approve(address to, uint256 tokenId)

有一個 depositNFT function,它采用 NFT 地址——在我們的例子中是 0x5fc7Dc95b4Bb48dbC9894fCaE417482cb8A6A45a 和 0。但是當我這樣做時,我收到錯誤消息:

The transaction has been reverted to the initial state.
Reason provided by the contract: "ERC721: transfer caller is not owner nor approved".
Debug the transaction to get more information.


contract NftEscrow is IERC721Receiver {
    
    enum ProjectState {newEscrow, nftDeposited, cancelNFT, ethDeposited, canceledBeforeDelivery, deliveryInitiated, delivered}
    
    address payable public sellerAddress;
    address payable public buyerAddress;
    address public nftAddress;
    uint256 tokenID;
    bool buyerCancel = false;
    bool sellerCancel = false;
    ProjectState public projectState;

    receive() external payable {
    
     }

    constructor(){
        sellerAddress = payable(msg.sender);
        projectState = ProjectState.newEscrow;
    }
    
    function onERC721Received( address , address , uint256 , bytes calldata  ) public pure override returns (bytes4) {
        return this.onERC721Received.selector;
    }
    
    function depositNFT(address _NFTAddress, uint256 _TokenID) public onlySeller {
        nftAddress = _NFTAddress;
        tokenID = _TokenID;
        ERC721(nftAddress).safeTransferFrom(msg.sender, address(this), tokenID);
        projectState = ProjectState.nftDeposited;
    }

    function depositEth() public payable {
        buyerAddress = payable(msg.sender);
        projectState = ProjectState.ethDeposited;
    }

    function confirmDelivery()public payable  {
        ERC721(nftAddress).safeTransferFrom(address(this), buyerAddress, tokenID);
        sellerAddress.transfer(address(this).balance);
    }
    

    modifier onlySeller() {
        require(msg.sender == sellerAddress);
        _;
    }

} 
 

不確定我做錯了什么並且堅持了一天。 為什么我不能將 NFT 存入智能合約?

如果以下任何一項都不為真,您的托管合同將恢復為"ERC721: transfer caller is not owner nor approved"

  1. msg.sender是合約的所有者
  2. msg.sender已為所有人批准
  3. msg.sender被所有者批准用於該令牌

根據您的情況,我們選擇第三種選擇。

我們需要檢查的是

  1. 你真的批准了正確的地址嗎?
  2. 批准function回復了嗎?

當托管合約調用NFT合約時

ERC721(nftAddress).safeTransferFrom(msg.sender, address(this), tokenID);

在 NFT 合約看來, msg.sender是托管合約。 所以 99% 的問題出在你的審批流程上。 請分享更多相關信息。

編輯:

我們試圖使以下條件為真,其中spender者是托管合約的地址

return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);

如果 getApproved 確實返回了合約地址,請嘗試將以下 function 添加到您的 nft 合約中:

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual override returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721.ownerOf(tokenId);
        console.log("spender %s", spender);
        console.log("getApproved %s", getApproved(tokenId);
        return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM