# 介绍ERC721A: 改进版的ERC721实现

By [MrDQ](https://paragraph.com/@0xmrdq) · 2022-01-07

---

太长不读
----

*   ERC721A是IERC721的一个实现方式，在一次交易中铸造多个NFT，可以大大节省Gas。
    
*   Azuki合约将使铸造多个NFT的成本**与铸造单个NFT的成本基本相同**。
    
*   我们与外部安全顾问（Caribou）合作，以确保我们的方法是合理的。
    
*   我们鼓励更广泛的社区采用这种实施方式，为他们的用户节省Gas成本。
    

背景介绍
----

以太坊的Gas价格几个月来一直居高不下，开发社区需要适应。当受欢迎的NFT项目开始铸造时，Gas价格飙升，导致整个生态系统为交易支付数百万的Gas费用。在Azuki，我们正在与我们的社区一起为metaverse建立一个品牌。开发团队的重点是优化我们的合约，使我们的社区在造币时尽可能少地花费Gas费。

我们没有使用OpenZeppelin流行的IERC721和IERC721Enumerable的默认实现，而是编写了我们的版本（在这篇文章的其余部分，我们将其称为ERC721A），并很高兴地宣布，Azuki合约将能够以铸造单个NFT的相同Gas成本铸造多个NFT。

测算
--

我们已经测算了铸造的Gas成本和价格，比较了OpenZeppelin的ERC721Enumerable和ERC721A。在我们的测算中，使用了相同的应用级逻辑，唯一的区别是调用了\_safeMint函数。

![](https://storage.googleapis.com/papyrus_images/e23ab5862569a7ec0a62b825432512ff25e777dcc1821c13e6edcb24510c6bee.png)

以及假设300 Gwei 和 $3500/ETH 的**美元成本**。这些只是估算，很难预测铸造时的Gas和ETH价格（在撰写本文时目前为120 Gwei）。

![](https://storage.googleapis.com/papyrus_images/c2fb2f021dbdf1186fec4f0d2832fea80bdac812186aafcfb2102fb9f28bfd4a.png)

它是如何工作的？
--------

我们在下面详细介绍我们所做的三个主要优化。虽然我们努力使其尽可能清晰 - 但这篇文章的其余部分确实假定你对Solidity和OpenZeppelin的ERC721 / ERC721Enumerable实现有所了解。

> ### 优化1 - 从OpenZeppelin（OZ）的ERC721Enumerable中移除重复存储
> 
> 广泛使用的IERC721Enumerable的OZ实现包括每个代币元数据的冗余存储。这种非规范化的方法为读取功能进行了优化，但对写入功能来说成本很高，鉴于用户更不可能为读取功能付费，这并不理想。此外，我们的令牌从0开始连续编号的事实让我们从基本实现中移除一些冗余的存储。我们强烈建议所有新启动的项目，如果他们想获得大的胜利，就仔细检查这个文件。

> ### 优化2 - 根据每批铸造请求，而不是每个铸造的NFT，来更新持有者的余额
> 
> 假设Alice有2个代币，想再买5个。在Solidity中，更新一个存储值需要花费Gas。因此，如果我们在存储中跟踪Alice拥有多少代币，那么通过一次更新将Alice的持有量从2直接更新到7，而不是更新该值5次（每增加一个代币一次，从2到3，3到4，等等），会更便宜。
> 
> 虽然这是一个相对简单的概念，但NFT领域的绝大多数批量铸造机构还没有采用这个方法，因为OZ的默认实现不包括批量铸造的API，而且很容易从货架上抓取现有的解决方案，而不对其进行调整。我们强烈建议所有项目如果支持批量铸造，就考虑这个技巧。

> ### 优化3 - 每批铸造请求更新一次持有者数据，而不是每次铸造的NFT
> 
> 这在精神上与优化2相似。假设Alice想买3个代币 - #100、#101和#102代币。我们可以不把Alice作为所有者保存3次（每次都要花费我们的Gas），而是只保存一次所有者值，在语义上暗示Alice拥有所有这3个代币。
> 
> 怎么做？假设Alice铸造了100号、101号和102号代币，而Bob铸造了103号和104号代币。内部持有者跟踪器将看起来像这样:

![](https://storage.googleapis.com/papyrus_images/d330b0aa74bff41c2c98160d867c1bb909bcac1e4eb4da7317af008e24d2f9d8.png)

> 这里的关键是，如果我们想看谁拥有#102，我们不需要真的把Alice明确设置为#102的明确所有者来做。我们只需改变ownerOf函数来做以下事情：

![](https://storage.googleapis.com/papyrus_images/f32176aa2d5dcf74d0af34065fa96159a6bcfc63f500567d5b42f40d879a0989.png)

> 关键见解：如果我们改变它的实现，使其递减直到找到一个显式所有者集合，ownerOf仍然像预期那样工作。
> 
> 虽然这些延迟的所有者写入可能仍然发生在代币生命周期的后期，但我们仍然期望从整体上节省大量的净成本，因为这减少了在铸造时花费的Gas，从而减少了铸造的整个生态系统的集中Gas峰值的严重性。这种优化涉及到一些额外的逻辑，特别是当它涉及到转移时，但超出了本博客的范围。该合约将在铸造时间之前公开，开发人员将很乐意回答任何问题并进行讨论!

结语
--

我们有信心，铸造多个NFT的Gas成本比我们在该领域所见的任何东西都要低。我们的外部安全顾问（Caribou）已经审查了合同，以确保我们的方法是合理的，以便用户自信地享受这些Gas节省。所有的项目都应该努力将Gas负担降到最低，并尽可能地朝着社区的 O(1) 方向发展。我们鼓励该领域的其他项目在任何公开销售中采用ERC721A标准，这允许在一次交易中铸造多个NFT。关于合同的任何问题，无论是关于代码还是关于为你的项目实施它，请通过Twitter DMs联系 [@locationtba](https://twitter.com/locationtba) 或 [@2pmflow](https://twitter.com/2pmflow) 。

Azuki mint将开始于1月12日@ 10:00AM PST。到时见。

---

*Originally published on [MrDQ](https://paragraph.com/@0xmrdq/erc721a-erc721)*
