Blockchain 为什么ERC721的造币功能具有访问控制?

Blockchain 为什么ERC721的造币功能具有访问控制?,blockchain,ethereum,solidity,openzeppelin,nft,Blockchain,Ethereum,Solidity,Openzeppelin,Nft,我看到的大多数使用OpenZeppelin的ERC721示例都要求mint函数具有访问控制,其中只有合同所有者才允许调用该函数。因为 或使用库执行以下操作 这是否意味着每次创建新令牌时都必须部署新契约?这不仅在天然气费用方面显得过高,而且ERC721合同还规定了不同所有者和代币的映射: // Mapping from token ID to owner address mapping (uint256 => address) private _owners; // Mapping own

我看到的大多数使用OpenZeppelin的ERC721示例都要求mint函数具有访问控制,其中只有合同所有者才允许调用该函数。因为

或使用库执行以下操作

这是否意味着每次创建新令牌时都必须部署新契约?这不仅在天然气费用方面显得过高,而且ERC721合同还规定了不同所有者和代币的映射:

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

// Mapping owner address to token count
mapping (address => uint256) private _balances;
如果铸造仅限于合同所有人,这就没有意义了

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

该标准没有定义造币新代币的“最佳”或“正确”方式(如是否应开放或限制),而是由每个合同开发者以反映其需求的方式实施或省略造币功能

规范中不包括创建NFT(“铸造”)和销毁NFT(“燃烧”)。您的合同可以通过其他方式实施这些。创建或销毁NFT时,请参阅事件文档了解您的责任

但是拥有一个授权造币的地址白名单(例如
MINTER_角色
onlyOwner
)似乎比允许任何人自由造币更常见


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

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

您在问题中指出的映射(
\u所有者
\u余额
)表明它们存储令牌所有者(而非合同所有者)地址以及每个地址持有的令牌数量

例如:

  • 合同所有者将令牌ID
    1
    发送到地址
    0x123

    • \u所有者[1]
      的值为
      0x123
      (为0,默认值)

    • \u余额[0x123]
      的值变为
      1
      (为0,默认值)

  • 合同所有者将令牌ID
    2
    发送到地址
    0x123

    • \u所有者[1]
      的值仍然是
      0x123

    • \u所有者[2]
      的值现在是
      0x123
      (是0,默认值)

    • \u余额[0x123]
      的值变为
      2
      (因为它们现在拥有2个令牌)


  • 这里提到的ERC721合同是否只有在合同所有者为某些地址铸造代币时才有用?实际上,我正在寻找一种结构,用户可以在没有中心人物的情况下造币。如果我只是删除造币功能的访问控制并将其公开,是否存在任何安全缺陷?我只是想弄清楚访问限制的原因,因为我不确定它是否与传输或刻录令牌的访问控制一样重要。如果要打开minting功能,可以从
    mint()
    函数中删除授权。从安全性的角度来看,我只能考虑更高的达到ID max值的概率(如果您选择将其设置为
    uint8
    或一些“小”数据类型)和可能的整数溢出(如果您不使用Solidity 0.8+,或使用
    require
    /
    assert
    进行检查)。否则,它的安全级别与您只有授权地址的安全级别相同,因为它们在代码中也应被视为不受信任的地址(例如,不信任,但验证它们是否返回一些值,如果它们是合同)。
    function mint(address receiver) external onlyOwner returns (uint256) {
        _tokenIds.increment();
    
        uint256 newTokenId = _tokenIds.current();
        _mint(receiver, newTokenId);
    
        return newTokenId;
    }
    
    // Mapping from token ID to owner address
    mapping (uint256 => address) private _owners;
    
    // Mapping owner address to token count
    mapping (address => uint256) private _balances;