【问题标题】:ERC721 Tokens with Metadata and Enumerable with Openzeppelin v4.1.0ERC721 令牌与元数据和 Enumerable 与 Openzeppelin v4.1.0
【发布时间】:2021-05-15 06:07:32
【问题描述】:

我的问题有两个部分,

我正在尝试使用带有元数据的 Openzeppelin 合约创建一个 ERC721 令牌,这是可枚举的。我的理解是在 openzeppelin v4.0.0 之后,他们删除了包含元数据和可枚举的 ERC721Full.sol 合约。我想使用solidity 0.8.0,所以那些旧合同不起作用,对吧?在将 ERC721Enumerable.sol 导入并继承到 ERC721.sol 合约中时,我得到TypeError: Definition of base has to precede definition of derived contract 我尝试在自己的合同中导入 ERC721Enumerable.sol,但仍然出错。我还尝试导入较旧的 ERC721Full.sol 合同并将所有 pragma 0.5.0 更改为 pragma 0.8.0,但它像其他十几个合同一样继承并且更改所有这些合同似乎并不明智。我对 IERC721Enumerable.sol 进行了同样的尝试,仍然出现错误。有任何想法吗?任何帮助都会很棒!

第二部分。 ERC__ 和 IERC__ 有什么区别? IERC 合同的目的是什么?

谢谢!!

这是我的合同(我正在学习教程)。我导入常规的 ERC721 合约,继承它。当我测试和调用 totalSupply 函数时,它给了我一个错误,因为没有 totalSupply 函数:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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


contract Color is ERC721 {
    string[] public colors;
    mapping(string => bool) _colorExists;

    constructor() ERC721("Color", "COLOR")  {
    }

    function mint(string memory _color) public {
        colors.push(_color);
        uint _id = colors.length;
        _mint(msg.sender, _id);
        _colorExists[_color] = true;

    }
}

我的测试脚本:

const Color = artifacts.require('./Color.sol')

require('chai')
    .use(require('chai-as-promised'))
    .should()

contract('Color', (accounts) => {
    let contract

    before(async () => {
        contract = await Color.deployed()
    })

    describe('deployment', async () => {
        it('deploys successfully', async () => {
            contract = await Color.deployed()
            const address = contract.address
            console.log(address)
            assert.notEqual(address, 0x0)
            assert.notEqual(address,'')
            assert.notEqual(address, null)
            assert.notEqual(address, undefined)


        })
        it('has a name', async () => {
            const name = await contract.name()
            assert.equal(name, 'Color')

        })
        it('has a symbol', async () => {
            const symbol = await contract.symbol()
            assert.equal(symbol, 'COLOR')

        })
    })

    describe('minting', async () => {
        it('creates a new token', async () => {
            const result = await contract.mint('#00CD22')
            const totalSupply = await contract.totalSupply()

            // SUCCESS
            asert.equal(totalSupply, 1)
        })
    })
})

this is my error without the enumerable contract/without totalSupply

如果你愿意,我可以粘贴 openzeppelin 合约,或者链接它们here

I also tried this, importing ERC721Enumerable

And got this:

让我知道您需要更多信息! 提前致谢

【问题讨论】:

  • 请编辑您的问题并显示我们可以复制粘贴到 Remix(或任何 IDE)中的合约代码,它会抛出相同的错误。我无法找到可以仅从描述中模拟它的情况组合。
  • 更新了!谢谢
  • 我也遇到了同样的问题!我们如何使用@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol 合约?我们怎么称呼它?我正在尝试使用它的 totalSupply 函数。

标签: ethereum solidity smartcontracts openzeppelin nft


【解决方案1】:

第一部分

默认情况下,ERC721 没有 totalSupply 方法,这就是您收到错误的原因。 totalSupply 方法来自 IERC721Enumerable,它是标准 ERC721 的可选扩展,如 the documentation states。如果您希望您的 ERC721 可枚举,只需从 为您的派生合约的 openzeppelin 实现导入可枚举扩展,如下所示:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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


contract Color is ERC721Enumerable {
    string[] public colors;
    mapping(string => bool) _colorExists;

    constructor() ERC721("Color", "COLOR")  {
    }

    function mint(string memory _color) public {
        colors.push(_color);
        uint _id = colors.length;
        _mint(msg.sender, _id);
        _colorExists[_color] = true;

    }
}

编译器在尝试导入 ERC721Enumerable 时给您错误的原因是您试图在 Openzeppelin ERC721 实现中导入它,但该合约必须在 ERC721Enumerable 之前存在。换句话说,继承链是

ERC721 <-- ERC721Enumerable

你想要做的是

ERC721 <-- ERC721Enumerable
   |_____________↑

Wich 创建了一个无法满足的循环依赖。

第二部分

ERC 合约就像每种 OOP 编程语言中的抽象类(首先想到的可能是 Java 和 C++),而 IERC 是接口;这意味着虽然两者都不能直接实例化(它们都需要孩子来实现某些东西),但 ERC 合约为相应的 IERC 方法提供了标准实现。这就是您经常看到合约执行 ERC 合约而不是 IERC 合约的原因。

【讨论】:

    【解决方案2】:

    要使用 ERC271Enumerable 扩展,您需要实现它并覆盖 ERC271、_beforeTokenTransfersupportsInterface 的一些功能。

    // SPDX-License-Identifier: MIT    
    pragma solidity ^0.8.0;
        
    import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
    import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
    
    contract Color is ERC721, ERC721Enumerable{
    
      string[] public colors;
      mapping(string => bool) _colorExists;
    
      constructor () ERC721("Color", "COLORS") {}
    
      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);
      }
    
      function mint(string memory _color) public{
        colors.push(_color);
        uint _id = colors.length;
        _mint(msg.sender, _id);
        _colorExists[_color] = true;
      }
    }
    

    ERC__和IERC__有什么区别? IERC 合同的目的是什么?

    • IERC 是代币合约的接口。
    • ERC 是代币合约的实现。

    重要的是确保合约实现具有正确的方法、正确的可见性、参数和返回值。

    【讨论】:

      猜你喜欢
      • 2021-10-06
      • 2021-10-06
      • 2022-11-07
      • 2022-08-22
      • 2022-10-21
      • 2021-10-08
      • 2022-11-11
      • 2022-08-11
      • 2022-06-25
      相关资源
      最近更新 更多