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

使用ERC20铸造ERC721 NFT时遇标识符重复声明错误求助

解决Solidity中ERC20导入重复声明错误

我是Solidity新手,正在尝试实现支持ETH及USDT等ERC20代币购买铸造ERC721 NFT的功能,但无论如何尝试,始终出现如下错误:

DeclarationError: Identifier already declared. --> contract-9b5b02c5de.sol:9:1:
|
9 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

我的代码如下:

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

import "@openzeppelin/contracts@4.8.0/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts@4.8.0/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts@4.8.0/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts@4.8.0/access/Ownable.sol";
import "@openzeppelin/contracts@4.8.0/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";


contract Combat is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;

    ERC20 public tokenUsdt;
    uint256 public ethPrice = 0;
    uint256 public usdtPrice = 0;
    uint256 public maxSupply; //Maximum amount token
    bool public isMintEnabled; //default : false
    mapping(address=>uint256) public mintedWallets;


    constructor(address _tokenUsdt) ERC721("XXX", "QAZ") {
        maxSupply = 100;
        tokenUsdt = ERC20(_tokenUsdt);
    }

    function setToken(address _tokenUsdt) external onlyOwner {
        tokenUsdt = _tokenUsdt;
    }

    function setPrice(uint256 _ethPrice, uint256 _usdtPrice) external onlyOwner {
        ethPrice = _ethPrice;
        usdtPrice = _usdtPrice;
    }

    function buyMembershipUsdt() external payable {
        require(msg.value >= usdtPrice, "Price Error");
        tokenUsdt.safeTransferFrom(msg.sender, owner(), _amount);
        mintMembership();
    }

    function buyMembershipEth() external payable {
        require(msg.value >= ethPrice, "Price Error");
        mintMembership();
    }

    function mintMembership() internal {
        require(isMintEnabled, "Not For Sale");
        require(totalSupply() < maxSupply, "Sold Out");

        uint256 tokenId = _tokenIdCounter.current();
        _tokenIdCounter.increment();
        _safeMint(msg.sender, tokenId);
    }

    function setMintEnabled(bool isMintEnabled_) external onlyOwner {
        isMintEnabled = isMintEnabled_;
    }

    function _baseURI() internal pure override returns (string memory) {
        return "ipfs://bafybeiebgbvibloa3p3vge7ecxobwxxnuyg4pdozbcfjigfglhz2ogidq4/";
    }

    function setMaxSupply(uint256 maxSupply_) external onlyOwner{
        maxSupply = maxSupply_;
    }

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

    function withdrawToken() external onlyOwner {
        uint256 tokenBalance = tokenUsdt.balanceOf(address(this));
        require(tokenBalance > 0, "Insufficient balance");
        tokenUsdt.safeTransfer(msg.sender, tokenBalance);
  }

  // The following functions are overrides required by Solidity.

    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }
}

问题原因及解决方案

1. 核心错误:导入版本不一致

你导入OpenZeppelin合约时混用了带版本号(@4.8.0)和不带版本号的路径:

  • 前5个导入用的是@openzeppelin/contracts@4.8.0/...
  • 最后一个ERC20导入用的是@openzeppelin/contracts/token/ERC20/ERC20.sol

这会导致编译器加载两个不同版本的ERC20合约,从而触发Identifier already declared错误。

2. 修复导入问题

将所有OpenZeppelin合约的导入路径统一版本号,修改最后一行导入为:

import "@openzeppelin/contracts@4.8.0/token/ERC20/ERC20.sol";

3. 额外代码问题修正

除了导入错误,你的代码还有两处需要调整:

  • buyMembershipUsdt函数中使用了未定义的_amount变量,应替换为usdtPrice
  • 该函数不需要payable修饰符,因为USDT转账和ETH转账是独立逻辑,添加payable会允许用户误转ETH到合约

修正后的函数:

function buyMembershipUsdt() external {
    tokenUsdt.safeTransferFrom(msg.sender, owner(), usdtPrice);
    mintMembership();
}

4. 优化建议:使用IERC20接口

由于你只是调用USDT的标准ERC20方法,不需要继承或实现完整的ERC20合约,推荐导入IERC20接口来减少合约字节码大小:

import "@openzeppelin/contracts@4.8.0/token/ERC20/IERC20.sol";

同时将变量声明改为:

IERC20 public tokenUsdt;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 14:05:22