ERC 是 Ethereum Request for Comments(以太坊征求意见提案)的缩写,代表着以太坊已正式化的提案,它是由 EIP(Ethereum Improvement Proposals 以太坊升级提案)经过以太坊开发团队的各种审议和测试后通过的一种提案,也就是对有用提案进行标准化,从而实现对开发者提供模版帮助以及标准限制。
而 ERC 后面的 20、721、1155 代表提案号,ERC-20 则代表着第 20 号提案,其它提案号以此类推。
ERC-1155 以太坊上的一种代币标准,由 Enjin 首席技术官 Witek Radomski 等人开发,并于 2018 年 6 月 17 日将该标准的第一个版本放置到 Ethereum 的 GitHub 库中,ERC-1155 是 ERC-20 和 ERC-721 的升级规范,它允许在一个交易中发送多种不同的代币,就像现实中我们可以同时转账人民币和美元。
标准 | ERC-20 | ERC-721 | ERC-1155 |
---|---|---|---|
代币类型 | 同质化代币 | 非同质化代币 | 同质化代币、非同质化代币、介于同质化和非同质化代币之间可以互相切换的代币 |
特点 | 代币属性相同、可无损互换、可拆分 | 代币属性互不相同、不可互换、不可拆分 | 前两者的特点都有,且在一定程度上可以在两者中切换 |
生成处理 | 一次性只能生成一种 ERC-20 代币,一次性只能进行单笔单对象交易,并且交易处理需要多次批准 | 一次性只能生成一种 ERC-721 代币,一次性只能进行单笔单对象交易,并且交易处理需要多次批准 | 一次性可以生成多种 ERC-1155 代币资产类别,一次性可以进行多笔多对象交易,交易处理只需要一次批准 |
根据 ERC-1155 的代码,可以看到其有以下的功能点:
ERC-1155 中的批量转账与 ERC-20 中的转账类似,我们先来看下 ERC-20 的转账函数:
// ERC-20
function transferFrom(address from, address to, uint256 value) external returns (bool);
ERC-1155 和 ERC-20 的唯一区别就是我们将值作为数组来进行传递,并且还传递了代币编号的 id 数组。例如,我们要转账的代币编号数组为 _ids = [3, 6, 13] 和它们对应的值 _values = [100, 200, 5],那么我们得到的转账结果就是:
在 ERC-1155 中只有 transferFrom 函数,没有 transfer 函数。如果要像 ERC-20 一样转账,只需将 from 地址设置为调用该函数的地址即可。我们还需要搞清楚三个问题,分别如下:
// ERC-1155
function safeBatchTransferFrom(
address _from,
address _to,
uint256[] calldata _ids,
uint256[] calldata _values,
bytes calldata _data
) external;
ERC-1155 中的批量查询余额和 ERC-20 中的 balanceOf 类似,我们先来看下 ERC-20 中的查询余额:
// ERC-20
function balanceOf(address owner) external view returns (uint256);
而 ERC-1155 中的查询余额就是在一次调用中查询多个余额,传入要查询用户的数组以及要查询该用户持有的指定代币的余额。例如,我们要查询的指定代币编号数组为 _ids = [3,6,13] 和所有者 _owners = [0xaaa…, 0xbbb…, 0xccc…]。
// ERC-1155
function balanceOfBatch(
address[] calldata _owners,
uint256[] calldata _ids
) external view returns (uint256[] memory);
那么就是说查询的结果是:
ERC-1155 中的批量授权和 ERC-20 中的授权还不太一样,在 ERC-1155 中,批量授权不需要指定授权金额,只需调用 setApprovalForAll 函数将操作者设置为批准或未批准即可。
// ERC-1155
function setApprovalForAll(
address _operator,
bool _approved
) external;
如果想查询是否已经授权,可以调用 isApprovedForAll 函数来读取当前的授权状态。我们无法定义要批准的代币数量,也不能指定授权哪种代币。
// ERC-1155
function isApprovedForAll(
address _owner,
address _operator
) external view returns (bool);
这就是 ERC-1155 中有意设计的,目的就是为了保持使用的简单性。所以我们只能批准一个地址的所有内容。如果我们需要对特定的批准进行更细致的控制,可以查看 EIP-1761。
如果我们还不了解 EIP-165 是什么,请查看 此教程。
简而言之, EIP-165 规范了智能合约如何声明其支持的接口。例如,智能合约是否支持接收 ERC-1155 代币,如果支持则相应的 supportsInterface 功能必须存在,并且对于该合约返回 true。
这就将我们带到了下一个概念:钩子。
有了 EIP-165 的支持,ERC-1155 仅需要支持智能合约的接收钩子。钩子函数必须返回一个预定义的 4 字节 magic 值,该值指定为:
bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))
当接收合约返回此值时,假定合约接受转账并知道如何处理 ERC-1155 代币,那么合约就不再会出现卡死的代币了。
// ERC-1155
function onERC1155BatchReceived(
address _operator,
address _from,
uint256[] calldata _ids,
uint256[] calldata _values,
bytes calldata _data
) external returns(bytes4);
如果代币的发行量为 1,那么这种代币本质上是非同质化代币 (NFT)。按照 ERC-721 的标准,我们可以定义元数据 URL。客户端可以读取和修改该 URL,详细内容请参见 此处。
我们在 2.1 章节中说到了安全的转账规则。下面来看其中最重要的规则:
注意:包括钩子在内的所有批处理功能也作为不带批处理的版本存在。这样做是出于提高 gas 率的考虑,考虑仅转移一种资产仍可能是最常用的方式。为了简单起见,我们省略了它们。名称相同,只需删除 Batch 前缀即可。