我正在尝试使用 ethers.js 铸造 NFT,我的前端代码似乎有问题

I am trying to mint NFT using ethers.js, there seems to be a problem with my frontend code

我曾多次尝试使用 ethers.js 铸造 NFT。我的代码有问题吗?我总是收到此错误:Error: transaction failed [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ]

而且我的solidity代码似乎没有任何问题。

我的前端代码:

const player: PlayerInterface = {
      name: "Lionel Messi",
      preferredPosition: "RWF",
      id: 1,
      age: 34,
      level: 20,
      lastUpgrade: new Date().getTime(),
      suitablePositions: ["ST", "CF", "RMF", "CAM"],
      imageURI:
        "https://bafybeicfhmevzs4aso7rqvx7l5ndb2ly7gudjyj5xjkztvohpwxw2za7iy.ipfs.dweb.link/nft.png",
    };
    const provider = new ethers.providers.Web3Provider(
      (window as any).ethereum
    );
    const signer = provider.getSigner();
    const tx = await futNFT.connect(signer).mint(player, {
      gasPrice: 30000000000,
      gasLimit: 2000000,
    });
    await tx.wait();
    console.log("minted");
    const player1 = await futNFT.getPlayer(1);
    console.log(player1);

这是我的 solidity 智能合约:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract FutNFT is ERC721, ERC721Enumerable, Ownable {
    /// @dev Should have logic for players with no suitable position array
    struct Player {
        string name;
        string preferredPosition;
        uint256 id;
        uint8 age;
        uint8 level;
        uint64 lastUpgrade;
        string[] suitablePositions;
        string imageURI;
    }

    struct History {
        uint256 winCount;
        uint256 lossCount;
    }

    mapping(address => History) ownerHistory;
    mapping(uint256 => Player) players;
    mapping(uint256 => address) public playerToOwner;
    mapping(uint256 => uint256) listedPlayerIndex;
    uint256[] public listedPlayers;
    uint256[] playerIds;

    event PlayerAdded(uint256 playerId);

    modifier owned(uint256 id) {
        require(getPlayerExists(id), "Player does not exist");
        require(msg.sender == ownerOf(id), "Not the owner!");
        _;
    }

    constructor() ERC721("FutNFT", "FNFT") {}

    function getListedPlayers() public view returns (uint256[] memory) {
        return listedPlayers;
    }

    function getPlayer(uint256 _id) public view returns (Player memory) {
        return players[_id];
    }

    function getPlayersByOwner(address _owner)
        public
        view
        returns (uint256[] memory)
    {
        uint256[] memory result;
        uint256 index = 0;
        for (uint256 i = 0; i < playerIds.length; i++) {
            if (playerToOwner[playerIds[i]] == _owner) {
                result[index] = playerIds[i];
                index++;
            }
        }
        return result;
    }

    function ownerOf(uint256 tokenId)
        public
        view
        override(ERC721, IERC721)
        returns (address)
    {
        return super.ownerOf(tokenId);
    }

    function getPlayerExists(uint256 _id) public view returns (bool) {
        return playerToOwner[_id] != address(0);
    }

    function mint(Player memory _player) public onlyOwner {
        require(playerToOwner[_player.id] == address(0), "Player Exists!");
        players[_player.id] = _player;
        playerIds.push(_player.id);
        playerToOwner[_player.id] = msg.sender;
        _mint(msg.sender, _player.id);
        emit PlayerAdded(_player.id);
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal override(ERC721, ERC721Enumerable) {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}

请告诉我这是否有问题。也请询问您是否需要更多信息。

您的 mint() 函数使用了 onlyOwner 修饰符。在 OpenZeppelin implementation 中,这意味着该函数只能从存储在 _owner 变量中的地址执行。如果您尝试从不同的地址执行它,它会恢复原状。

默认情况下(根据 OZ 实现),_owner 地址是部署合约的地址。

所以你需要从当前的 _owner 地址执行 mint() 函数——在你的例子中是部署合约的相同地址。或者删除 onlyOwner 修饰符(并重新部署合约),它打开任何人都可以执行的函数。