ERC-721: 非同质化代币标准
Authors | William Entriken (@fulldecent), Dieter Shirley <dete@axiomzen.co>, Jacob Evans <jacob@dekz.net>, Nastassia Sachs <nastassia.sachs@protonmail.com> |
---|---|
Created | 2018-01-24 |
Requires | EIP-165 |
简单概述
一种非同质化代币(non-fungible tokens),也称为所有权凭证的标准接口。
摘要
以下标准允许在智能合约中实现 NFT 的标准 API。此标准提供跟踪和转移 NFT 的基本功能。
我们考虑了 NFT 被个人拥有和交易,以及委托给第三方经纪人/钱包/拍卖商(”运营商”)的使用场景。NFT 可以代表对数字或物理资产的所有权。我们考虑了一个多样化的资产宇宙,并且我们知道您会设想出更多:
- 物理财产——房屋、独特的艺术品
- 虚拟收藏品——独特的猫咪图片、收藏卡
- “负价值”资产——贷款、负担和其他责任
一般来说,所有的房子都是不同的,没有两只小猫是相同的。NFT 是可区分的,您必须单独跟踪每个 NFT 的所有权。
动机
一个标准接口允许钱包/经纪人/拍卖应用程序与以太坊上的任何 NFT 一起工作。我们为简单的 ERC-721 智能合约以及跟踪任意数量 NFT 的合约提供支持。其他应用将在下面讨论。
这个标准受到了 ERC-20 代币标准的启发,并建立在 EIP-20 创建以来的两年经验之上。EIP-20 不足以跟踪 NFT,因为每个资产都是不同的(非同质化),而一定数量的代币是相同的(同质化)。
此标准与 EIP-20 之间的差异将在下面进行检查。
规范
本文档中的关键词“必须(MUST)”,“禁止(MUST NOT)”,“需要(REQUIRED)”,“应该(SHALL)”,“不应该(SHALL NOT)”,“推荐(SHOULD)”,“不推荐(SHOULD NOT)”,“可以(MAY)”和“可选(OPTIONAL)”应按照 RFC 2119 中的描述进行解释。
每个符合 ERC-721 标准的合约必须实现 ERC721
和 ERC165
接口(受以下“注意事项”的约束):
pragma solidity ^0.4.20;
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x80ac58cd.
interface ERC721 /* is ERC165 */ {
/// @dev 当任何 NFT 的所有权通过任何机制发生变化时,都会发出此事件。
/// 当创建 NFT(`from` == 0)和销毁 NFT(`to` == 0)时,会发出此事件。
/// 例外情况:在合约创建期间,可以创建和分配任意数量的 NFT,而无需发出 Transfer 事件。 在
/// 任何转移时,该 NFT 的批准地址(如果有)将重置为 none。
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
/// @dev 当 NFT 的批准地址更改或
/// 确认时,会发出此事件。零地址表示没有批准的地址。
/// 当发出 Transfer 事件时,这也表示该 NFT 的批准
/// 地址(如果有)将重置为 none。
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
/// @dev 当为所有者启用或禁用运营商时,会发出此事件。
/// 运营商可以管理所有者的所有 NFT。
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
/// @notice 计算分配给所有者的所有 NFT
/// @dev 分配给零地址的 NFT 被认为是无效的,并且此
/// 函数会抛出关于零地址的查询。
/// @param _owner 要查询余额的地址
/// @return `_owner`拥有的 NFT 数量,可能为零
function balanceOf(address _owner) external view returns (uint256);
/// @notice 查找 NFT 的所有者
/// @dev 分配给零地址的 NFT 被认为是无效的,并且关于
/// 它们的查询会抛出异常。
/// @param _tokenId NFT 的标识符
/// @return NFT 所有者的地址
function ownerOf(uint256 _tokenId) external view returns (address);
/// @notice 将 NFT 的所有权从一个地址转移到另一个地址
/// @dev 除非`msg.sender`是当前所有者、授权的
/// 运营商或此 NFT 的批准地址,否则会抛出异常。如果`_from`不是
/// 当前所有者,则抛出异常。如果`_to`是零地址,则抛出异常。如果
/// `_tokenId`不是有效的 NFT,则抛出异常。当转移完成后,此函数
/// 检查`_to`是否为智能合约(代码大小 > 0)。如果是,它会调用
/// `onERC721Received`在`_to`上,如果返回值不是
/// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`,则抛出异常。
/// @param _from NFT 的当前所有者
/// @param _to 新所有者
/// @param _tokenId 要转移的 NFT
/// @param data 没有指定格式的附加数据,在调用 `_to` 时发送
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
/// @notice 将 NFT 的所有权从一个地址转移到另一个地址
/// @dev 此函数的工作方式与具有额外数据参数的另一个函数完全相同,
/// 只是此函数将数据设置为 ""。
/// @param _from NFT 的当前所有者
/// @param _to 新所有者
/// @param _tokenId 要转移的 NFT
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
/// @notice 转移 NFT 的所有权 -- 调用者有责任
/// 确认`_to`能够接收 NFTS,否则
/// 它们可能会永久丢失
/// @dev 除非`msg.sender`是当前所有者、授权的
/// 运营商或此 NFT 的批准地址,否则会抛出异常。如果`_from`不是
/// 当前所有者,则抛出异常。如果`_to`是零地址,则抛出异常。如果
/// `_tokenId`不是有效的 NFT,则抛出异常。
/// @param _from NFT 的当前所有者
/// @param _to 新所有者
/// @param _tokenId 要转移的 NFT
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
/// @notice 更改或确认 NFT 的批准地址
/// @dev 零地址表示没有批准的地址。
/// 除非`msg.sender`是当前的 NFT 所有者,或者是当前的 NFT 所有者的授权
/// 运营商,否则会抛出异常。
/// @param _approved 新的批准 NFT 控制器
/// @param _tokenId 要批准的 NFT
function approve(address _approved, uint256 _tokenId) external payable;
/// @notice 启用或禁用第三方(“运营商”)管理
/// `msg.sender`的所有资产的批准
/// @dev 发出 ApprovalForAll 事件。合约必须允许
/// 每个所有者有多个运营商。
/// @param _operator 要添加到授权运营商集合的地址
/// @param _approved 如果运营商获得批准,则为 True,如果撤销批准,则为 False
function setApprovalForAll(address _operator, bool _approved) external;
/// @notice 获取单个 NFT 的批准地址
/// @dev 如果`_tokenId`不是有效的 NFT,则抛出异常。
/// @param _tokenId 要查找批准地址的 NFT
/// @return 此 NFT 的批准地址,如果没有,则为零地址
function getApproved(uint256 _tokenId) external view returns (address);
/// @notice 查询地址是否为另一个地址的授权运营商
/// @param _owner 拥有 NFT 的地址
/// @param _operator 代表所有者行事的地址
/// @return 如果`_operator`是`_owner`的批准运营商,则为 True,否则为 False
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
interface ERC165 {
/// @notice 查询合约是否实现了接口
/// @param interfaceID 接口标识符,如 ERC-165 中指定的
/// @dev 接口标识在 ERC-165 中指定。 此函数
/// 使用的 gas 小于 30,000。
/// @return 如果合约实现了`interfaceID`并且
/// `interfaceID`不是 0xffffffff,则为“true”,否则为“false”
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
如果钱包/经纪人/拍卖应用程序将接受安全转移,则必须实现钱包接口。
/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
interface ERC721TokenReceiver {
/// @notice 处理 NFT 的接收
/// @dev ERC721 智能合约在`transfer`之后在接收者上调用此函数
/// 。此函数可能会抛出以还原并拒绝
/// 转移。返回除魔术值以外的值必须导致
/// 交易被还原。
/// 注意:合约地址始终是消息发送者。
/// @param _operator 调用`safeTransferFrom`函数的地址
/// @param _from 先前拥有token的地址
/// @param _tokenId 正在转移的 NFT 标识符
/// @param _data 没有指定格式的附加数据
/// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
/// 除非抛出异常
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
}
对于 ERC-721 智能合约,元数据扩展是可选的(请参阅下面的“注意事项”)。 这允许查询您的智能合约的名称以及您的 NFT 所代表的资产的详细信息。
/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x5b5e139f.
interface ERC721Metadata /* is ERC721 */ {
/// @notice 此合约中 NFT 集合的描述性名称
function name() external view returns (string _name);
/// @notice 此合约中 NFT 的缩写名称
function symbol() external view returns (string _symbol);
/// @notice 给定资产的独特统一资源标识符 (URI)。
/// @dev 如果`_tokenId`不是有效的 NFT,则抛出异常。 URI 在 RFC 中定义
/// 3986。URI 可以指向符合“ERC721
/// 元数据 JSON 模式”。
function tokenURI(uint256 _tokenId) external view returns (string);
}
这是上面引用的“ERC721 元数据 JSON 模式”。
{
"title": "资产元数据",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "标识此 NFT 所代表的资产"
},
"description": {
"type": "string",
"description": "描述此 NFT 所代表的资产"
},
"image": {
"type": "string",
"description": "指向具有 mime 类型 image/* 的资源的 URI,该资源表示此 NFT 所代表的资产。 考虑制作宽度在 320 到 1080 像素之间且纵横比在 1.91:1 到 4:5 之间的任何图像。"
}
}
}
对于 ERC-721 智能合约,枚举扩展是可选的(请参阅下面的“注意事项”)。 这允许您的合约发布其完整的 NFT 列表并使其可被发现。
/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x780e9d63.
interface ERC721Enumerable /* is ERC721 */ {
/// @notice 计算此合约跟踪的 NFT
/// @return 此合约跟踪的有效 NFT 的计数,其中每个 NFT
/// 都具有已分配且可查询的所有者,该所有者不等于零地址
function totalSupply() external view returns (uint256);
/// @notice 枚举有效的 NFT
/// @dev 如果`_index` >= `totalSupply()`,则抛出异常。
/// @param _index 小于`totalSupply()`的计数器
/// @return `_index`th NFT 的 token 标识符,
/// (未指定排序顺序)
function tokenByIndex(uint256 _index) external view returns (uint256);
/// @notice 枚举分配给所有者的 NFT
/// @dev 如果`_index` >= `balanceOf(_owner)`或如果
/// `_owner`是零地址,表示无效的 NFT,则抛出异常。
/// @param _owner 我们感兴趣于他们拥有的 NFT 的地址
/// @param _index 小于`balanceOf(_owner)`的计数器
/// @return 分配给`_owner`的`_index`th NFT 的 token 标识符,
/// (未指定排序顺序)
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}
注意事项
0.4.20 Solidity 接口语法不足以记录 ERC-721 标准。符合 ERC-721 的合约还必须遵守以下规定:
- Solidity issue #3412:上面的接口包括每个函数的显式可变性保证。可变性保证的强度依次为:
payable
、隐式 nonpayable、view
和pure
。您的实现必须满足此接口中的可变性保证,您可以满足更强的保证。例如,此接口中的payable
函数可以在您的合约中实现为 nonpayable(未指定状态可变性)。我们希望以后的 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:使用
this.*.selector
被 Solidity 标记为警告,Solidity 的未来版本不会将其标记为错误。
如果较新版本的 Solidity 允许在代码中表达注意事项,则可以更新此 EIP 并删除注意事项,这将等同于原始规范。
理由
以太坊智能合约的许多拟议用途取决于跟踪可区分资产。现有或计划的 NFT 的示例包括 Decentraland 中的 LAND、CryptoPunks 中的同名 punks 以及使用 DMarket 或 EnjinCoin 等系统的游戏内物品。未来的用途包括跟踪现实世界的资产,例如房地产(正如 Ubitquity 或 Propy 等公司所设想的那样)。在每种情况下,关键是这些项目不能像分类账中的数字一样“混在一起”,而是每个资产的所有权必须单独且原子地跟踪。无论这些资产的性质如何,如果我们有一个标准化接口来允许跨功能的资产管理和销售平台,生态系统将会更加强大。
“NFT”词语选择
“NFT”对几乎所有接受调查的人来说都是令人满意的,并且广泛适用于广泛的可区分数字资产领域。我们认识到“契约”对于此标准的某些应用(特别是物理财产)来说非常具有描述性。
考虑的替代方案:可区分资产、所有权凭证、代币、资产、权益、票证
NFT 标识符
每个 NFT 都由 ERC-721 智能合约中的唯一 uint256
ID 标识。此标识号在合约的生命周期内不得更改。然后,(合约地址,uint256 tokenId)
对将是以太坊链上特定资产的全局唯一和完全限定的标识符。虽然一些 ERC-721 智能合约可能会发现从 ID 0 开始并且为每个新 NFT 简单地递增 1 很方便,但调用者不得假定 ID 号具有任何特定模式,并且必须将 ID 视为“黑盒”。另请注意,NFT 可能会失效(被销毁)。请参阅枚举函数以获取受支持的枚举接口。
uint256
的选择允许各种各样的应用程序,因为 UUID 和 sha3 哈希可以直接转换为 uint256
。
转移机制
ERC-721 标准化了一个安全转移函数 safeTransferFrom
(重载了带和不带 bytes
参数的版本)和一个不安全函数 transferFrom
。转移可以由以下人员发起:
- NFT 的所有者
- NFT 的批准地址
- NFT 当前所有者的授权运营商
此外,授权运营商可以设置 NFT 的批准地址。这为钱包、经纪人和拍卖应用程序提供了一套强大的工具,可以快速使用大量 NFT。
转移和接受函数的文档仅指定了交易必须抛出异常的情况。您的实现也可能在其他情况下抛出异常。这允许实现实现有趣的结果:
- 如果合约暂停,则禁止转移 - 先例,CryptoKitties 部署的合约,第 611 行
- 阻止某些地址接收 NFT - 先例,CryptoKitties 部署的合约,第 565、566 行
- 禁止不安全转移 - 除非
_to
等于msg.sender
或countOf(_to)
为非零值或先前为非零值(因为这种情况是安全的),否则transferFrom
抛出异常 - 向交易的双方收取费用 - 如果先前为零地址,则在调用
approve
并使用非零_approved
时需要付款,如果先前为非零地址,则在调用approve
并使用零地址时退款,在调用任何转移函数时需要付款,需要转移参数_to
等于msg.sender
,需要转移参数_to
为 NFT 的批准地址 - 只读 NFT 注册表 - 始终从
safeTransferFrom
、transferFrom
、approve
和setApprovalForAll
抛出异常
失败的交易将抛出异常,这是 ERC-223、ERC-677、ERC-827 和 OpenZeppelin 的 SafeERC20.sol 实现中确定的最佳实践。ERC-20 定义了一个 allowance
功能,当调用该功能,然后再将其修改为不同的金额时,这会导致一个问题,如 OpenZeppelin issue #438 中所示。在 ERC-721 中,没有 allowance,因为每个 NFT 都是唯一的,数量为零或一。因此,我们获得了 ERC-20 原始设计的好处,而没有后来发现的问题。
NFT 的创建(“铸造”)和 NFT 的销毁(“销毁”)不包括在本规范中。您的合约可以通过其他方式实现这些。请参阅 event
文档,了解您在创建或销毁 NFT 时的责任。
我们质疑了 onERC721Received
上的 operator
参数是否必要。在我们能想到的所有情况下,如果运营商很重要,那么该运营商可以将其 token 转移给自己,然后再发送 - 那么他们将成为 from
地址。这似乎是人为的,因为我们认为运营商是 token 的临时所有者(并且转移给自己是多余的)。当运营商发送 token 时,运营商是自己行动,而不是代表 token 持有者行动。这就是为什么运营商和先前的 token 所有者对 token 接收者都很重要。
考虑的替代方案:仅允许两步 ERC-20 风格的交易,要求转移函数永远不抛出异常,要求所有函数都返回一个布尔值,指示操作是否成功。
ERC-165 接口
我们选择标准接口检测 (ERC-165) 来公开 ERC-721 智能合约支持的接口。
未来的 EIP 可能会创建一个合约接口的全局注册表。我们强烈支持这样的 EIP,它将允许您的 ERC-721 实现通过委托给单独的合约来实现 ERC721Enumerable
、ERC721Metadata
或其他接口。
Gas 和复杂性(关于枚举扩展)
本规范考虑了管理少量和任意大量 NFT 的实现。如果您的应用程序能够增长,请避免在代码中使用 for/while 循环(参见 CryptoKitties bounty issue #4)。这些表明您的合约可能无法扩展,并且 gas 成本会随着时间的推移而无限期地上升。
我们已将一个合约 XXXXERC721 部署到 Testnet,该合约实例化并跟踪 340282366920938463463374607431768211456 个不同的契约 (2^128)。这足以将每个 IPV6 地址分配给以太坊帐户所有者,或跟踪尺寸为几微米的纳米机器人的所有权,并且总体上占地球一半的大小。您可以从区块链查询它。每个函数消耗的 gas 都比查询 ENS 少。
此图示清楚地表明:ERC-721 标准是可扩展的。
考虑的替代方案:如果资产枚举函数需要 for 循环,则删除该函数,从枚举函数返回 Solidity 数组类型。
隐私
动机部分中确定的钱包/经纪人/拍卖商强烈需要识别所有者拥有哪些 NFT。
考虑一个 NFT 不可枚举的用例可能很有趣,例如财产所有权的私有注册表或部分私有注册表。但是,无法实现隐私,因为攻击者可以简单地 (!) 为每个可能的 tokenId
调用 ownerOf
。
元数据选择(元数据扩展)
我们在元数据扩展中需要 name
和 symbol
函数。我们审查的每个 token EIP 和草案(ERC-20、ERC-223、ERC-677、ERC-777、ERC-827)都包括这些函数。
我们提醒实现作者,如果您抗议使用此机制,则空字符串是对 name
和 symbol
的有效响应。我们还提醒大家,任何智能合约都可以使用与您的合约相同的名称和符号。客户端如何确定哪些 ERC-721 智能合约是众所周知的(规范的)不在本标准的范围之内。
提供了一种将 NFT 与 URI 相关联的机制。我们希望许多实现将利用这一点来为每个 NFT 提供元数据。图像尺寸建议来自 Instagram,他们可能非常了解图像的可用性。URI 可能是可变的(即,它会不时更改)。我们考虑了一个代表房屋所有权的 NFT,在这种情况下,有关房屋的元数据(图像、居住者等)自然会发生变化。
元数据作为字符串值返回。目前,这只能通过从 web3
调用来使用,而不能从其他合约调用。这是可以接受的,因为我们没有考虑在链上应用程序会查询此类信息的用例。
考虑的替代方案:将每个资产的所有元数据放在区块链上(太昂贵),使用 URL 模板查询元数据部分(URL 模板不适用于所有 URL 方案,尤其是 P2P URL),多地址网络地址(不够成熟)
社区共识
在最初的 ERC-721 问题上进行了大量的讨论,此外,我们还在 Gitter 上举行了第一次现场会议,该会议具有良好的代表性并已充分宣传(在 Reddit 上,在 Gitter #ERC 频道和最初的 ERC-721 问题中)。感谢参与者:
- @ImAllInNow Rob from DEC Gaming / Presenting Michigan Ethereum Meetup Feb 7
- @Arachnid Nick Johnson
- @jadhavajay Ajay Jadhav from AyanWorks
- @superphly Cody Marx Bailey - XRAM Capital / Sharing at hackathon Jan 20 / UN Future of Finance Hackathon.
- @fulldecent William Entriken
在 ETHDenver 2018 上举行了第二次活动,以讨论可区分的资产标准(笔记将发布)。
我们在此过程中非常具有包容性,并邀请任何有疑问或贡献的人参与我们的讨论。但是,此标准仅用于支持此处列出的已识别用例。
向后兼容性
我们采用了 ERC-20 规范中的 balanceOf
、totalSupply
、name
和 symbol
语义。如果实现的目标是在支持此标准的同时与 ERC-20 更加兼容,则也可以包括一个返回 uint8(0)
的函数 decimals
。但是,我们发现要求所有 ERC-721 实现都支持 decimals
函数是人为的。
截至 2018 年 2 月的 NFT 实现示例:
- CryptoKitties - 与此标准的早期版本兼容。
- CryptoPunks - 部分 ERC-20 兼容,但不容易推广,因为它直接在合约中包含拍卖功能,并使用明确地将资产称为“punks”的函数名称。
- Auctionhouse Asset Interface - 作者需要为 Auctionhouse ÐApp(目前已暂停)提供一个通用接口。他的“Asset”合约非常简单,但缺少 ERC-20 兼容性、
approve()
功能和元数据。EIP-173 的讨论中引用了此工作。
注意:“限量版、收藏代币”,如 Curio Cards 和 Rare Pepe 不是可区分的资产。它们实际上是单个同质化代币的集合,每个代币都由其自己的智能合约跟踪,并具有其自己的总供应量(在极端情况下可能为 1
)。
onERC721Received
函数专门用于解决旧的已部署合约,这些合约即使没有实现函数,也可能在某些情况下无意中返回 1 (true
)(请参阅 Solidity DelegateCallReturnValue bug)。通过返回并检查魔术值,我们能够区分实际的肯定响应与这些空洞的 true
。
测试用例
0xcert ERC-721 Token 包括使用 Truffle 编写的测试用例。
实现
0xcert ERC721 – 参考实现
- 采用 MIT 许可,因此您可以免费将其用于您的项目
- 包括测试用例
- 积极的漏洞赏金,如果您发现错误,您将获得报酬
Su Squares – 一个广告平台,您可以在其中租用空间和放置图像
- 完成 Su Squares 漏洞赏金计划以寻找此标准或其实现的问题
- 实现了完整的标准和所有可选接口
ERC721ExampleDeed – 实现示例
- 使用 OpenZeppelin 项目格式实现
XXXXERC721,作者:William Entriken – 可扩展的实现示例
- 部署在 testnet 上,包含 10 亿个资产并支持所有带有元数据扩展的查找。这表明扩展不是问题。
参考文献
标准
- ERC-20 代币标准。
- ERC-165 标准接口检测。
- ERC-173 Owned 标准。
- ERC-223 代币标准。
- ERC-677
transferAndCall
代币标准。 - ERC-827 代币标准。
- Ethereum Name Service (ENS). https://ens.domains
- Instagram – 什么是图像分辨率? https://help.instagram.com/1631821640426723
- JSON Schema. https://json-schema.org/
- Multiaddr. https://github.com/multiformats/multiaddr
- RFC 2119 用于在 RFC 中指示需求级别的关键词。 https://www.ietf.org/rfc/rfc2119.txt
问题
- 最初的 ERC-721 问题。 https://github.com/ethereum/eips/issues/721
- Solidity Issue #2330 – 接口函数是外部的。 https://github.com/ethereum/solidity/issues/2330
- Solidity Issue #3412 – 实现接口:允许更严格的可变性。 https://github.com/ethereum/solidity/issues/3412
- Solidity Issue #3419 – 接口无法继承。 https://github.com/ethereum/solidity/issues/3419
- Solidity Issue #3494 – 编译器不正确地推断
selector
函数。 https://github.com/ethereum/solidity/issues/3494 - Solidity Issue #3544 – 无法计算名为
transfer
的函数的 Selector。 https://github.com/ethereum/solidity/issues/3544 - CryptoKitties Bounty Issue #4 – 列出用户拥有的所有 Kitties 为
O(n^2)
。 https://github.com/axiomzen/cryptokitties-bounty/issues/4 - OpenZeppelin Issue #438 –
approve
方法的实现违反了 ERC20 标准。 https://github.com/OpenZeppelin/zeppelin-solidity/issues/438 - Solidity DelegateCallReturnValue Bug. https://solidity.readthedocs.io/en/develop/bugs.html#DelegateCallReturnValue
讨论
- Reddit(首次现场讨论的公告)。 https://www.reddit.com/r/ethereum/comments/7r2ena/friday_119_live_discussion_on_erc_nonfungible/
- Gitter #EIPs(首次现场讨论的公告)。 https://gitter.im/ethereum/EIPs?at=5a5f823fb48e8c3566f0a5e7
- ERC-721(首次现场讨论的公告)。 https://github.com/ethereum/eips/issues/721#issuecomment-358369377
- ETHDenver 2018. https://ethdenver.com
NFT 实现和其他项目
- 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 部署的合约。 https://etherscan.io/address/0x06012c8cf97bead5deae237070f9587f8e7a266d#code
- Su Squares 漏洞赏金计划。 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.
版权
通过 CC0 放弃版权及相关权利。
Citation
Please cite this document as:
William Entriken (@fulldecent), Dieter Shirley <dete@axiomzen.co>, Jacob Evans <jacob@dekz.net>, Nastassia Sachs <nastassia.sachs@protonmail.com>, "ERC-721: 非同质化代币标准," Ethereum Improvement Proposals, no. 721, January 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-721.