如何将NFT转移到另一个智能合同中?

发布于 2025-01-17 14:02:21 字数 3147 浏览 2 评论 0原文

我正在尝试设置托管合同,该托管合同将押金作为NFT纳入合同。我正在努力将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();
  }
}

在这种情况下,w/ id 0的NFT已被铸造给合同的味精。:0xDD870FA1B7C4700F2BD7F2BD7F444238821C26F7392148

我知道现在我需要允许批准托管合同来“支出”此tokken。为了在myepicnft合同上执行此操作,我将myepicnft的合同地址和铸造的NFT的ID称为批准功能。

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

就我而言,我将(0x5FC7DC95B4BB48DBC9894FCAE417482CB8A6A45A,0)称为批准。现在,我需要在NFTESCROW合同中要做的是存放NFT。

我使用的批准功能是来自ERC721 lib,

approve(address to, uint256 tokenId)

有一个reademnft函数获取NFT地址 - 在我们的情况下0x5fc7dc7dc95b4bb48db48dbc9894fcae417482cb8a6a45a和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存入智能合同?

I am trying to setup an escrow contract which takes a deposit as a NFT into the contract. I am struggling to deposit the NFT into the contract.

I start by having a simple NFT that gets minted to the address with an 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();
  }
}

An NFT w/ ID 0 has been minted to the msg.sender of the contract in this case: 0xdD870fA1b7C4700F2BD7f44238821C26f7392148

I know now I need to approve the Escrow contract to be allowed to "spend" this token. To do this on MyEpicNft contract I call the approve function with the contract address of the MyEpicNft and the Id of the NFT that was minted.

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

In my case I call the approve with (0x5fc7Dc95b4Bb48dbC9894fCaE417482cb8A6A45a, 0) - this seems to work. Now what I need to do in the NftEscrow contract is to deposit the NFT.

The approve function i am using is from the ERC721 lib

approve(address to, uint256 tokenId)

There is a depositNFT function which takes the NFT address - in our case 0x5fc7Dc95b4Bb48dbC9894fCaE417482cb8A6A45a and 0. But when i do this i get the error message:

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);
        _;
    }

} 
 

Not sure what I am doing wrong and been stuck on this for a day. Why can't i deposit the NFT to the smart contract?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

虚拟世界 2025-01-24 14:02:22

您的托管合同将使用“ ERC721:转让呼叫者为所有者也不批准”如果以下各项为真:

  1. msg.sender是合同的所有者
  2. 。 sg.sender 已批准所有者
  3. msg.sender在您的情况下,所有者批准了该令牌

,我们选择了第三种选项。

我们需要检查的是

  1. 您是否真的批准了正确的地址?
  2. 批准功能还原了吗?

当托管合同

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

以NFT合同的角度拨打NFT合同时,msg.sender是托管合同。因此,您的批准过程为99%。请分享有关此信息的更多信息。

编辑:

我们正在尝试使以下条件正确,其中spender是托管合同的地址,

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

如果签名确实是返回合同地址,请尝试在您的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);
    }

Your escrow contract will revert with "ERC721: transfer caller is not owner nor approved" if none of the following are true:

  1. msg.sender is the owner of contract
  2. msg.sender is approved for all for the owner
  3. msg.sender is approved for that token by the owner

In your situation, we are opting for the 3rd option.

What we need to check is

  1. Did you really approve correct address?
  2. Did approve function revert?

When the escrow contract calls the NFT contract

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

in NFT contract's point of view, the msg.sender is the escrow contract. So the problem is 99% with your approval process. Please share more information about that.

EDIT:

We are trying to get the following condition true, where the spender is the escrow contract's adress

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

If getApproved is really returns the contract address, try adding following function to your nft contract:

    /**
     * @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);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文