ERC-1155 标准

ERC-1155 标准

1. 概念

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 代币资产类别,一次性可以进行多笔多对象交易,交易处理只需要一次批准

2. ERC-1155 功能和特点

根据 ERC-1155 的代码,可以看到其有以下的功能点:

  • 批量转移:一次调用即可转移多个资产。
  • 批次余额:一次调用即可获取多个资产的余额。
  • 批量批准:批准所有令牌到一个地址。
  • EIP-165 支持:声明支持的接口。
  • 钩子接口:提供代币接受钩子接口。
  • NFT 支持:如果供应量仅为 1,则将其视为 NFT。
  • 安全转移规则:安全转移的规则集。

2.1 批量转账

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],那么我们得到的转账结果就是:

  • 将 ID 为 3 的 100 个代币从 _from 转移到 _to。
  • 将 ID 为 6 的 200 个代币从 _from 转移到 _to。
  • 将 ID 为 13 的 5 个代币从 _from 转移到 _to。

在 ERC-1155 中只有 transferFrom 函数,没有 transfer 函数。如果要像 ERC-20 一样转账,只需将 from 地址设置为调用该函数的地址即可。我们还需要搞清楚三个问题,分别如下:

  • 为什么说 safeBatchTransferFrom 是安全的呢?因为有关安全转移规则,可以看下面的 2.7 章节。
  • 为什么没有返回布尔值?因为交易失败时将回滚,这和我们之前讨论的 SafeERC-20 的实现是相同的。
  • 什么是字节数据字段?这就和 ERC-777 一样,我们可以传入任意的数据,这些数据也都将传递给接收钩子。
// ERC-1155
function safeBatchTransferFrom(
    address _from,
    address _to,
    uint256[] calldata _ids,
    uint256[] calldata _values,
    bytes calldata _data
) external;

2.2 批量查询余额

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);

那么就是说查询的结果是:

  • 0xaaa… 用户拥有的 id 为 3 的代币的余额
  • 0xbbb… 用户拥有的 id 为 6 的代币的余额
  • 0xccc… 用户拥有的 id 为 13 的代币的余额

2.3 批量授权

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。

2.4 EIP-165 支持

如果我们还不了解 EIP-165 是什么,请查看 此教程。

简而言之, EIP-165 规范了智能合约如何声明其支持的接口。例如,智能合约是否支持接收 ERC-1155 代币,如果支持则相应的 supportsInterface 功能必须存在,并且对于该合约返回 true。

这就将我们带到了下一个概念:钩子。

2.5 EIP-1155 的接收钩子

有了 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);

2.6 ERC-1155 非同质化代币支持

如果代币的发行量为 1,那么这种代币本质上是非同质化代币 (NFT)。按照 ERC-721 的标准,我们可以定义元数据 URL。客户端可以读取和修改该 URL,详细内容请参见 此处。

2.7 ERC-1155 安全转账规则

我们在 2.1 章节中说到了安全的转账规则。下面来看其中最重要的规则:

  • 必须批准调用者可以转移该 _from 地址持有的代币,否则调用者必须为 _from。
  • 在出现如下状况时,转账交易必须回滚:
    • _to 地址为 0。
    • _ids 与 _values 长度不同。
    • 代币持有人在 _ids 的任何余额都低于 _values 发送给接收者的相应金额。
    • 发生任何其他错误。

注意:包括钩子在内的所有批处理功能也作为不带批处理的版本存在。这样做是出于提高 gas 率的考虑,考虑仅转移一种资产仍可能是最常用的方式。为了简单起见,我们省略了它们。名称相同,只需删除 Batch 前缀即可。

3. 参考文章

  • ERC1155 多合一代币开发教程【Solidity 合约】
  • 解析——什么是 ERC-1155

你可能感兴趣的