为什么ERC721的铸币功能有权限控制?

Why does the minting function of ERC721 have an access control?

我看到的大多数使用 Open Zeppelin 的 ERC721 示例都要求 mint 函数具有访问控制,其中只允许合约所有者调用该函数。对于 example

function mint(address to) public virtual {
    require(hasRole(MINTER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have minter role to mint");

    _mint(to, _tokenIdTracker.current());
    _tokenIdTracker.increment();
}

或以下使用 Ownable 库。

function mint(address receiver) external onlyOwner returns (uint256) {
    _tokenIds.increment();

    uint256 newTokenId = _tokenIds.current();
    _mint(receiver, newTokenId);

    return newTokenId;
}

这是否意味着每次铸造新代币时都必须部署新合约?这不仅在 gas 费用方面似乎过高,而且 ERC721 合约有 properties 用于映射不同的所有者和代币:

// Mapping from token ID to owner address
mapping (uint256 => address) private _owners;

// Mapping owner address to token count
mapping (address => uint256) private _balances;

如果铸造仅限于合约所有者,这就没有意义了。

对我来说,部署单个 ERC721 contract(及其依赖项)并让用户调用 mint 函数更有意义。 ERC721的铸币功能最佳实践是什么?

ERC-721 标准没有定义铸造新代币的“最佳”或“正确”方式(例如它是否应该开放或受限),这取决于每个合约开发者实施或省略铸币功能以反映他们需求的方式。

Creating of NFTs ("minting") and destruction NFTs ("burning") is not included in the specification. Your contract may implement these by other means. Please see the event documentation for your responsibilities when creating or destroying NFTs.

但是拥有授权铸造新代币的地址白名单(例如 MINTER_ROLEonlyOwner)似乎比允许任何人自由铸造新代币更常见。


尽管理论上可以在每次铸造新代币时部署新合约,但这不是标准方法(我个人还没有看到任何合约这样做)。在大多数情况下,铸造过程“只是”创建一个新 ID,存储一个与 ID 关联的新 string/URL 值,将这个新代币与所有者地址(代币的,而不是合约所有者)相关联,并更新一些元数据,例如地址拥有的代币数量(参见下面的示例)。

令牌所有者然后可以转移他们的令牌,让任何人控制他们的令牌,并根据合同实施做其他事情。

您在问题中指出的映射(_owners_balances)表明它们存储代币所有者(而非合约所有者)地址以及每个地址持有的代币数量。

示例:

  1. 合约所有者将代币 ID 1 铸造到地址 0x123.

    • _owners[1] 的值为 0x123(原为 0,默认值)

    • _balances[0x123] 的值变为 1(原为 0,默认值)

  2. 合约所有者将代币 ID 2 铸造到地址 0x123.

    • _owners[1] 的值仍然是 0x123

    • _owners[2] 的值现在是 0x123(原为 0,默认值)

    • _balances[0x123] 的价值变为 2(因为他们现在拥有 2 个代币)