ERC-3525: 半同质化代币
| Authors |
|---|
Table of Contents
slot 的枚举扩展是 OPTIONAL 的。这允许你的合约发布其完整的 SLOT 列表,并使它们可被发现。
pragma solidity ^0.8.0;
/**
* @title ERC-3525 Semi-Fungible Token Standard, optional extension for slot enumeration
* @dev Interfaces for any contract that wants to support enumeration of slots as well as tokens
* with the same slot.
* 用于任何想要支持枚举 slot 以及具有相同 slot 的代币的合约的接口。
* Note: the ERC-165 identifier for this interface is 0x3b741b9e.
*/
interface IERC3525SlotEnumerable is IERC3525 /* , IERC721Enumerable */ {
/**
* @notice Get the total amount of slots stored by the contract.
* 获取合约存储的 slot 总数。
* @return The total amount of slots
*/
function slotCount() external view returns (uint256);
/**
* @notice Get the slot at the specified index of all slots stored by the contract.
* 获取合约存储的所有 slot 中指定索引处的 slot。
* @param _index The index in the slot list
* @return The slot at `index` of all slots.
*/
function slotByIndex(uint256 _index) external view returns (uint256);
/**
* @notice Get the total amount of tokens with the same slot.
* 获取具有相同 slot 的代币总数。
* @param _slot The slot to query token supply for
* @return The total amount of tokens with the specified `_slot`
*/
function tokenSupplyInSlot(uint256 _slot) external view returns (uint256);
/**
* @notice Get the token at the specified index of all tokens with the same slot.
* 获取具有相同 slot 的所有代币中指定索引处的代币。
* @param _slot The slot to query tokens with
* @param _index The index in the token list of the slot
* @return The token ID at `_index` of all tokens with `_slot`
*/
function tokenInSlotByIndex(uint256 _slot, uint256 _index) external view returns (uint256);
}
slot 级别的授权是 OPTIONAL 的。这允许任何想要支持 slot 授权的合约,该授权允许 operator 管理一个人具有相同 slot 的代币。
pragma solidity ^0.8.0;
/**
* @title ERC-3525 Semi-Fungible Token Standard, optional extension for approval of slot level
* @dev Interfaces for any contract that wants to support approval of slot level, which allows an
* operator to manage one's tokens with the same slot.
* 用于任何想要支持 slot 级别授权的合约的接口,该授权允许 operator 管理一个人具有相同 slot 的代币。
* See https://eips.ethereum.org/EIPS/eip-3525
* Note: the ERC-165 identifier for this interface is 0xb688be58.
*/
interface IERC3525SlotApprovable is IERC3525 {
/**
* @dev MUST emit when an operator is approved or disapproved to manage all of `_owner`'s
* tokens with the same slot.
* 当批准或不批准 operator 管理所有 `_owner` 的具有相同 slot 的代币时,必须发出此事件。
* @param _owner The address whose tokens are approved
* @param _slot The slot to approve, all of `_owner`'s tokens with this slot are approved
* @param _operator The operator being approved or disapproved
* @param _approved Identify if `_operator` is approved or disapproved
*/
event ApprovalForSlot(address indexed _owner, uint256 indexed _slot, address indexed _operator, bool _approved);
/**
* @notice Approve or disapprove an operator to manage all of `_owner`'s tokens with the
* specified slot.
* 批准或不批准 operator 管理所有 `_owner` 的具有指定 slot 的代币。
* @dev Caller SHOULD be `_owner` or an operator who has been authorized through
* `setApprovalForAll`.
* 调用者应该是 `_owner` 或已通过 `setApprovalForAll` 授权的 operator。
* MUST emit ApprovalSlot event.
* 必须发出 ApprovalSlot 事件。
* @param _owner The address that owns the ERC-3525 tokens
* @param _slot The slot of tokens being queried approval of
* @param _operator The address for whom to query approval
* @param _approved Identify if `_operator` would be approved or disapproved
*/
function setApprovalForSlot(
address _owner,
uint256 _slot,
address _operator,
bool _approved
) external payable;
/**
* @notice Query if `_operator` is authorized to manage all of `_owner`'s tokens with the
* specified slot.
* 查询 `_operator` 是否被授权管理所有 `_owner` 的具有指定 slot 的代币。
* @param _owner The address that owns the ERC-3525 tokens
* @param _slot The slot of tokens being queried approval of
* @param _operator The address for whom to query approval
* @return True if `_operator` is authorized to manage all of `_owner`'s tokens with `_slot`,
* false otherwise.
* 如果 `_operator` 被授权管理所有 `_owner` 的具有 `_slot` 的代币,则为 True,否则为 False。
*/
function isApprovedForSlot(
address _owner,
uint256 _slot,
address _operator
) external view returns (bool);
}
摘要
这是一个关于半同质化代币的标准。本文档中描述的智能合约接口集定义了一个 ERC-721 兼容的代币标准。该标准引入了一个 三元标量模型,该模型表示代币的半同质化结构。它还引入了新的转移模型以及反映代币半同质化性质的授权模型。
代币包含一个等效于 ERC-721 的 ID 属性,以将其标识为普遍唯一的实体,以便代币可以在地址之间转移,并被授权以 ERC-721 兼容的方式进行操作。
代币还包含一个 value 属性,表示代币的定量性质。value 属性的含义与 ERC-20 代币的 balance 属性非常相似。每个代币都有一个 slot 属性,确保将具有相同 slot 的两个代币的值视为可互换的,从而为代币的 value 属性增加同质性。
此 EIP 引入了用于半同质化的新代币转移模型,包括同一 slot 的两个代币之间的 value 转移以及从代币到地址的 value 转移。
动机
代币化是使用和控制加密数字资产的最重要趋势之一。传统上,有两种方法可以做到这一点:同质化和非同质化代币。同质化代币通常使用 ERC-20 标准,其中每个单位的资产彼此相同。ERC-20 是一种灵活高效的操作同质化代币的方式。非同质化代币主要为 ERC-721 代币,这是一种能够根据身份区分数字资产的标准。
但是,两者都有明显的缺点。例如,ERC-20 要求用户为每个单独的数据结构或可自定义属性的组合创建一个单独的 ERC-20 合约。实际上,这导致需要创建大量的 ERC-20 合约。另一方面,ERC-721 代币不提供定量功能,从而大大削弱了它们的可计算性、流动性和可管理性。例如,如果有人要使用 ERC-721 创建金融工具(如债券、保险单或归属计划),则没有标准接口可供我们控制其中的 value,从而无法转移代币所代表的合约中的一部分权益。
解决此问题的一种更直观、更直接的方法是创建一个同时具有 ERC-20 的定量功能和 ERC-721 的定性属性的半同质化代币。这种半同质化代币与 ERC-721 的向后兼容性将有助于利用已在使用的现有基础设施,并加快采用速度。
规范
本文档中使用的关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL”应按照 RFC 2119 中的描述进行解释。
每个 ERC-3525 兼容合约必须实现 ERC-3525、ERC-721 和 ERC-165 接口
pragma solidity ^0.8.0;
/**
* @title ERC-3525 Semi-Fungible Token Standard
* Note: the ERC-165 identifier for this interface is 0xd5358140.
*/
interface IERC3525 /* is IERC165, IERC721 */ {
/**
* @dev MUST emit when value of a token is transferred to another token with the same slot,
* including zero value transfers (_value == 0) as well as transfers when tokens are created
* (`_fromTokenId` == 0) or destroyed (`_toTokenId` == 0).
* 当一个代币的 value 被转移到另一个具有相同 slot 的代币时,必须发出此事件
* 包括零 value 转移 (_value == 0) 以及创建代币时 (`_fromTokenId` == 0) 或销毁代币时 (`_toTokenId` == 0) 的转移。
* @param _fromTokenId The token id to transfer value from
* @param _toTokenId The token id to transfer value to
* @param _value The transferred value
*/
event TransferValue(uint256 indexed _fromTokenId, uint256 indexed _toTokenId, uint256 _value);
/**
* @dev MUST emit when the approval value of a token is set or changed.
* 当一个代币的授权 value 被设置或更改时,必须发出此事件。
* @param _tokenId The token to approve
* @param _operator The operator to approve for
* @param _value The maximum value that `_operator` is allowed to manage
*/
event ApprovalValue(uint256 indexed _tokenId, address indexed _operator, uint256 _value);
/**
* @dev MUST emit when the slot of a token is set or changed.
* 当一个代币的 slot 被设置或更改时,必须发出此事件。
* @param _tokenId The token of which slot is set or changed
* @param _oldSlot The previous slot of the token
* @param _newSlot The updated slot of the token
*/
event SlotChanged(uint256 indexed _tokenId, uint256 indexed _oldSlot, uint256 indexed _newSlot);
/**
* @notice Get the number of decimals the token uses for value - e.g. 6, means the user
* representation of the value of a token can be calculated by dividing it by 1,000,000.
* 获取代币用于 value 的小数位数 - 例如,6 表示可以通过将代币 value 除以 1,000,000 来计算代币 value 的用户表示形式。
* Considering the compatibility with third-party wallets, this function is defined as
* `valueDecimals()` instead of `decimals()` to avoid conflict with ERC-20 tokens.
* 考虑到与第三方钱包的兼容性,此函数定义为 `valueDecimals()` 而不是 `decimals()`,以避免与 ERC-20 代币冲突。
* @return The number of decimals for value
*/
function valueDecimals() external view returns (uint8);
/**
* @notice Get the value of a token.
* 获取代币的 value。
* @param _tokenId The token for which to query the balance
* @return The value of `_tokenId`
*/
function balanceOf(uint256 _tokenId) external view returns (uint256);
/**
* @notice Get the slot of a token.
* 获取代币的 slot。
* @param _tokenId The identifier for a token
* @return The slot of the token
*/
function slotOf(uint256 _tokenId) external view returns (uint256);
/**
* @notice Allow an operator to manage the value of a token, up to the `_value`.
* 允许 operator 管理代币的 value,最高可达 `_value`。
* @dev MUST revert unless caller is the current owner, an authorized operator, or the approved
* address for `_tokenId`.
* 除非调用者是当前所有者、授权的 operator 或 `_tokenId` 的授权地址,否则必须回退。
* MUST emit the ApprovalValue event.
* 必须发出 ApprovalValue 事件。
* @param _tokenId The token to approve
* @param _operator The operator to be approved
* @param _value The maximum value of `_toTokenId` that `_operator` is allowed to manage
*/
function approve(
uint256 _tokenId,
address _operator,
uint256 _value
) external payable;
/**
* @notice Get the maximum value of a token that an operator is allowed to manage.
* 获取 operator 允许管理的一个代币的最大 value。
* @param _tokenId The token for which to query the allowance
* @param _operator The address of an operator
* @return The current approval value of `_tokenId` that `_operator` is allowed to manage
*/
function allowance(uint256 _tokenId, address _operator) external view returns (uint256);
/**
* @notice Transfer value from a specified token to another specified token with the same slot.
* 将 value 从指定的代币转移到另一个具有相同 slot 的指定代币。
* @dev Caller MUST be the current owner, an authorized operator or an operator who has been
* approved the whole `_fromTokenId` or part of it.
* 调用者必须是 `_fromTokenId` 的当前所有者、授权的 operator 或已被授权全部 `_fromTokenId` 或其中一部分的 operator。
* MUST revert if `_fromTokenId` or `_toTokenId` is zero token id or does not exist.
* 如果 `_fromTokenId` 或 `_toTokenId` 为零代币 id 或不存在,则必须回退。
* MUST revert if slots of `_fromTokenId` and `_toTokenId` do not match.
* 如果 `_fromTokenId` 和 `_toTokenId` 的 slot 不匹配,则必须回退。
* MUST revert if `_value` exceeds the balance of `_fromTokenId` or its allowance to the
* operator.
* 如果 `_value` 超过 `_fromTokenId` 的余额或其对 operator 的授权,则必须回退。
* MUST emit `TransferValue` event.
* 必须发出 `TransferValue` 事件。
* @param _fromTokenId The token to transfer value from
* @param _toTokenId The token to transfer value to
* @param _value The transferred value
*/
function transferFrom(
uint256 _fromTokenId,
uint256 _toTokenId,
uint256 _value
) external payable;
/**
* @notice Transfer value from a specified token to an address. The caller should confirm that
* `_to` is capable of receiving ERC-3525 tokens.
* 将 value 从指定的代币转移到一个地址。调用者应确认 `_to` 能够接收 ERC-3525 代币。
* @dev This function MUST create a new ERC-3525 token with the same slot for `_to`,
* or find an existing token with the same slot owned by `_to`, to receive the transferred value.
* 此函数必须为 `_to` 创建一个具有相同 slot 的新 ERC-3525 代币,或者找到一个 `_to` 拥有的具有相同 slot 的现有代币,以接收转移的 value。
* MUST revert if `_fromTokenId` is zero token id or does not exist.
* 如果 `_fromTokenId` 为零代币 id 或不存在,则必须回退。
* MUST revert if `_to` is zero address.
* 如果 `_to` 为零地址,则必须回退。
* MUST revert if `_value` exceeds the balance of `_fromTokenId` or its allowance to the
* operator.
* 如果 `_value` 超过 `_fromTokenId` 的余额或其对 operator 的授权,则必须回退。
* MUST emit `Transfer` and `TransferValue` events.
* 必须发出 `Transfer` 和 `TransferValue` 事件。
* @param _fromTokenId The token to transfer value from
* @param _to The address to transfer value to
* @param _value The transferred value
* @return ID of the token which receives the transferred value
*/
function transferFrom(
uint256 _fromTokenId,
address _to,
uint256 _value
) external payable returns (uint256);
}slot 的枚举扩展是 OPTIONAL 的。这允许你的合约发布其完整的 SLOT 列表,并使它们可被发现。
pragma solidity ^0.8.0;
/**
* @title ERC-3525 Semi-Fungible Token Standard, optional extension for slot enumeration
* @dev Interfaces for any contract that wants to support enumeration of slots as well as tokens
* with the same slot.
* 用于任何想要支持枚举 slot 以及具有相同 slot 的代币的合约的接口。
* Note: the ERC-165 identifier for this interface is 0x3b741b9e.
*/
interface IERC3525SlotEnumerable is IERC3525 /* , IERC721Enumerable */ {
/**
* @notice Get the total amount of slots stored by the contract.
* 获取合约存储的 slot 总数。
* @return The total amount of slots
*/
function slotCount() external view returns (uint256);
/**
* @notice Get the slot at the specified index of all slots stored by the contract.
* 获取合约存储的所有 slot 中指定索引处的 slot。
* @param _index The index in the slot list
* @return The slot at `index` of all slots.
*/
function slotByIndex(uint256 _index) external view returns (uint256);
/**
* @notice Get the total amount of tokens with the same slot.
* 获取具有相同 slot 的代币总数。
* @param _slot The slot to query token supply for
* @return The total amount of tokens with the specified `_slot`
*/
function tokenSupplyInSlot(uint256 _slot) external view returns (uint256);
/**
* @notice Get the token at the specified index of all tokens with the same slot.
* 获取具有相同 slot 的所有代币中指定索引处的代币。
* @param _slot The slot to query tokens with
* @param _index The index in the token list of the slot
* @return The token ID at `_index` of all tokens with `_slot`
*/
function tokenInSlotByIndex(uint256 _slot, uint256 _index) external view returns (uint256);
}slot 级别的授权是 OPTIONAL 的。这允许任何想要支持 slot 授权的合约,该授权允许 operator 管理一个人具有相同 slot 的代币。
pragma solidity ^0.8.0;
/**
* @title ERC-3525 Semi-Fungible Token Standard, optional extension for approval of slot level
* @dev Interfaces for any contract that wants to support approval of slot level, which allows an
* operator to manage one's tokens with the same slot.
* 用于任何想要支持 slot 级别授权的合约的接口,该授权允许 operator 管理一个人具有相同 slot 的代币。
* See https://eips.ethereum.org/EIPS/eip-3525
* Note: the ERC-165 identifier for this interface is 0xb688be58.
*/
interface IERC3525SlotApprovable is IERC3525 {
/**
* @dev MUST emit when an operator is approved or disapproved to manage all of `_owner`'s
* tokens with the same slot.
* 当批准或不批准 operator 管理所有 `_owner` 的具有相同 slot 的代币时,必须发出此事件。
* @param _owner The address whose tokens are approved
* @param _slot The slot to approve, all of `_owner`'s tokens with this slot are approved
* @param _operator The operator being approved or disapproved
* @param _approved Identify if `_operator` is approved or disapproved
*/
event ApprovalForSlot(address indexed _owner, uint256 indexed _slot, address indexed _operator, bool _approved);
/**
* @notice Approve or disapprove an operator to manage all of `_owner`'s tokens with the
* specified slot.
* 批准或不批准 operator 管理所有 `_owner` 的具有指定 slot 的代币。
* @dev Caller SHOULD be `_owner` or an operator who has been authorized through
* `setApprovalForAll`.
* 调用者应该是 `_owner` 或已通过 `setApprovalForAll` 授权的 operator。
* MUST emit ApprovalSlot event.
* 必须发出 ApprovalSlot 事件。
* @param _owner The address that owns the ERC-3525 tokens
* @param _slot The slot of tokens being queried approval of
* @param _operator The address for whom to query approval
* @param _approved Identify if `_operator` would be approved or disapproved
*/
function setApprovalForSlot(
address _owner,
uint256 _slot,
address _operator,
bool _approved
) external payable;
/**
* @notice Query if `_operator` is authorized to manage all of `_owner`'s tokens with the
* specified slot.
* 查询 `_operator` 是否被授权管理所有 `_owner` 的具有指定 slot 的代币。
* @param _owner The address that owns the ERC-3525 tokens
* @param _slot The slot of tokens being queried approval of
* @param _operator The address for whom to query approval
* @return True if `_operator` is authorized to manage all of `_owner`'s tokens with `_slot`,
* false otherwise.
* 如果 `_operator` 被授权管理所有 `_owner` 的具有 `_slot` 的代币,则为 True,否则为 False。
*/
function isApprovedForSlot(
address _owner,
uint256 _slot,
address _operator
) external view returns (bool);
}ERC-3525 代币接收器
如果一个智能合约想要在接收到来自其他地址的 value 时得到通知,它应该实现 IERC3525Receiver 接口中的所有函数,在实现中它可以决定是否接受或拒绝转移。有关更多详细信息,请参阅“转移规则”。
pragma solidity ^0.8.0;
/**
* @title ERC-3525 token receiver interface
* @dev Interface for a smart contract that wants to be informed by ERC-3525 contracts when receiving values from ANY addresses or ERC-3525 tokens.
* 用于智能合约的接口,该智能合约希望在接收到来自任何地址或 ERC-3525 代币的 value 时得到 ERC-3525 合约的通知。
* Note: the ERC-165 identifier for this interface is 0x009ce20b.
*/
interface IERC3525Receiver {
/**
* @notice Handle the receipt of an ERC-3525 token value.
* 处理接收 ERC-3525 代币的 value。
* @dev An ERC-3525 smart contract MUST check whether this function is implemented by the recipient contract, if the
* recipient contract implements this function, the ERC-3525 contract MUST call this function after a
* value transfer (i.e. `transferFrom(uint256,uint256,uint256,bytes)`).
* ERC-3525 智能合约必须检查接收者合约是否实现了此函数,如果接收者合约实现了此函数,则 ERC-3525 合约必须在 value 转移后调用此函数(即 `transferFrom(uint256,uint256,uint256,bytes)`)。
* MUST return 0x009ce20b (i.e. `bytes4(keccak256('onERC3525Received(address,uint256,uint256,
* uint256,bytes)'))`) if the transfer is accepted.
* 如果转移被接受,必须返回 0x009ce20b(即 `bytes4(keccak256('onERC3525Received(address,uint256,uint256,uint256,bytes)'))`)。
* MUST revert or return any value other than 0x009ce20b if the transfer is rejected.
* 如果转移被拒绝,必须回退或返回除 0x009ce20b 之外的任何 value。
* @param _operator The address which triggered the transfer
* @param _fromTokenId The token id to transfer value from
* @param _toTokenId The token id to transfer value to
* @param _value The transferred value
* @param _data Additional data with no specified format
* @return `bytes4(keccak256('onERC3525Received(address,uint256,uint256,uint256,bytes)'))`
* unless the transfer is rejected.
* 除非转移被拒绝,否则返回 `bytes4(keccak256('onERC3525Received(address,uint256,uint256,uint256,bytes)'))`。
*/
function onERC3525Received(address _operator, uint256 _fromTokenId, uint256 _toTokenId, uint256 _value, bytes calldata _data) external returns (bytes4);
}
代币操作
场景
转移:
除了 ERC-721 兼容的代币转移方法外,此 EIP 还引入了两个新的转移模型:从 ID 到 ID 的 value 转移,以及从 ID 到地址的 value 转移。
function transferFrom(uint256 _fromTokenId, uint256 _toTokenId, uint256 _value) external payable;
function transferFrom(uint256 _fromTokenId, address _to, uint256 _value) external payable returns (uint256 toTokenId_);
第一个允许 value 从一个代币(由 _fromTokenId 指定)转移到同一 slot 中的另一个代币(由 _toTokenId 指定),从而导致从源代币的 value 中减去 _value 并将其添加到目标代币的 value 中;
第二个允许 value 从一个代币(由 _fromTokenId 指定)转移到一个地址(由 _to 指定),value 实际上被转移到该地址拥有的一个代币,并且应该返回目标代币的 id。有关此方法的更多说明,请参见“设计决策”部分。
规则
授权规则:
此 EIP 提供了四种授权功能,指示了不同级别的授权,可以描述为完全级别授权、slot 级别授权、代币 ID 级别授权以及 value 级别授权。
- 与 ERC-721 兼容的
setApprovalForAll应该指示完全级别的授权,这意味着授权的 operator 能够管理所有代币,包括它们的所有者拥有的 value。 setApprovalForSlot(可选)应该指示 slot 级别的授权,这意味着授权的 operator 能够管理所有具有指定 slot 的代币,包括它们的所有者拥有的 value。- 代币 ID 级别的
approve函数与 ERC-721 兼容,应该指示授权的 operator 只能管理指定的代币 ID,包括其所有者拥有的 value。 - value 级别的
approve函数应该指示授权的 operator 能够管理所有者拥有的指定代币的指定最大 value。 - 对于任何授权函数,调用者必须是所有者或已被授予更高级别的授权。
transferFrom 规则:
-
transferFrom(uint256 _fromTokenId, uint256 _toTokenId, uint256 _value)函数应该指示 value 从一个代币转移到另一个代币,并符合以下规则:- 除非
msg.sender是_fromTokenId的所有者、授权的 operator 或已被授权全部代币或至少其中_value的 operator,否则必须回退。 - 如果
_fromTokenId或_toTokenId为零代币 id 或不存在,则必须回退。 - 如果
_fromTokenId和_toTokenId的 slot 不匹配,则必须回退。 - 如果
_value超过_fromTokenId的 value 或其对 operator 的授权,则必须回退。 - 如果 _toTokenId 的所有者是一个智能合约,则必须检查
onERC3525Received函数,如果该函数存在,则必须在 value 转移后调用此函数,如果结果不等于 0x009ce20b,则必须回退; - 必须发出
TransferValue事件。
- 除非
-
transferFrom(uint256 _fromTokenId, address _to, uint256 _value)函数,该函数将 value 从一个代币 ID 转移到一个地址,应该遵循以下规则:- 必须找到地址
_to拥有的 ERC-3525 代币,或者创建一个新的 ERC-3525 代币,该代币具有与_fromTokenId相同的 slot,以接收转移的 value。 - 除非
msg.sender是_fromTokenId的所有者、授权的 operator 或已被授权全部代币或至少其中_value的 operator,否则必须回退。 - 如果
_fromTokenId为零代币 id 或不存在,则必须回退。 - 如果
_to为零地址,则必须回退。 - 如果
_value超过_fromTokenId的 value 或其对 operator 的授权,则必须回退。 - 如果 _to 地址是一个智能合约,则必须检查
onERC3525Received函数,如果该函数存在,则必须在 value 转移后调用此函数,如果结果不等于 0x009ce20b,则必须回退; - 必须发出
Transfer和TransferValue事件。
- 必须找到地址
元数据
元数据扩展
ERC-3525 元数据扩展与 ERC-721 元数据扩展兼容。
此可选接口可以通过 ERC-165 标准接口检测来识别。
pragma solidity ^0.8.0;
/**
* @title ERC-3525 Semi-Fungible Token Standard, optional extension for metadata
* @dev Interfaces for any contract that wants to support query of the Uniform Resource Identifier
* (URI) for the ERC-3525 contract as well as a specified slot.
* 用于任何想要支持查询 ERC-3525 合约以及指定 slot 的统一资源标识符 (URI) 的合约的接口。
* Because of the higher reliability of data stored in smart contracts compared to data stored in
* centralized systems, it is recommended that metadata, including `contractURI`, `slotURI` and
* `tokenURI`, be directly returned in JSON format, instead of being returned with a url pointing
* to any resource stored in a centralized system.
* 由于与存储在集中式系统中的数据相比,存储在智能合约中的数据具有更高的可靠性,因此建议以 JSON 格式直接返回元数据,包括 `contractURI`、`slotURI` 和 `tokenURI`,而不是返回指向存储在集中式系统中的任何资源的 URL。
* See https://eips.ethereum.org/EIPS/eip-3525
* Note: the ERC-165 identifier for this interface is 0xe1600902.
*/
interface IERC3525Metadata is
IERC3525 /* , IERC721Metadata */
{
/**
* @notice Returns the Uniform Resource Identifier (URI) for the current ERC-3525 contract.
* 返回当前 ERC-3525 合约的统一资源标识符 (URI)。
* @dev This function SHOULD return the URI for this contract in JSON format, starting with
* header `data:application/json;`.
* 此函数应该以 JSON 格式返回此合约的 URI,以 `data:application/json;` 标头开头。
* See https://eips.ethereum.org/EIPS/eip-3525 for the JSON schema for contract URI.
* @return The JSON formatted URI of the current ERC-3525 contract
*/
function contractURI() external view returns (string memory);
/**
* @notice Returns the Uniform Resource Identifier (URI) for the specified slot.
* 返回指定 slot 的统一资源标识符 (URI)。
* @dev This function SHOULD return the URI for `_slot` in JSON format, starting with header
* `data:application/json;`.
* 此函数应该以 JSON 格式返回 `_slot` 的 URI,以 `data:application/json;` 标头开头。
* See https://eips.ethereum.org/EIPS/eip-3525 for the JSON schema for slot URI.
* @return The JSON formatted URI of `_slot`
*/
function slotURI(uint256 _slot) external view returns (string memory);
}
ERC-3525 元数据 URI JSON 模式
这是上面引用的“contractURI() 的 ERC-3525 元数据 JSON 模式”。
{
"title": "合约元数据",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "合约名称"
},
"description": {
"type": "string",
"description": "描述合约"
},
"image": {
"type": "string",
"description": "可选。可以是 base64 编码的图像数据,也可以是指向具有 mime 类型 image/* 的资源的 URI,表示此合约所代表的内容。"
},
"external_link": {
"type": "string",
"description": "可选。指向外部资源的 URI。"
},
"valueDecimals": {
"type": "integer",
"description": "余额应显示的小数位数 - 例如,18 表示将代币 value 除以 1000000000000000000 以获得其用户表示形式。"
}
}
}
这是上面引用的“slotURI(uint) 的 ERC-3525 元数据 JSON 模式”。
{
"title": "Slot 元数据",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "标识此 slot 代表的资产类别"
},
"description": {
"type": "string",
"description": "描述此 slot 代表的资产类别"
},
"image": {
"type": "string",
"description": "可选。可以是 base64 编码的图像数据,也可以是指向具有 mime 类型 image/* 的资源的 URI,表示此 slot 代表的资产类别。"
},
"properties": {
"type": "array",
"description": "`properties` 的每个项目都应该以对象格式组织,包括名称、描述、value、order(可选)、display_type(可选)等。"
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "此属性的名称。"
},
"description": {
"type": "string",
"description": "描述此属性。"
}
"value": {
"description": "此属性的 value,可以是字符串或数字。"
},
"is_intrinsic": {
"type": "boolean",
"description": "根据 `slot` 的定义,生成 slot value 的最佳实践之一是利用 `keccak256` 算法来计算多个属性的哈希 value。在这种情况下,`properties` 字段应包含用于计算 `slot` value 的所有属性,并且如果在计算中使用了某个属性,则 is_intrinsic 必须为 TRUE。"
},
"order": {
"type": "integer",
"description": "可选,与 is_intrinsic 的 value 相关。如果 is_intrinsic 为 TRUE,则必须是此属性在 slot 的计算方法中出现的顺序。"
},
"display_type": {
"type": "string",
"description": "可选。指定应以何种形式显示此属性。"
}
}
}
}
}
}
这是上面引用的“tokenURI(uint) 的 ERC-3525 元数据 JSON 模式”。
{
"title": "代币元数据",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "标识此代币代表的资产"
},
"description": {
"type": "string",
"description": "描述此代币代表的资产"
},
"image": {
"type": "string",
"description": "可以是 base64 编码的图像数据,也可以是指向具有 mime 类型 image/* 的资源的 URI,表示此代币代表的资产。"
},
"balance": {
"type": "integer",
"description": "此代币持有的 value。"
},
"slot": {
"type": "integer",
"description": "此代币所属的 slot 的 ID。"
},
"properties": {
"type": "object",
"description": "任意属性。Value 可以是字符串、数字、对象或数组。可选,如果需要更好的描述属性,可以使用与 slotURI(uint) 的 ERC-3525 元数据 JSON 模式的 properties 部分相同的模式。"
}
}
}
原理
元数据生成
此代币标准旨在表示半同质化资产,这些资产最适合金融工具,而不是收藏品或游戏内物品。为了数字资产的最大透明度和安全性,我们强烈建议所有实现都直接从合约代码生成
Citation
Please cite this document as:
Will Wang (@will42w), Mike Meng