ERC-3475: Abstract Storage Bonds
Interface for creating tokenized obligations with abstract on-chain metadata storage
Abstract
-
This EIP allows the creation of tokenized obligations with abstract on-chain metadata storage. Issuing bonds with multiple redemption data cannot be achieved with existing token standards.
-
This EIP enables each bond class ID to represent a new configurable token type and corresponding to each class, corresponding bond nonces to represent an issuing condition or any other form of data in uint256. Every single nonce of a bond class can have its metadata, supply, and other redemption conditions.
-
Bonds created by this EIP can also be batched for issuance/redemption conditions for efficiency on gas costs and UX side. And finally, bonds created from this standard can be divided and exchanged in a secondary market.
Motivation
Current LP (Liquidity Provider) tokens are simple EIP-20 tokens with no complex data structure. To allow more complex reward and redemption logic to be stored on-chain, we need a new token standard that:
- Supports multiple token IDs
- Can store on-chain metadata
- Doesn't require a fixed storage pattern
- Is gas-efficient.
Also Some benefits:
- This EIP allows the creation of any obligation with the same interface.
- It will enable any 3rd party wallet applications or exchanges to read these tokens' balance and redemption conditions.
- These bonds can also be batched as tradeable instruments. Those instruments can then be divided and exchanged in secondary markets.
Specification
Definition
Bank: an entity that issues, redeems, or burns bonds after getting the necessary amount of liquidity. Generally, a single entity with admin access to the pool.
Functions
Events
Metadata: The metadata of a bond class or nonce is stored as an array of JSON objects, represented by the following types.
NOTE: all of the metadata schemas are referenced from here
1. Description:
This defines the additional information about the nature of data being stored in the nonce/class metadata structures. They are defined using the structured explained here. this will then be used by the frontend of the respective entities participating in the bond markets to interpret the data which is compliant with their jurisdiction.
2. Nonce:
The key value for indexing the information is the 'class' field. Following are the rules:
- The title can be any alphanumeric type that is differentiated by the description of metadata (although it can be dependent on certain jurisdictions).
- The title SHOULD not be EMPTY.
Some specific examples of metadata can be the localization of bonds, jurisdiction details etc., and they can be found in the metadata.md example description.
3. Class metadata:
This structure defines the details of the class information (symbol, risk information, etc.). the example is explained here in the class metadata section.
4. Decoding data
First, the functions for analyzing the metadata (i.e ClassMetadata
and NonceMetadata
) are to be used by the corresponding frontend to decode the information of the bond.
This is done via overriding the function interface for functions classValues
and nonceValues
by defining the key (which SHOULD be an index) to read the corresponding information stored as a JSON object.
e.g. In the above example, to get the symbol
of the given class id, we can use the class id as a key to get the symbol
value in the values, which then can be used for fetching the detail for instance.
Rationale
Metadata structure
Instead of storing the details about the class and their issuances to the user (ie nonce) externally, we store the details in the respective structures. Classes represent the different bond types, and nonces represent the various period of issuances. Nonces under the same class share the same metadata. Meanwhile, nonces are non-fungible. Each nonce can store a different set of metadata. Thus, upon transfer of a bond, all the metadata will be transferred to the new owner of the bond.
Batch function
This EIP supports batch operations. It allows the user to transfer different bonds along with their metadata to a new address instantaneously in a single transaction. After execution, the new owner holds the right to reclaim the face value of each of the bonds. This mechanism helps with the "packaging" of bonds–helpful in use cases like trades on a secondary market.
Where:
The classId
is the class id of the bond.
The nonceId
is the nonce id of the given bond class. This param is for distinctions of the issuing conditions of the bond.
The _amount
is the amount of the bond for which the spender is approved.
AMM optimization
One of the most obvious use cases of this EIP is the multilayered pool. The early version of AMM uses a separate smart contract and an EIP-20 LP token to manage a pair. By doing so, the overall liquidity inside of one pool is significantly reduced and thus generates unnecessary gas spent and slippage. Using this EIP standard, one can build a big liquidity pool with all the pairs inside (thanks to the presence of the data structures consisting of the liquidity corresponding to the given class and nonce of bonds). Thus by knowing the class and nonce of the bonds, the liquidity can be represented as the percentage of a given token pair for the owner of the bond in the given pool. Effectively, the EIP-20 LP token (defined by a unique smart contract in the pool factory contract) is aggregated into a single bond and consolidated into a single pool.
- The reason behind the standard's name (abstract storage bond) is its ability to store all the specifications (metadata/values and transaction as defined in the following sections) without needing external storage on-chain/off-chain.
Backwards Compatibility
Any contract that inherits the interface of this EIP is compatible. This compatibility exists for issuer and receiver of the bonds. Also any client EOA wallet can be compatible with the standard if they are able to sign issue()
and redeem()
commands.
However, any existing EIP-20 token contract can issue its bonds by delegating the minting role to a bank contract with the interface of this standard built-in. Check out our reference implementation for the correct interface definition.
To ensure the indexing of transactions throughout the bond lifecycle (i.e "Issue", "Redeem" and "Transfer" functions), events cited in specification section MUST be emitted when such transaction is passed.
Note that the this standard interface is also compatible with EIP-20 and EIP-721 and EIP-1155interface.
However, creating a separate bank contract is recommended for reading the bonds and future upgrade needs.
Acceptable collateral can be in the form of fungible (like EIP-20), non-fungible (EIP-721, EIP-1155) , or other bonds represented by this standard.
Test Cases
Test-case for the minimal reference implementation is here. Use the Truffle box to compile and test the contracts.
Reference Implementation
-
- This demonstration shows only minimalist implementation.
Security Considerations
-
The
function setApprovalFor(address _operatorAddress)
gives the operator role to_operatorAddress
. It has all the permissions to transfer, burn and redeem bonds by default. -
If the owner wants to give a one-time allocation to an address for specific bonds(classId,bondsId), he should call the
function approve()
giving theTransaction[]
allocated rather than approving all the classes usingsetApprovalFor
.
Copyright
Copyright and related rights waived via CC0.