使用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
相关产品推荐
相关产品推荐

