【源码解读】你买的 NFT 到底是什么?

帖子 未结 0 8701
w012h6aaz
w012h6aaz LV1 2022年10月22日 11:36 发表
<section id="nice" style="font-size: 16px; padding-right: 10px; padding-left: 10px; word-break: break-word; overflow-wrap: break-word; line-height: 1.25; font-family: Optima-Regular, Optima, PingFangTC-Light, PingFangSC-light, PingFangTC-light; letter-spacing: 2px; background-image: linear-gradient(90deg, rgba(50, 0, 0, 0.05) 3%, rgba(0, 0, 0, 0) 3%), linear-gradient(360deg, rgba(50, 0, 0, 0.05) 3%, rgba(0, 0, 0, 0) 3%); background-size: 20px 20px; background-position: center center;"><h2 style="font-weight: bold; font-size: 22px; margin-top: 20px; margin-right: 10px; margin-bottom: 0px;"><span style="display: none;"></span><span style="font-size: 18px; display: inline-block; padding-left: 10px; border-left: 5px solid rgb(145, 109, 213);">【源码解读】你买的 NFT 到底是什么?</span></h2> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「内容概要」</strong></p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">如果你是 WEB3 加密界的新手,面对众多概念无从入手,那么欢迎你,来对地方了!!</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">本文围绕标准 &nbsp;ERC721 协议,描述了 Mint、&nbsp;safeMint、&nbsp;transfer 等是如何实现资产管理的,并通过解读代码来了解它的安全性设计和以太坊数据上链成本构成。</p> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;"><strong style="color: rgb(145, 109, 213);">「目录大纲」</strong></span><span style="display: none;"></span></h3> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;">1.所谓 NFT 资产是什么?</span><span style="display: none;"></span></h3> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;">2.Mint 和 safeMint 的差别</span><span style="display: none;"></span></h3> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;">3.交易时会发生什么?有哪些细节设计</span><span style="display: none;"></span></h3> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;">4.NFT 哪些数据也存储在链上?</span><span style="display: none;"></span></h3> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;">5.以太坊上存储有多贵?</span><span style="display: none;"></span></h3> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「面向对象」</strong></p> <ul style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; font-size: 15px; list-style-type: circle;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; word-spacing: 2px;">Web3 新手,有无技术背景均可:</p> <ul style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; font-size: 15px; list-style-type: square;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; word-spacing: 2px;">研发——可无障碍阅读,理解精美的合约设计</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; word-spacing: 2px;">非研发——可能读不懂列举的代码,但能体会标准协议的设计思路</p> </section></li></ul> </section></li></ul> <hr style="margin-top: 10px; margin-bottom: 10px; border-right-width: initial; border-bottom-width: initial; border-left-width: initial; border-style: solid none none; border-top-width: 2px; border-top-color: rgb(217, 184, 250);"> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「正文」</strong></p> <h2 style="font-weight: bold; font-size: 22px; margin-top: 20px; margin-right: 10px; margin-bottom: 0px;"><span style="display: none;"></span><span style="font-size: 18px; display: inline-block; padding-left: 10px; border-left: 5px solid rgb(145, 109, 213);"><strong style="color: rgb(145, 109, 213);">「1.所谓 NFT 资产是什么?」</strong></span></h2> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">在 opensea 上,可看到每个 NFT 都有个唯一的编号。</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">比如 azuki 系列中第 4132 号,在页面的 Details 栏目可以看到其合约地址,ID 编号,部署所在公链等信息,而 Properties 栏目则是其设定的具备各种属性,对应的稀有度(非 azuki 本身携带,而是 opensea 整合计算的)。</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「1.1 资产在标准 ERC721 协议里是什么?」</strong></p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">而咱们回顾到源代码(此处取 ERC721 标准库 openzepplin 代码),会发现程序记录了全局性的两个字典类型的变量,通过 &nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">_owners</code><strong style="color: rgb(145, 109, 213);">「中用数字映射地址的方式记录每一个」</strong><code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">ID</code><strong style="color: rgb(145, 109, 213);">「当前对应的所有者,同时也附带用」</strong><code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">_balances</code>**记录了当前所有者总计持有的 NFT 数量</p> <pre><code style="overflow-x: auto; padding: 16px; color: rgb(171, 178, 191); background: rgb(40, 44, 52); display: -webkit-box; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; border-radius: 0px;">mapping(uint256&nbsp;=&gt;&nbsp;address)&nbsp;private&nbsp;_owners;<br></code></pre> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">并且由于 ERC721 创新性的赋予了一个 ID 对应地址的变量 &nbsp;<strong style="color: rgb(145, 109, 213);">「<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">_owners</code>」</strong>,从而与 ERC20 仅**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">_balances</code>**进行地址与余额的管理,区分出了 FT(同质化)与 NFT(非同质化)的差别。</p> <h2 style="font-weight: bold; font-size: 22px; margin-top: 20px; margin-right: 10px; margin-bottom: 0px;"><span style="display: none;"></span><span style="font-size: 18px; display: inline-block; padding-left: 10px; border-left: 5px solid rgb(145, 109, 213);"><strong style="color: rgb(145, 109, 213);">「2.Mint 和 safeMint 的差别」</strong></span></h2> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;"><strong style="color: rgb(145, 109, 213);">「2.1&nbsp;**」</strong><code>Mint</code>*<strong style="color: rgb(145, 109, 213);">「*是如何进行的」</strong></span><span style="display: none;"></span></h3> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Mint</code>**意思为铸造,即每个 NFT 的创造过程,例如之前的</p> <blockquote style="border-top: none; border-right: none; border-bottom: none; border-image: initial; font-size: 0.9em; overflow: auto; border-left-width: 3px; color: rgb(106, 115, 125); padding-top: 10px; padding-bottom: 10px; padding-left: 20px; margin-bottom: 20px; margin-top: 20px; border-left-color: rgb(216, 156, 246); background: rgb(244, 238, 255);"> <p style="padding-top: 8px; padding-bottom: 8px; font-size: 14px; word-spacing: 2px; margin-top: 0px; margin-bottom: 0px; color: black; line-height: 26px;">爱死机 NFT</p> <p style="padding-top: 8px; padding-bottom: 8px; font-size: 14px; word-spacing: 2px; margin-top: 0px; margin-bottom: 0px; color: black; line-height: 26px;">十四君,公众号:十四君<a href="" style="overflow-wrap: break-word; color: rgb(145, 109, 213); font-weight: bolder; border-bottom: 1px solid rgb(145, 109, 213);">当奈飞的 NFT 忘记了 web2 的业务安全</a></p> </blockquote> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Mint</code>&nbsp;**获取到该 NFT 的资产证明。</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">从源代码中可以看到,**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Mint</code>**主要是进行了安全判断:</p> <ul style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; font-size: 15px; list-style-type: circle;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; word-spacing: 2px;">判断 1:确保转入的不是<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">0x00</code>地址(黑洞地址无法转出,转入则资产损失)</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; word-spacing: 2px;">判断 2:确保此交易所操作的<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">NFTID</code>是不存在的</p> </section></li></ul> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">最终代码执行的操作是:</p> <ul style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; font-size: 15px; list-style-type: circle;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; word-spacing: 2px;">操作 1:将转入地址的<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">_balances</code>&nbsp; 所持有总数加 1</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; word-spacing: 2px;">操作 2:将对应 &nbsp;<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">NFTID</code>&nbsp; 的所有者修改为转入的地址</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; word-spacing: 2px;">操作 3:完成交易则发出<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">emit</code>&nbsp; 事件,可以让链下监听到这次交易的数据</p> </section></li></ul> <pre><code style="overflow-x: auto; padding: 16px; color: rgb(171, 178, 191); background: rgb(40, 44, 52); display: -webkit-box; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; border-radius: 0px;">/**<br>&nbsp;*&nbsp;@dev&nbsp;Mints&nbsp;`tokenId`&nbsp;and&nbsp;transfers&nbsp;it&nbsp;to&nbsp;`to`.<br>&nbsp;*&nbsp;Emits&nbsp;a&nbsp;{Transfer}&nbsp;event.<br>&nbsp;*/<br><span style="color: #c678dd; line-height: 26px;">function</span>&nbsp;_mint(address&nbsp;to,&nbsp;uint256&nbsp;tokenId)&nbsp;internal&nbsp;virtual&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;require(to&nbsp;!=&nbsp;address(0),&nbsp;<span style="color: #98c379; line-height: 26px;">"ERC721:&nbsp;mint&nbsp;to&nbsp;the&nbsp;zero&nbsp;address"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;require(!_exists(tokenId),&nbsp;<span style="color: #98c379; line-height: 26px;">"ERC721:&nbsp;token&nbsp;already&nbsp;minted"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;_beforeTokenTransfer(address(0),&nbsp;to,&nbsp;tokenId);<br>&nbsp;&nbsp;&nbsp;&nbsp;_balances[to]&nbsp;+=&nbsp;1;<br>&nbsp;&nbsp;&nbsp;&nbsp;_owners[tokenId]&nbsp;=&nbsp;to;<br>&nbsp;&nbsp;&nbsp;&nbsp;emit&nbsp;Transfer(address(0),&nbsp;to,&nbsp;tokenId);<br>&nbsp;&nbsp;&nbsp;&nbsp;_afterTokenTransfer(address(0),&nbsp;to,&nbsp;tokenId);<br>}<br></code></pre> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">中间有 &nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">_beforeTokenTransfer</code>**和 &nbsp;&nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">_afterTokenTransfer</code>**属于虚函数,作为标准,是让项目方可以在不修改标准协议的情况下增加一些特定的逻辑代码用的。</p> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"></h3> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;"><strong style="color: rgb(145, 109, 213);">「2.2 为何**」</strong><code>safeMint</code>更安全**</span><span style="display: none;"></span></h3> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;"><code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">safeMint</code>&nbsp; 意为安全的铸造,从代码实现中可以看到他本身也是调用了<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Mint</code>但是他额外增加了 &nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">_checkOnERC721Received</code>**的判断,这点是属于 &nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">ERC165</code>**的标准,相当于在完成转入操作后,则判断对方地址,是否是黑洞地址(即无法发起交易 NFT 操作的地址)是防止转入对象为合约地址时候,其合约没有预设置好转出的函数,导致资产在内无法被转走,从而造成永久损失:</p> <pre><code style="overflow-x: auto; padding: 16px; color: rgb(171, 178, 191); background: rgb(40, 44, 52); display: -webkit-box; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; border-radius: 0px;">/**<br>&nbsp;*&nbsp;@dev&nbsp;Same&nbsp;as&nbsp;{xref-ERC721-_safeMint-address-uint256-}[`_safeMint`],&nbsp;with&nbsp;an&nbsp;additional&nbsp;`data`&nbsp;parameter&nbsp;<span style="color: #e6c07b; line-height: 26px;">which</span>&nbsp;is<br>&nbsp;*&nbsp;forwarded&nbsp;<span style="color: #c678dd; line-height: 26px;">in</span>&nbsp;{IERC721Receiver-onERC721Received}&nbsp;to&nbsp;contract&nbsp;recipients.<br>&nbsp;*/<br><span style="color: #c678dd; line-height: 26px;">function</span>&nbsp;_safeMint(address&nbsp;to,uint256&nbsp;tokenId,bytes&nbsp;memory&nbsp;_data)<br>&nbsp;&nbsp;&nbsp;&nbsp;internal&nbsp;virtual&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;_mint(to,&nbsp;tokenId);<br>&nbsp;&nbsp;&nbsp;&nbsp;require(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_checkOnERC721Received(address(0),&nbsp;to,&nbsp;tokenId,&nbsp;_data),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #98c379; line-height: 26px;">"ERC721:&nbsp;transfer&nbsp;to&nbsp;non&nbsp;ERC721Receiver&nbsp;implementer"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;);<br>}<br></code></pre> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;"><strong style="color: rgb(145, 109, 213);">「2.3&nbsp;**」</strong><code>ERC165</code>是如何防止资产转入黑洞的?**</span><span style="display: none;"></span></h3> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">_设计初衷可见:&nbsp;_https://eips.ethereum.org/EIPS/eip-165__</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">是让合约接口标准化的提案,在编程语法中**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">interface</code>**是接口的意思,在其中定义的函数可以不实现仅仅放上函数名字相关参数,在程序复杂的时候,相当于目录一般告诉别人我都有什么功能。但是接口的写法各有千秋,名字定义参数类型,甚至是否存在都有不同,所以此提案最终形成了 ERC165 标准,规范了接口的识别规则:</p> <pre><code style="overflow-x: auto; padding: 16px; color: rgb(171, 178, 191); background: rgb(40, 44, 52); display: -webkit-box; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; border-radius: 0px;"><br>interface&nbsp;ERC165&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;///&nbsp;@notice&nbsp;查询合约所实现的接口<br>&nbsp;&nbsp;&nbsp;&nbsp;///&nbsp;@param&nbsp;interfaceID&nbsp;&nbsp;参数:接口ID<br>&nbsp;&nbsp;&nbsp;&nbsp;///&nbsp;@<span style="color: #e6c07b; line-height: 26px;">return</span>&nbsp;<span style="color: #56b6c2; line-height: 26px;">true</span>&nbsp;如果函数实现了&nbsp;interfaceID&nbsp;(interfaceID&nbsp;不为&nbsp;0xffffffff&nbsp;)返回<span style="color: #56b6c2; line-height: 26px;">true</span>,&nbsp;否则为&nbsp;<span style="color: #56b6c2; line-height: 26px;">false</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd; line-height: 26px;">function</span>&nbsp;supportsInterface(bytes4&nbsp;interfaceID)&nbsp;external&nbsp;view&nbsp;returns&nbsp;(bool);<br>}<br></code></pre> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">使用流程是:</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">STEP 1&nbsp; 判断是否存在 &nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">supportsInterface</code>**函数,并且其符合 165 标准</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">STEP&nbsp;2 通过 &nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">supportsInterface</code>**函数,判断是否具有转出 NFT 的函数</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;"><span style="color: rgb(145, 109, 213);">(PS:让合约具备 NFT 接收转出功能,可通过引入 &nbsp;<strong>「<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">IERC721Receiver.sol</code>」</strong>__&nbsp; 拓展包来实现)</span></p> <h2 style="font-weight: bold; font-size: 22px; margin-top: 20px; margin-right: 10px; margin-bottom: 0px;"><span style="display: none;"></span><span style="font-size: 18px; display: inline-block; padding-left: 10px; border-left: 5px solid rgb(145, 109, 213);"><strong style="color: rgb(145, 109, 213);">「3.交易时会发生什么?有哪些细节?」</strong></span></h2> <h2 style="font-weight: bold; font-size: 22px; margin-top: 20px; margin-right: 10px; margin-bottom: 0px;"><span style="display: none;"></span><span style="font-size: 18px; display: inline-block; padding-left: 10px; border-left: 5px solid rgb(145, 109, 213);">标准协议设计有两种转移方式,**<code>transfer</code>&nbsp;**和 &nbsp;**<code>**`transferFrom`**,</code>**作用于两种场景:</span></h2> <ul style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; font-size: 15px; list-style-type: circle;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><h2 style="font-weight: bold; color: black; font-size: 22px; margin-top: 20px; margin-right: 10px; margin-bottom: 0px;"><span style="display: none;"></span><span style="font-size: 18px; display: inline-block; padding-left: 10px; border-left: 5px solid rgb(145, 109, 213);"><strong style="color: rgb(145, 109, 213);">「<code style="font-size: 14px; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">transfer</code>」</strong>&nbsp; 转移:由用户调用,将本消息发送的钱包所持有的 NFTID 转移到指定地址</span></h2> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><h2 style="font-weight: bold; color: black; font-size: 22px; margin-top: 20px; margin-right: 10px; margin-bottom: 0px;"><span style="display: none;"></span><span style="font-size: 18px; display: inline-block; padding-left: 10px; border-left: 5px solid rgb(145, 109, 213);"><strong style="color: rgb(145, 109, 213);">「<code style="font-size: 14px; overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">transferFrom</code>」</strong>&nbsp; 从转移:用某机构调用,需要用户先授权某地址,让其有权可转移</span></h2> </section></li></ul> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">类比一下:</p> <ul style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; font-size: 15px; list-style-type: circle;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;">**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">transfer</code>**就是现金交易,从自己口袋里拿钱支付</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><strong style="color: rgb(145, 109, 213);">「<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">transferFrom</code>」</strong>&nbsp; 就是扫码扣款,由店家申请扣款,受制于用户是否开通小额代扣权限</section></li></ul> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">接下来咱们从代码来看看,其中可能有会意想不到的细节。</p> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;"><strong style="color: rgb(145, 109, 213);">「3.1&nbsp;**」</strong><code>transfer</code>&nbsp; 是如何进行的**</span><span style="display: none;"></span></h3> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">他会检测当前交易的 &nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">from</code>**方是否是此<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">NFTID</code>的持有者,并且限制该 NFT 转入<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">0x00</code>地址。其次进行 &nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">from</code>**转出地址和 &nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">to</code>**转入地址的余额刷新,修改 &nbsp;<strong style="color: rgb(145, 109, 213);">「<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">_balances</code><strong>「全局变量并且重新设置」</strong><code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">_owners</code><strong>「此 NFTID 的所有者地址修改为」</strong><code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">to。</code>」</strong></p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「这里有个防护的细节会先执行」</strong><code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">_approve(address(0), tokenId)</code><strong style="color: rgb(145, 109, 213);">「**」</strong><code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">;</code>&nbsp; 清空历史授权,*<strong style="color: rgb(145, 109, 213);">「*如果没有这一步,则资产完成了转移,但是其 NFTID 的转移授权依旧在,细思极恐:」</strong></p> <pre><code style="overflow-x: auto; padding: 16px; color: rgb(171, 178, 191); background: rgb(40, 44, 52); display: -webkit-box; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; border-radius: 0px;"><br><span style="color: #c678dd; line-height: 26px;">function</span>&nbsp;_transfer(address&nbsp;from,address&nbsp;to,uint256&nbsp;tokenId)&nbsp;internal&nbsp;virtual&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require(ERC721.ownerOf(tokenId)&nbsp;==&nbsp;from,&nbsp;<span style="color: #98c379; line-height: 26px;">"ERC721:&nbsp;transfer&nbsp;from&nbsp;incorrect&nbsp;owner"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require(to&nbsp;!=&nbsp;address(0),&nbsp;<span style="color: #98c379; line-height: 26px;">"ERC721:&nbsp;transfer&nbsp;to&nbsp;the&nbsp;zero&nbsp;address"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_beforeTokenTransfer(from,&nbsp;to,&nbsp;tokenId);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_approve(address(0),&nbsp;tokenId);//&nbsp;Clear&nbsp;approvals&nbsp;from&nbsp;the&nbsp;previous&nbsp;owner<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_balances[from]&nbsp;-=&nbsp;1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_balances[to]&nbsp;+=&nbsp;1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_owners[tokenId]&nbsp;=&nbsp;to;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;emit&nbsp;Transfer(from,&nbsp;to,&nbsp;tokenId);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_afterTokenTransfer(from,&nbsp;to,&nbsp;tokenId);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></code></pre> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;"><strong style="color: rgb(145, 109, 213);">「3.2&nbsp;**」</strong><code>transferFrom</code>是如何进行的**</span><span style="display: none;"></span></h3> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">这里的交易本质调用的是 &nbsp;<strong style="color: rgb(145, 109, 213);">「<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">_safeTransfer</code>」</strong>&nbsp; 所以他的核心逻辑是 &nbsp;<strong style="color: rgb(145, 109, 213);">「<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">require</code><strong>「部分,这的一大细节是:」</strong><code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">_msgSender()</code>」</strong> 这是 &nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">openzepplin</code>**的标准库 &nbsp;**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Context.sol</code>**中的方法。</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">其实就是获取当前交易的发送者地址,但这里使用了封装版本,而不是直接使用**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">msg.sender</code>**是考虑到,可能存在一种交易类型<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">“元交易”</code>,即交易的付费 gas 方和交易发起方不相同的情况。</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">所以一些处于中间环节的,类似 library 的合约需要考虑这种特殊情况。其余部分判断是确定是否有授权记录,易于理解,不作赘述:</p> <pre><code style="overflow-x: auto; padding: 16px; color: rgb(171, 178, 191); background: rgb(40, 44, 52); display: -webkit-box; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; border-radius: 0px;"><span style="color: #c678dd; line-height: 26px;">function</span>&nbsp;safeTransferFrom(address&nbsp;from,address&nbsp;to,uint256&nbsp;tokenId,bytes&nbsp;memory&nbsp;_data)&nbsp;public&nbsp;virtual&nbsp;override&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require(_isApprovedOrOwner(_msgSender(),&nbsp;tokenId),&nbsp;<span style="color: #98c379; line-height: 26px;">"ERC721:&nbsp;transfer&nbsp;caller&nbsp;is&nbsp;not&nbsp;owner&nbsp;nor&nbsp;approved"</span>);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_safeTransfer(from,&nbsp;to,&nbsp;tokenId,&nbsp;_data);}<br></code></pre> <h2 style="font-weight: bold; font-size: 22px; margin-top: 20px; margin-right: 10px; margin-bottom: 0px;"></h2> <h2 style="font-weight: bold; font-size: 22px; margin-top: 20px; margin-right: 10px; margin-bottom: 0px;"><span style="display: none;"></span><span style="font-size: 18px; display: inline-block; padding-left: 10px; border-left: 5px solid rgb(145, 109, 213);"><strong style="color: rgb(145, 109, 213);">「4.NFT 哪些数据也存储在链上?」</strong></span></h2> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">交易的环节也看完后,其实很多新同学也顿感奇怪,原来我买的 NFT 只有一个 ID 的归属地址指向了我,从而达成了唯一性。那就算如此,稀有度信息放在哪里?我的 NFT 图像本身在哪里?</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">这就是涉及到 ERC721 的元数据拓展**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">IERC721Metadata.sol。</code>**要放什么都可以,但是项目方往往在链上只存储最基础的 ID+IPFS 的地址。</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">咱们可以通过之前**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Etherscan</code>**教程方法来看看一些项目数据有什么,<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">先取Azuki</code>上合约地址:</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「0xed5af388653567af2f388e6224dc7c4b3241c544」</strong></p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">再通过**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Read Contract</code>**可以查阅到,其元数据只存放了 ipfs 上的指向地址。而近期兴起的<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Metaverse</code>项目元宇宙土地 S<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">andbox</code>和<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Decentraland</code>&nbsp;,以及去年火热<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">的Axie Infinity</code>&nbsp;,基本链上存储元数据也只是 ID+网址:</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">像 mirror 那些是专门设计低费用可进行高存储,一个块常规都是 30M 起步,大约是以太坊的 1000 倍。</p> <h2 style="font-weight: bold; font-size: 22px; margin-top: 20px; margin-right: 10px; margin-bottom: 0px;"><span style="display: none;"></span><span style="font-size: 18px; display: inline-block; padding-left: 10px; border-left: 5px solid rgb(145, 109, 213);"><strong style="color: rgb(145, 109, 213);">「5.以太坊上存储有多贵?」</strong></span></h2> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">以下是本文稍难理解的地方。咱们从源码来分析链上存储的成本构成以及金额换算,成本产生将有 2 个方面,按执行流程来看:</p> <ul style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; font-size: 15px; list-style-type: circle;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;">用户发起一笔交易,将数据作为参数传入,其大小是一笔成本</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;">交易执行合约代码,依据修改和使用,EVM 计算消耗的 gas 成本</section></li></ul> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;"><strong style="color: rgb(145, 109, 213);">「5.1 交易发起的成本」</strong></span><span style="display: none;"></span></h3> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">咱们可以核对下以太坊黄皮书,里对交易数据大小所消耗 gas 有清晰的定义</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">可以看到交易所附带的参数的价格:</p> <ul style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; font-size: 15px; list-style-type: circle;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; word-spacing: 2px;">每笔交易都有 21000 GAS 需要支付</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; word-spacing: 2px;">为交易的每个非零字节数据或代码支付 68 GAS</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; word-spacing: 2px;">为交易的每个零字节数据或代码支付 4 GAS</p> </section></li></ul> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">所以如果是再 &nbsp;<strong style="color: rgb(145, 109, 213);">「<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; font-weight: bolder; background: none;">Mint</code>」</strong>&nbsp; 的时候,登记上若干 NFT 属性信息,交易的 data 部分会将 abc 等字符转成 2 个十六进制表示,而每个字符为一个八位二进制,等于一个 byte。所以可以约等于将 data 的长度除以 2 作为 byte 数。</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">而 1kb 的数据,如果都是非 0 的有信息量的文本信息,则等于增加是 68*1000=6.8W 的 gas 消耗。按<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">20gwei</code>的 gas 价格和<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">2000</code>的 eth 兑换美元价格,可以估算出,每上链 1kb 数据在交易发起端就要:</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;"><code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">20*(21000+68000)*1e9/1e18 * 2000 =</code>&nbsp;3.5 美金</p> <h3 style="margin-top: 30px; margin-bottom: 15px; font-size: 16px; font-weight: bold; text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;"><strong style="color: rgb(145, 109, 213);">「5.2 合约存储的成本」</strong></span><span style="display: none;"></span></h3> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">由于交易发起后,还有智能合约上存储的逻辑,咱们从以太坊 go 源代码中(<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">EIP1283</code>),来分析具体的消费量,代码具体在函数内,太长了不全粘来:</p> <pre><code style="overflow-x: auto; padding: 16px; color: rgb(171, 178, 191); background: rgb(40, 44, 52); display: -webkit-box; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; border-radius: 0px;">func&nbsp;gasSStore(evm&nbsp;*EVM,&nbsp;contract&nbsp;*Contract,&nbsp;stack&nbsp;*Stack,&nbsp;mem&nbsp;*Memory,&nbsp;memorySize&nbsp;uint64)&nbsp;(uint64,&nbsp;error)<br></code></pre> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">历史上 GAS 消耗的估算有经过若干迭代,如果是<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Petersburg</code>或者 <code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Constantinople</code> 未激活的话,则不按下面逻辑进行计算</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">gas 消耗计算,依赖 3 个种数据的管理形式(增删改)</p> <ul style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; font-size: 15px; list-style-type: circle;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;">从零值地址到非零值(NEW VALUE),每个存储槽需消耗 2Wgas</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;">从非零值地址到零值地址(DELETE),每个存储槽需消耗 5Kgas,但会有奖励 1.5W gas 退回</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1); font-size: 14px;">从非零到非零(CHANGE),每个存储槽需消耗 200 gas</section></li></ul> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「注意,上述每一个存储槽算**」</strong><code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">32byte</code>,1kb 存储则是 32 个存储槽。**<code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">Mint</code>&nbsp; 的过程是新增存储,所以如果新增 1kb 的数据存储在链上代价将是 64Wgas,换算成金额则是:</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;"><code style="overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin-right: 2px; margin-left: 2px; font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(145, 109, 213); font-weight: bolder; background: none;">20*(640000)*1e9/1e18 * 2000 =</code>&nbsp;25 美金</p> <p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; font-size: 14px; word-spacing: 2px;">真可谓寸土寸金!</p></section>
收藏(769)  分享
相关标签: 互联网 经济 科技 科学 科普 观察
0个回复
  • 消灭零回复