如何实现授权合约运营商来执行 NFT 代币的购买操作?

问题描述

我已经实施了一个基本合约,可以铸造代币、将代币转移到其他人的账户以及购买 NFT。这是在 Remix 上测试的完全实现的代码

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

import '@openzeppelin/contracts/utils/Counters.sol';
import '@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol';

contract ArtWorkMinter is ERC721URIStorage{

  mapping(uint256 => address) idToOwner;
  mapping(address => uint256[]) userTokenList;
  mapping(uint256 => uint256) tokenPriceList;

  using Counters for Counters.Counter;
  Counters.Counter private _tokenIds;
  constructor() ERC721("MyNFT","MNFT") {}

    function mint_art_work(address receiver,string memory tokenURI,uint price) external {
    _tokenIds.increment();

    uint256 newNftTokenId = _tokenIds.current();
    _mint(receiver,newNftTokenId);
    _setTokenURI(newNftTokenId,tokenURI);

    userTokenList[receiver].push(newNftTokenId);
    idToOwner[newNftTokenId] = receiver;
    tokenPriceList[newNftTokenId] = price;
  }

  function my_total_tokens(address receiver) external view returns (uint256){
    return userTokenList[receiver].length;
  }

  function get_my_nft_tokens(address receiver) external view returns (uint256[] memory){
    return userTokenList[receiver];
  }

  function get_token_details(uint token_id) external view returns (string memory){
    return tokenURI(token_id);
  }

  function _transfer_token(address from_address,address to_address,uint token_id) internal{
    // Update contract variables --
    idToOwner[token_id] = to_address;
    // Move the last element into the place of token id,delete the last item in array --
    for(uint i = 0; i<userTokenList[from_address].length-1; i++){
      if(userTokenList[from_address][i] == token_id){
        userTokenList[from_address][i] = userTokenList[from_address][userTokenList[from_address].length - 1];
        userTokenList[from_address].pop();
        break;
      }
    }
    // Add nft token to to address mapping array --
    userTokenList[to_address].push(token_id);
  }

  function transfer_token(address from_address,uint token_id) external{
    // Check if the caller is the owner of the token id --
    require(ownerOf(token_id) == msg.sender,"NOT OWNER");
    // approve the target address on which we are going to transfer the token
    approve(to_address,token_id);
    // transfer the token --
    safeTransferFrom(from_address,to_address,token_id);

    _transfer_token(from_address,token_id);
  }

  function buy_token(uint token_id) external payable{
    require(msg.value >= tokenPriceList[token_id]);
    // approve the target address on which we are going to transfer the token
    approve(msg.sender,token_id);
    // transfer the token --
    address token_owner = ownerOf(token_id);
    safeTransferFrom(token_owner,msg.sender,token_id);
    _transfer_token(token_owner,token_id);
    // send the ETH to the seller
    payable(token_owner).transfer(msg.value);
  }
}

合约可以成功铸造代币和转移代币。但是,每当我执行函数 buy_token 时,都会出现以下错误

transact to ArtWorkMinter.buy_token errored: VM error: revert.

revert
    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. 

我想我理解错误以及问题出在哪里,在 NFT 令牌从所有者账户转移到支出者账户之前,必须先批准调用用户(支出者)。因为代币是由所有者创建的,所有者不会购买他自己的代币,其他一些用户会这样做。但是其他用户 (Spender) 不能调用 transferFromapprove 因为他不是令牌的所有者。 那么,我们如何解决这个问题呢?解决此问题的标准方法是什么?

经过一番研究,我知道应该有一个额外的合同,称为“运营商合同”,它将代表所有者批准和转让代币。

如何实施此运营商合同以及此合同如何与主要 NFT 合同合并?

任何建议或示例将不胜感激。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...