ERC-3525: Semi-Fungible Token
Defines a specification where ERC-721 compatible tokens with the same SLOT and different IDs are fungible.
Abstract
This is a standard for semi-fungible tokens. The set of smart contract interfaces described in this document defines an ERC-721 compatible token standard. This standard introduces an <ID, SLOT, VALUE>
triple scalar model that represents the semi-fungible structure of a token. It also introduces new transfer models as well as approval models that reflect the semi-fungible nature of the tokens.
Token contains an ERC-721 equivalent ID property to identify itself as a universally unique entity, so that the tokens can be transferred between addresses and approved to be operated in ERC-721 compatible way.
Token also contains a value
property, representing the quantitative nature of the token. The meaning of the 'value' property is quite like that of the 'balance' property of an ERC-20 token. Each token has a 'slot' attribute, ensuring that the value of two tokens with the same slot be treated as fungible, adding fungibility to the value property of the tokens.
This EIP introduces new token transfer models for semi-fungibility, including value transfer between two tokens of the same slot and value transfer from a token to an address.
Motivation
Tokenization is one of the most important trends by which to use and control digital assets in crypto. Traditionally, there have been two approaches to do so: fungible and non-fungible tokens. Fungible tokens generally use the ERC-20 standard, where every unit of an asset is identical to each other. ERC-20 is a flexible and efficient way to manipulate fungible tokens. Non-fungible tokens are predominantly ERC-721 tokens, a standard capable of distinguishing digital assets from one another based on identity.
However, both have significant drawbacks. For example, ERC-20 requires that users create a separate ERC-20 contract for each individual data structure or combination of customizable properties. In practice, this results in an extraordinarily large amount of ERC-20 contracts that need to be created. On the other hand, ERC-721 tokens provide no quantitative feature, significantly undercutting their computability, liquidity, and manageability. For example, if one was to create financial instruments such as bonds, insurance policy, or vesting plans using ERC-721, no standard interfaces are available for us to control the value in them, making it impossible, for example, to transfer a portion of the equity in the contract represented by the token.
A more intuitive and straightforward way to solve the problem is to create a semi-fungible token that has the quantitative features of ERC-20 and qualitative attributes of ERC-721. The backwards-compatibility with ERC-721 of such semi-fungible tokens would help utilize existing infrastructures already in use and lead to faster adoption.
Specification
The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Every ERC-3525 compliant contract must implement the ERC-3525, ERC-721 and ERC-165 interfaces
The slot's enumeration extension is OPTIONAL. This allows your contract to publish its full list of SLOT
s and make them discoverable.
The slot level approval is OPTIONAL. This allows any contract that wants to support approval for slots, which allows an operator to manage one's tokens with the same slot.
ERC-3525 Token Receiver
If a smart contract wants to be informed when they receive values from other addresses, it should implement all of the functions in the IERC3525Receiver
interface, in the implementation it can decide whether to accept or reject the transfer. See "Transfer Rules" for further detail.
Token Manipulation
Scenarios
Transfer:
Besides ERC-721 compatible token transfer methods, this EIP introduces two new transfer models: value transfer from ID to ID, and value transfer from ID to address.
The first one allows value transfers from one token (specified by _fromTokenId
) to another token (specified by _toTokenId
) within the same slot, resulting in the _value
being subtracted from the value of the source token and added to the value of the destination token;
The second one allows value transfers from one token (specified by _fromTokenId
) to an address (specified by _to
), the value is actually transferred to a token owned by the address, and the id of the destination token should be returned. Further explanation can be found in the 'design decision' section for this method.
Rules
approving rules:
This EIP provides four kinds of approving functions indicating different levels of approvals, which can be described as full level approval, slot level approval, token ID level approval as well as value level approval.
setApprovalForAll
, compatible with ERC-721, SHOULD indicate the full level of approval, which means that the authorized operators are capable of managing all the tokens, including their values, owned by the owner.setApprovalForSlot
(optional) SHOULD indicate the slot level of approval, which means that the authorized operators are capable of managing all the tokens with the specified slot, including their values, owned by the owner.- The token ID level
approve
function, compatible with ERC-721, SHOULD indicate that the authorized operator is capable of managing only the specified token ID, including its value, owned by the owner. - The value level
approve
function, SHOULD indicate that the authorized operator is capable of managing the specified maximum value of the specified token owned by the owner. - For any approving function, the caller MUST be the owner or has been approved with a higher level of authority.
transferFrom rules:
-
The
transferFrom(uint256 _fromTokenId, uint256 _toTokenId, uint256 _value)
function, SHOULD indicate value transfers from one token to another token, in accordance with the rules below:- MUST revert unless
msg.sender
is the owner of_fromTokenId
, an authorized operator or an operator who has been approved the whole token or at least_value
of it. - MUST revert if
_fromTokenId
or_toTokenId
is zero token id or does not exist. - MUST revert if slots of
_fromTokenId
and_toTokenId
do not match. - MUST revert if
_value
exceeds the value of_fromTokenId
or its allowance to the operator. - MUST check for the
onERC3525Received
function if the owner of _toTokenId is a smart contract, if the function exists, MUST call this function after the value transfer, MUST revert if the result is not equal to 0x009ce20b; - MUST emit
TransferValue
event.
- MUST revert unless
-
The
transferFrom(uint256 _fromTokenId, address _to, uint256 _value)
function, which transfers value from one token ID to an address, SHOULD follow the rule below:- MUST either find a ERC-3525 token owned by the address
_to
or create a new ERC-3525 token, with the same slot of_fromTokenId
, to receive the transferred value. - MUST revert unless
msg.sender
is the owner of_fromTokenId
, an authorized operator or an operator who has been approved the whole token or at least_value
of it. - MUST revert if
_fromTokenId
is zero token id or does not exist. - MUST revert if
_to
is zero address. - MUST revert if
_value
exceeds the value of_fromTokenId
or its allowance to the operator. - MUST check for the
onERC3525Received
function if the _to address is a smart contract, if the function exists, MUST call this function after the value transfer, MUST revert if the result is not equal to 0x009ce20b; - MUST emit
Transfer
andTransferValue
events.
- MUST either find a ERC-3525 token owned by the address
Metadata
Metadata Extensions
ERC-3525 metadata extensions are compatible ERC-721 metadata extensions.
This optional interface can be identified with the ERC-165 Standard Interface Detection.
ERC-3525 Metadata URI JSON Schema
This is the "ERC-3525 Metadata JSON Schema for contractURI()
" referenced above.
This is the "ERC-3525 Metadata JSON Schema for slotURI(uint)
" referenced above.
This is the "ERC-3525 Metadata JSON Schema for tokenURI(uint)
" referenced above.
Rationale
Metadata generation
This token standard is designed to represent semi-fungible assets, which are most suited for financial instruments rather than collectibles or in-game items. For maximum transparency and safety of digital assets, we strongly recommend that all implementations should generate metadata directly from contract code rather than giving out an off-chain server URL.
Design decision: Value transfer from token to address
The 'value' of a token is a property of the token and is not linked to an address, so to transfer the value to an address would be actually transferring it to a token owned by that address, not the address itself.
From the implementation perspective, the process of transferring values from token to address could be done as follows: (1) create a new token for the recipient's address, (2) transfer the value to the new token from the 'source token'. So that this method is not fully independent from the ID-to-ID transfer method, and can be viewed as syntactic sugar that wraps the process described above.
In a special case, if the destination address owns one or more tokens with the same slot value as the source token, this method will have an alternative implementation as follows: (1) find one token owned by the address with the same slot value of the source token, (2) transfer the value to the found token.
Both implementations described above should be treated as compliant with this standard.
The purpose of maintaining id-to-address transfer function is to maximize the compatibility with most wallet apps, since for most of the token standards, the destination of token transfer are addresses. This syntactic wrapping will help wallet apps easily implement the value transfer function from a token to any address.
Design decision: Notification/acceptance mechanism instead of 'Safe Transfer'
ERC-721 and some later token standards introduced 'Safe Transfer' model, for better control of the 'safety' when transferring tokens, this mechanism leaves the choice of different transfer modes (safe/unsafe) to the sender, and may cause some potential problems:
- In most situations the sender does not know how to choose between two kinds of transfer methods (safe/unsafe);
- If the sender calls the
safeTransferFrom
method, the transfer may fail if the recipient contract did not implement the callback function, even if that contract is capable of receiving and manipulating the token without issue.
This EIP defines a simple 'Check, Notify and Response' model for better flexibility as well as simplicity:
- No extra
safeTransferFrom
methods are needed, all callers only need to call one kind of transfer; - All ERC-3525 contracts MUST check for the existence of
onERC3525Received
on the recipient contract and call the function when it exists; - Any smart contract can implement
onERC3525Received
function for the purpose of being notified after receiving values; this function MUST return 0x009ce20b (i.e.bytes4(keccak256('onERC3525Received(address,uint256,uint256,uint256,bytes)'))
) if the transfer is accepted, or any other value if the transfer is rejected.
There is a special case for this notification/acceptance mechanism: since ERC-3525 allows value transfer from an address to itself, when a smart contract which implements onERC3525Received
transfers value to itself, onERC3525Received
will also be called. This allows for the contract to implement different rules of acceptance between self-value-transfer and receiving value from other addresses.
Design decision: Relationship between different approval models
For semantic compatibility with ERC-721 as well as the flexibility of value manipulation of tokens, we decided to define the relationships between some of the levels of approval like that:
- Approval of an id will lead to the ability to partially transfer values from this id by the approved operator; this will simplify the value approval for an id. However, the approval of total values in a token should not lead to the ability to transfer the token entity by the approved operator.
setApprovalForAll
will lead to the ability to partially transfer values from any token, as well as the ability to approve partial transfer of values from any token to a third party; this will simplify the value transfer and approval of all tokens owned by an address.
Backwards Compatibility
As mentioned in the beginning, this EIP is backward compatible with ERC-721.
Reference Implementation
Security Considerations
The value level approval and slot level approval (optional) is isolated from ERC-721 approval models, so that approving value should not affect ERC-721 level approvals. Implementations of this EIP must obey this principle.
Since this EIP is ERC-721 compatible, any wallets and smart contracts that can hold and manipulate standard ERC-721 tokens will have no risks of asset loss for ERC-3525 tokens due to incompatible standards implementations.
Copyright
Copyright and related rights waived via CC0.