You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Polygon测试网NFT铸造报错:ERC721无效Token ID问题求助

问题:Polygon测试网NFT mint交易成功,但未收到NFT,调用ownerOf返回无效token ID错误

在Polygon测试网开发NFT合约,通过Remix IDE的「Injected Provider - Metamask」部署。用户支付MATIC后交易显示成功,但MetaMask账户未收到NFT,调用ownerOf函数时返回错误:

call to ERC721.ownerOf errored: Returned error: {"jsonrpc":"2.0","error":"execution reverted: ERC721: invalid token ID"

尝试了两个合约均出现相同问题,代码如下:

合约1:Example_credential1

pragma solidity ^0.8.9; //define version

import "@openzeppelin/contracts@4.8.3/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts@4.8.3/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts@4.8.3/security/Pausable.sol";
import "@openzeppelin/contracts@4.8.3/access/Ownable.sol";
import "@openzeppelin/contracts@4.8.3/utils/Counters.sol";

contract Example_credential1 is ERC721, ERC721Enumerable, Pausable, Ownable {

    event Log(string message);

    // Propoerty variables
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;
    //uint256 private _tokenIdCounter;

    uint256 public MINT_PRICE = 0.005 ether;
    uint256 public MAX_SUPPLY = 10000; //we define the max amount of NFTs that can be created

    // Lifecycle Methods
    constructor() ERC721("Example_credential1", "EC1") {
        _tokenIdCounter.increment();
    }

    //Function withdraw
    function withdraw() public onlyOwner() {
        require(address(this).balance > 0, "Balance is zero");
        payable(owner()).transfer(address(this).balance);
    }


    // Pausable Functions
    function pause() public onlyOwner {
        _pause();
    }

    function unpause() public onlyOwner {
        _unpause();
    }


    //Minting functions
    function safeMint(address to) public payable {
        require(msg.value >= MINT_PRICE, "not enough ether sent");
        require(totalSupply() <= MAX_SUPPLY, "No more tokens can be minted");
        uint256 tokenId = _tokenIdCounter.current();
        _tokenIdCounter.increment();
        _safeMint(to,tokenId);
    }


    // Other functions
    function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
        internal
        whenNotPaused
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId, batchSize);
    }

    // The following functions are overrides required by Solidity.

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

合约2:Example_credential2

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

import "@openzeppelin/contracts@4.8.3/token/ERC721/ERC721.sol";

contract Example_credential2 is ERC721 {

    uint256 public MINT_PRICE = 0.005 ether;


    uint256 public tokenCounter;
    constructor() public ERC721("Example_credential2", "EC2") {
        tokenCounter = 0;
    }

    function createCollectible(string memory tokenURI) public returns (uint256){
        uint256 newItemId = tokenCounter;
        _safeMint(msg.sender, newItemId);
        tokenCounter = tokenCounter + 1;
        return newItemId;
    }

}

原因分析与解决方案

核心问题

两个合约的mint逻辑存在关键缺陷:

  • 合约1:虽有金额校验,但你可能未正确触发safeMint函数(比如只转了MATIC但没调用mint方法),且totalSupply判断逻辑有误
  • 合约2:createCollectible完全未处理MATIC支付校验,导致该函数可被无成本调用,而你转的MATIC只是单纯转账到合约,未触发mint

以上情况都会导致没有实际生成NFT,自然调用ownerOf会提示无效token ID。

针对合约1的修复

  1. 修正safeMint的供应量判断:totalSupply()返回已 mint 数量,<= MAX_SUPPLY会允许超量 mint,改为< MAX_SUPPLY
  2. 确保调用safeMint时,在Remix的「Value」输入框填写至少0.005 ether(对应5000000000000000 wei),并传入你的MetaMask地址作为to参数

修改后的safeMint函数:

function safeMint(address to) public payable {
    require(msg.value >= MINT_PRICE, "not enough ether sent");
    require(totalSupply() < MAX_SUPPLY, "No more tokens can be minted");
    uint256 tokenId = _tokenIdCounter.current();
    _tokenIdCounter.increment();
    _safeMint(to, tokenId);
}

针对合约2的修复

给createCollectible添加支付校验,确保只有支付足够MATIC才能mint:

function createCollectible(string memory tokenURI) public payable returns (uint256){
    require(msg.value >= MINT_PRICE, "Insufficient MATIC sent");
    uint256 newItemId = tokenCounter;
    _safeMint(msg.sender, newItemId);
    tokenCounter += 1;
    return newItemId;
}

调用该函数时,必须在Remix的「Value」栏填入0.005 ether以上的金额。

额外检查项

  1. 查交易详情:在Polygon测试网扫描器上查看你的交易,确认「Input Data」对应合约的mint函数调用,若只是单纯转MATIC到合约,不会触发mint
  2. 手动添加NFT:即使mint成功,MetaMask可能需要手动添加NFT(输入合约地址和对应的token ID)才能显示
  3. 确认token ID:调用合约的tokenCounter(合约2)或给合约1添加getCurrentTokenId()函数读取_tokenIdCounter.current(),确保调用ownerOf时传入的是已存在的ID

内容的提问来源于stack exchange,提问作者Frenom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 23:07:49