🐮12 ERC系列标准
[TOC]
ERC系列标准
基于 ERC 系列标准开发可以建立在 OpenZeppelin 的基础上
OpenZeppelin 是著名的安全智能合约开发库。建立在经过社区审查的代码的坚实基础之上。
ERC20 和 ERC721 等标准的实施。
灵活的基于角色的许可方案。
可重用的 Solidity 组件,用于构建自定义合约和复杂的去中心化系统。
文档 https://docs.openzeppelin.com
源码 https://github.com/OpenZeppelin
ERC20 代币标准
ERC20 是2015年提出的一个能实现智能合约中代币的 API 标准。
ERC-20 提供一个同质化代币的标准,是以太坊上的一个代币协议,所有基于以太坊开发的代币合约都遵守这个协议,遵守协议的代币可以被各种以太坊钱包支持,用于不同的平台和项目。
它提供了多个功能。例如转账代币从一个帐户到不同的帐户,来实现获取帐户的当前余额以及网络上的可用代币总供应量。
函数和事件
如果智能合约实施了下列函数和事件,它可以被称为 ERC-20 代币合约, 部署后负责跟踪以太坊上创建的代币。
一共 4 个getter函数,5个转账相关函数,2个事件。
授权函数 approve ,用户授权一个额度给
_spender,_spender这个用户可以多次使用这个额度,如使用transferFrom函数将_from授权给_spender的额度发送给_to,也可以通过allowance函数查询_owner授权给_spender的剩余额度。ERC20 文档 https://eips.ethereum.org/EIPS/eip-20 。
函数
事件
ERC20 标准智能合约发行代币
IERC20.sol
IERC20.sol 是介绍的一个接口源代码,可以通过实现这个接口快速发代币。
SafeMath.sol
SafeMath.sol 是官方介绍的用于代币发行的代币计算相关函数库,它提供了对代币加减乘除计算的函数,一般使用
using SafeMath for uint256;的方式使用。在 https://github.com/OpenZeppelin/openzeppelin-contracts 可以找到库源码。
代币合约
代币合约可以参考 https://github.com/OpenZeppelin/openzeppelin-contracts/blob/9b3710465583284b8c4c5d2245749246bb2e0094/contracts/token/ERC20/ERC20.sol 。
扩展标准 ERC-165
扩展接口 ERC165 是用于标准接口检测,创建标准方法以发布和检测智能合约实现的接口。
目的是为了查询合约是否支持接口以及是否支持接口的版本,可以根据是否实现接口调整与合约的交互方式。
在此标准中,接口是由以太坊 ABI 定义的一组函数选择器。 这是Solidity的接口(ABI)概念子集,ABI接口还定义了返回类型,可变性(mutability)和事件。
通过函数选择器的函数签名(如:
"myMethod(uint256,string)")的 Keccak(SHA-3)哈希的前 4 字节识别是否实现了接口。兼容 ERC-165 的合约只需实现
ERC165接口的supportsInterface函数。
函数
计算接口标识符:
接口标识符是接口中所有函数选择器的异或(XOR)。
检测合约是否实现了 ERC-165
在合约地址上使用附加数据(input data)
0x01ffc9a701ffc9a700000000000000000000000000000000000000000000000000000000和 gas 30000 进行STATICCALL调用,相当于contract.supportsInterface(0x01ffc9a7)。如果调用失败或返回false , 说明合约不兼容ERC-165标准
如果返回true,则使用输入数据
0x01ffc9a7ffffffff000000000000000000000000000000000000000000000000000000000000进行第二次调用。如果第二次调用失败或返回true,则目标合约不会实现ERC-165。 否则它实现了ERC-165。
检测合约是否实现了某个接口
如果不确定合约是否实现ERC-165,请使用上面的方法进行确认。
如果没有实现ERC-165,那么你将不得不看看它采用哪种老式方法。
如果实现了ERC-165,那么只需调用 supportsInterface(interfaceID) 来确定它是否实现了对应的接口。
ERC-165 的实现
supportsInterface 的实现
例子中实现方式是在构造函数中将合约实现的接口的标识符存入 mapping ,
supportsInterface函数中通过查找 mapping 以确定是否实现了某些接口,每次执行查找成本都是 586 gas。 但合约初始化需要存储每个接口会消耗 gas。也可以直接在
supportsInterface中对接口进行比较确定是否实现接口,但是随着计算的接口越多支付的 gas 也会增加。两种方式在 gas 消耗上差别较大。
ERC-721 非同质化代币标准
ERC-721(Ethereum Request for Comments 721),是在 2018 年提出的一个在智能合约中实现代币 API 的非同质化代币标准。
非同质化代币(NFT)用于以唯一的方式标识某样物品。此类型的代币可以用于出售收藏品、密钥、彩票、音乐会座位编号、体育比赛等物品的平台。
ERC-721 是为 NFT 引入的标准,这种类型的代币是独一无二的,并且可能与来自同一智能合约的另一代币有不同的价值,也许是因为它的年份、稀有性或是它的外观。
所有 NFT 都有一个 uint256 变量,名为 tokenId,所以对于任何 ERC-721 合约,这对值
contract address, tokenId必须是全局唯一的。dApp 可以有一个“转换器”,该转换器使用 tokenId 输入和输出一些非常有趣的事物的图像, 例如蒙娜丽莎、武器、技能或一只宠物。
ERC-721 提供了一些功能,例如将代币从一个帐户转移到另一个帐户、获取帐户的当前代币余额、获取代币的所有者、以及整个网络的可用代币总供应量。 除此之外,它还具有其他功能,例如批准帐户中一定数量的代币可以被第三方帐户转移。
函数和事件
智能合约实现了 ERC-721 规定的方法和事件,就可以被称为 ERC-721 非同质化代币合约。 部署后它负责跟踪在以太坊上创建的代币。
函数
事件
扩展接口 ERC721TokenReceiver
扩展接口
ERC721TokenReceiver的接口标识符是0x150b7a02。
合约要接受 NFT 转账,就必须实现
ERC721TokenReceiver接口。
可选元数据扩展接口 ERC721Metadata
对于ERC-721 智能合约,元数据扩展接口是可选的。实现允许询问智能合约的名称以及 NFT 所代表的资产的详细信息。
ERC721Metadata的接口标识符是0x5b5e139f。接口用于提供合约的元数据:name , symbol 及 URI(NFT所对应的资源)。
name、symbol 如果不具体实现则使用空字符串是有效的响应也比不实现好。任何智能合约都可以使用与合约相同的 name 和 symbol。
ERC721Metadata提供了一种将 NFT 与 URI 关联的机制。预计许多实现将利用这一点为每个 NFT 提供元数据。URI 可能是可变的。我们考虑了代表房屋所有权的 NFT,在这种情况下,关于房屋的元数据(图像、居住者等)可以自然地改变。元数据作为字符串值返回。目前,这仅可用作调用 web3,而不是从其他合约调用。没有考虑过区块链应用程序会查询此类信息的用例。
考虑的替代方案:将每个资产的所有元数据放在区块链上(太昂贵),使用 URL 模板查询元数据部分(URL 模板不适用于所有 URL 方案,尤其是 P2P URL),multiaddr 网络地址(不够成熟)。
元数据格式,这个元数据一般存储在 IPFS 上,但也有可能存放在私人服务器
可选枚举扩展接口 ERC721Enumerable
ERC721Enumerable的主要目的是提高合约中NTF的可访问性。
ERC721Enumerable的接口标识符0x780e9d63。
ERC-721 的实现
实现 ERC-721 是发行 NFT 资产的智能合约
以图片为例,智能合约中并不负责存储图片,图片也不是存储在以太坊,图片存储在 IPFS 或其它地方(没有强制性规定),合约的重要功能是将图片所在地方与智能合约中的
_tokenId相关联。
NFT 之坑
因为链本身不存储图片,如果存储图片的服务消失则持有者只能傻傻看着一个
tokenId发愣。如果存储扩展元数据的不是 IPFS 这类一经发布不可更改的服务,那么元数据的 JSON 文件的内容可能还是可变的,今天
tokenId关联的是林志玲艺术照的元数据,明日可能被篡改关联到xxx艺术照甚至可能是404。因此 NFT 具备的唯一性是一个假唯一性,并不是真正唯一。
例子中实现 ERC-721 并发行 NFT(图片) 步骤:
第一步:制作图片,并且图片用数字命名,这个名字与合约中的
tokenId一致,上传图片到 IPFS。第二步:写元数据扩展文件,一个图片对应一个扩展文件,文件名就是图片名的数字,不要有后缀,上传元数据扩展文件到 IPFS。
第三步:开始编写智能合约代码,主要结构遵循
openzeppelin的 ERC-721 案例实现。第四步:调用铸币函数开始铸币,就是将已经上传到 IPFS 的元数据扩展文件名
tokenId存到区块链上,这个tokenId的持有者是合约拥有者。第五步:配置一个
baseURI,它是 IPFS 文件访问的前缀,确保baseURI+tokenId能够访问到元数据扩展文件,而ERC721Metadata接口的tokenURI函数的返回值就是baseURI/tokenId。第六步:正常转让交易 NFT,也可以在 opensea 查看。
引入的依赖所有源码在 https://github.com/OpenZeppelin/openzeppelin-contracts 下
一个最简单的 ERC-721 实现
在这个 demo 中,合约部署完成后调用
mint(address to)函数铸币,实际是产生一个未被使用的tokenId并且它归属to,默认情况下tokenId从0开始。这个 demo 中的铸币函数1次铸币一个,在正常业务中,还需根据业务需要增加或修改铸币函数,但是铸币其实负责的只是生成未被使用的
tokenId。
测试环境下访问 https://testnets.opensea.io/assets/ 查看测试铸造的 NFT
如访问 https://testnets.opensea.io/assets/0x85d969e9018a30e39dafd2d7b73f3d1bd0254b04/1

测试环境 NFT 访问
1号NFT的扩展元数据
ipfs://QmYB7P4WLNGxv4x8g5PBPS4sHtD5Q3cqDES7aWzHmM2YWE/1
在不同平台支持的 NFT 元数据解析数据会有所差异,因此
ERC721Metadata的元数据模板是一个基础的模板,opensea 的元数据格式参见 https://docs.opensea.io/docs/metadata-standards 。
函数
contractURI()的用途是集合描述扩展元数据文件的存放地址,如ipfs://QmRPdHNnzm9Xj5TMZ15p81t4xKPrLcCWW9nvpDnhKw6nyL的集合描述扩展元数据
集合元数据如 opensea 的格式在 https://docs.opensea.io/docs/contract-level-metadata ,
name集合名称,description集合描述,image集合封面图片的URI,external_link外部连接生成环境改成 https://openseacreatures.io ,seller_fee_basis_points是每次销售收取费率 1是万分之1 设置成100就是百分之1,fee_recipient费率收取账户。

集合描述的展示
Last updated