前言
在之前的2篇文章中,已经讲了一些关于ERC-721的基本概念,适用范围,以及ERC-721与ERC-20的区别。本文是针对ERC-721 NFTS (Non-Fungible Tokens)标准的翻译,将会更加详细与准确,由于文章篇幅较长,所以分为上、下2部分来讲解,本文为下半部分。由于本人水平有限,如有错误,欢迎大家指正。
原文链接https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
警告说明(Caveats)
0.4.20版本的 Solidity 接口语法还不能很好的表诉ERC-721标准。通过ERC-721标准编译的合约必须遵守如下规则:
Solidity issue #3412:以上接口包含每个函数的显示可变性保障。可变性保障从弱到强依次为:payable, implicit nonpayable, view, pure。你的实现方法必须满足这个接口中的可变性保证,并且你应该尽可能满足一个更强的保证。例如,这个接口中的payable函数可以实现为您合约中的nonpayble(没有指定状态可变形)。我们预计以后的Solidity版本将会允许你的更严格的合约继承这个接口。但是在0.4.20版本中,变通的解决方案是你可以编辑这个接口,以在继承合约之前,来添加更严格的可变性。
Solidity issue #3419:实现了ERC721Metadata 或者ERC721Enumerable的合约也应该实现ERC721。ERC-721实现了ERC-165.接口的要求。
Solidity issue #2330:如果一个函数在本规范中显示为外部(external)函数,如果合约使用了public可见性,那它是符合规定的。作为0.4.20版本的解决方案,你可以在继承合约之前,编辑这个接口以切换为public状态
Solidity issues #3494, #3544: 在Solidity中使用
this.*.selector
会背标记为警告,将来版本的Solidity 不会将其标记为error
。
如果新版本的Solidity允许以代码表示注意事项,那这个EIP可能会更新,并删除警告,这样将等同于原始规范。
Rationale
这里有大量的计划,用以太坊智能合约来追踪可区分的资产。已经存在的或者计划的NFTs的例子有Decentraland的LAND
,CryptoPunks中著名的punks
,以及使用 DMarket 或 EnjinCoin系统的游戏内物品。将来的使用包括追踪现实世界中的资产,像房地产( 像Ubitquity 或者 Propy这样的公司设想的)。在这些案例中,这些项目在分类账目中不是集中在一起的数字,而是每个资产都必须拥有其所有权并进行原子追踪。不管这些资产是什么种类,如果我们有一个跨职能资产管理和销售平台的标准的接口,生态系统将更加强大。
"NFT"-世界的选择
"NFT"
几乎可以满足所有受访者的需求,并且广泛适用于可区分的数字资产。我们意识到“(deed)契约”对于本标准的某些应用(特别是物理性质)是非常具有描述性的。
可供选择的方案:可区分的资产,所有权,token,资产,股权,票证。
NFT 标识符
每个NFT都由ERC-721 智能合约中唯一的uint256
ID标识。这个标识符号码在合约期限内不会改变。这一对(合约地址,uint256 tokenId)将成为以太坊链上特定资产的全球唯一且完全合格的标识符。尽管一些ERC-721智能合约会发现从 ID 0 开始,并且对每个新的NFT,简单的增加1是便利的,然而调用者不应该假定ID具有任何固定模式给他们,并且必须将ID视为黑匣子。另外注意:NFTs可能会失效(被销毁)。请参考枚举接口的枚举函数。
uint256
的选择允许各种各样的应用程序,因为UUIDs 和 sha3哈希可以直接转化为uint256
。
交易机制(Transfer Mechanism)
ERC-721标准化了一个安全的交易函数safeTransferFrom
以及一个不太安全的函数transferFrom
。交易可能会按如下初始化:
NFT的所有权
NFT的 核准地址(经过检验的地址)
NFT当前所有者的授权操作
另外,授权的操作者可以为NFT设置批准的地址。这为钱包、经纪人和拍卖应用程序提供了一套强大的工具来快速使用NFTs。
transfer
和 accept
函数的文档仅指定事物必须抛出的条件。你的实现也可能会抛出其它一些情形。这使得实现可以实现一些有趣的结果:
如果合约停止,禁止交易—现有技术,加密猫(CryptoKitties)已部署合约,第611行。
接收NFTs的一些黑名单地址— 现有技术,加密猫(CryptoKitties)已部署合约,第565、566行。
不允许不安全的交易 —除非
_to
等于msg.sender
或者countOf(_to)
是非零或者以前是非零(因为这种情况是安全的),否则transferFrom
会抛出异常向交易双方收取费用 —如果以前是零地址,当调用
approve
(用非零参数_approved
)需要支付费用;如果以前是非零地址,以零地址的形式调用approve
,当调用任何transfer
函数时,都需要支付费用,要求transfer
参数_to
等于msg.sender
,要求transfer
参数_to
是NFT的批准地址。阅读NFT注册表—总是抛出
unsafeTransfer
,transferFrom
,approve
和setApprovalForAll
交易失败,将会引发ERC-223, ERC-677, ERC-827 和OpenZeppelin's 实现 of SafeERC20.sol中确定的最佳做法。ERC-20定义了一项允许功能,这在调用时引起了一个问题,之后又被修改为与OpenZeppelin issue #438不同的数量。在ERC-721中没有限制,因为每个NFT是唯一的,数量要么是0,要么是1。因此,我们可以获得ERC-20原创设计的好处,而不会遇到后来发现的问题。
在规范中不包含NFTs增发 ("minting") 和NFTs销毁("burning") 。你的合约可以通过其他方式来实现。参见或者销毁NFTs时,请查看文档以了解您的责任。
我们被问到在onERC721Received
的operator
参数是否是必要的。在所有的情况下,我们都可以想象,如果操作者是重要的,那么操作者可以将token卖给他们自己,然后发送它们--然后它们将成为from
地址。这看起来很麻烦,因为我们认为操作员是零时的token拥有者(并且转移给自己是多余的)。当操作员发送token时,操作员是自行采取行动,而不是按照token持有者的行为。这就是为什么操作员和以前的token拥有者对接收方来说事非常重要的。
可供选择的方案:对于ERC-20类型的交易,只允许2步,要求transfer
函数永远不会抛出异常,要求所有函数返回一个bool值来表示操作是否成功
ERC-165 接口
我们选择了标准的接口检测 (ERC-165)来展示ERC-721智能合约支持的接口。
未来的EIP可能会为合约创造一个全局的注册接口。我们强烈支持这样的EIP,并且它将允许ERC-721通过委托给一个单独的合约来实现ERC721Enumerable
, ERC721Metadata
或其它接口
Gas and Complexity (关于枚举扩展)
本规范考虑了管理几个和任意数量NFTs的实现。如果你的应用能够增长,那么请避免在代码中使用for/while循环(请参考CryptoKitties bounty issue #4)。这表明你的合约可能无法扩展并且gas
会无限制的增加。
我们已经在测试网络部署了一个合约XXXXERC721,它可以实例化并追踪340282366920938463463374607431768211456不同的行为(2^128)。这足以将每个IPV6地址分配给以太坊账户持有者,或者追踪纳米机器人的所有权,这种纳米机器人的大小只有几微米。你可以从区块链查询它。与查询ENS相比,每个功能花费的gas更少。
这个例子表明:ERC-721是标准规模。
可供选择的方案:如果需要for循环,则移除资产枚举函数,从枚举函数返回Solidity数组类型。
References
Standards
- ERC-20 Token Standard. https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
- ERC-165 Standard Interface Detection. https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
- ERC-173 Owned Standard. https://github.com/ethereum/EIPs/issues/173
- ERC-223 Token Standard. https://github.com/ethereum/EIPs/issues/223
- ERC-677
transferAndCall
Token Standard. https://github.com/ethereum/EIPs/issues/677 - ERC-827 Token Standard. https://github.com/ethereum/EIPs/issues/827
- Ethereum Name Service (ENS). https://ens.domains
- Instagram -- What's the Image Resolution? https://help.instagram.com/1631821640426723
- JSON Schema. http://json-schema.org/
- Multiaddr. https://github.com/multiformats/multiaddr
- RFC 2119 Key words for use in RFCs to Indicate Requirement Levels. https://www.ietf.org/rfc/rfc2119.txt
Issues
- The Original ERC-721 Issue. https://github.com/ethereum/eips/issues/721
- Solidity Issue #2330 -- Interface Functions are Axternal. https://github.com/ethereum/solidity/issues/2330
- Solidity Issue #3412 -- Implement Interface: Allow Stricter Mutability. https://github.com/ethereum/solidity/issues/3412
- Solidity Issue #3419 -- Interfaces Can't Inherit. https://github.com/ethereum/solidity/issues/3419
- Solidity Issue #3494 -- Compiler Incorrectly Reasons About the
selector
Function. https://github.com/ethereum/solidity/issues/3494 - Solidity Issue #3544 -- Cannot Calculate Selector of Function Named
transfer
. https://github.com/ethereum/solidity/issues/3544 - CryptoKitties Bounty Issue #4 -- Listing all Kitties Owned by a User is
O(n^2)
. https://github.com/axiomzen/cryptokitties-bounty/issues/4 - OpenZeppelin Issue #438 -- Implementation of
approve
method violates ERC20 standard. https://github.com/OpenZeppelin/zeppelin-solidity/issues/438 - Solidity DelegateCallReturnValue Bug. http://solidity.readthedocs.io/en/develop/bugs.html#DelegateCallReturnValue
Discussions
- Reddit (announcement of first live discussion). https://www.reddit.com/r/ethereum/comments/7r2ena/friday_119_live_discussion_on_erc_nonfungible/
- Gitter #EIPs (announcement of first live discussion). https://gitter.im/ethereum/EIPs?at=5a5f823fb48e8c3566f0a5e7
- ERC-721 (announcement of first live discussion). https://github.com/ethereum/eips/issues/721#issuecomment-358369377
- ETHDenver 2018. https://ethdenver.com
NFT Implementations and Other Projects
- CryptoKitties. https://www.cryptokitties.co
- 0xcert ERC-721 Token. https://github.com/0xcert/ethereum-erc721
- Su Squares. https://tenthousandsu.com
- Decentraland. https://decentraland.org
- CryptoPunks. https://www.larvalabs.com/cryptopunks
- DMarket. https://www.dmarket.io
- Enjin Coin. https://enjincoin.io
- Ubitquity. https://www.ubitquity.io
- Propy. https://tokensale.propy.com
- CryptoKitties Deployed Contract. https://etherscan.io/address/0x06012c8cf97bead5deae237070f9587f8e7a266d#code
- Su Squares Bug Bounty Program. https://github.com/fulldecent/su-squares-bounty
- XXXXERC721. https://github.com/fulldecent/erc721-example
- ERC721ExampleDeed. https://github.com/nastassiasachs/ERC721ExampleDeed
- Curio Cards. https://mycuriocards.com
- Rare Pepe. https://rarepepewallet.com
- Auctionhouse Asset Interface. https://github.com/dob/auctionhouse/blob/master/contracts/Asset.sol
- OpenZeppelin SafeERC20.sol Implementation. https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/ERC20/SafeERC20.sol