ERC-5773: Context-Dependent Multi-Asset Tokens

An interface for Multi-Asset tokens with context dependent asset type output controlled by owner's preference.


Metadata
Status: FinalStandards Track: ERCCreated: 2022-10-10
Authors
Bruno Škvorc (@Swader), Cicada (@CicadaNCR), Steven Pineda (@steven2308), Stevan Bogosavljevic (@stevyhacker), Jan Turk (@ThunderDeliverer)
Requires

Abstract


The Multi-Asset NFT standard allows for the construction of a new primitive: context-dependent output of information per single NFT.

The context-dependent output of information means that the asset in an appropriate format is displayed based on how the token is being accessed. I.e. if the token is being opened in an e-book reader, the PDF asset is displayed, if the token is opened in the marketplace, the PNG or the SVG asset is displayed, if the token is accessed from within a game, the 3D model asset is accessed and if the token is accessed by the (Internet of Things) IoT hub, the asset providing the necessary addressing and specification information is accessed.

An NFT can have multiple assets (outputs), which can be any kind of file to be served to the consumer, and orders them by priority. They do not have to match in mimetype or tokenURI, nor do they depend on one another. Assets are not standalone entities, but should be thought of as “namespaced tokenURIs” that can be ordered at will by the NFT owner, but only modified, updated, added, or removed if agreed on by both the owner of the token and the issuer of the token.

Motivation


With NFTs being a widespread form of tokens in the Ethereum ecosystem and being used for a variety of use cases, it is time to standardize additional utility for them. Having multiple assets associated with a single NFT allows for greater utility, usability and forward compatibility.

In the four years since ERC-721 was published, the need for additional functionality has resulted in countless extensions. This EIP improves upon ERC-721 in the following areas:

Cross-metaverse compatibility

At the time of writing this proposal, the metaverse is still a fledgling, not full defined, term. No matter how the definition of metaverse evolves, the proposal can support any number of different implementations.

Cross-metaverse compatibility could also be referred to as cross-engine compatibility. An example of this is where a cosmetic item for game A is not available in game B because the frameworks are incompatible.

Such NFT can be given further utility by means of new additional assets: more games, more cosmetic items, appended to the same NFT. Thus, a game cosmetic item as an NFT becomes an ever-evolving NFT of infinite utility.

The following is a more concrete example. One asset is a cosmetic item for game A, a file containing the cosmetic assets. Another is a cosmetic asset file for game B. A third is a generic asset intended to be shown in catalogs, marketplaces, portfolio trackers, or other generalized NFT viewers, containing a representation, stylized thumbnail, and animated demo/trailer of the cosmetic item.

This EIP adds a layer of abstraction, allowing game developers to directly pull asset data from a user's NFTs instead of hard-coding it.

Multi-media output

An NFT of an eBook can be represented as a PDF, MP3, or some other format, depending on what software loads it. If loaded into an eBook reader, a PDF should be displayed, and if loaded into an audiobook application, the MP3 representation should be used. Other metadata could be present in the NFT (perhaps the book's cover image) for identification on various marketplaces, Search Engine Result Pages (SERPs), or portfolio trackers.

Media redundancy

Many NFTs are minted hastily without best practices in mind - specifically, many NFTs are minted with metadata centralized on a server somewhere or, in some cases, a hardcoded IPFS gateway which can also go down, instead of just an IPFS hash.

By adding the same metadata file as different assets, e.g., one asset of a metadata and its linked image on Arweave, one asset of this same combination on Sia, another of the same combination on IPFS, etc., the resilience of the metadata and its referenced information increases exponentially as the chances of all the protocols going down at once become less likely.

NFT evolution

Many NFTs, particularly game related ones, require evolution. This is especially the case in modern metaverses where no metaverse is actually a metaverse - it is just a multiplayer game hosted on someone's server which replaces username/password logins with reading an account's NFT balance.

When the server goes down or the game shuts down, the player ends up with nothing (loss of experience) or something unrelated (assets or accessories unrelated to the game experience, spamming the wallet, incompatible with other “verses” - see cross-metaverse compatibility above).

With Multi-Asset NFTs, a minter or another pre-approved entity is allowed to suggest a new asset to the NFT owner who can then accept it or reject it. The asset can even target an existing asset which is to be replaced.

Replacing an asset could, to some extent, be similar to replacing an ERC-721 token's URI. When an asset is replaced a clear line of traceability remains; the old asset is still reachable and verifiable. Replacing an asset's metadata URI obscures this lineage. It also gives more trust to the token owner if the issuer cannot replace the asset of the NFT at will. The propose-accept asset replacement mechanic of this proposal provides this assurance.

This allows level-up mechanics where, once enough experience has been collected, a user can accept the level-up. The level-up consists of a new asset being added to the NFT, and once accepted, this new asset replaces the old one.

As a concrete example, think of Pokemon™️ evolving - once enough experience has been attained, a trainer can choose to evolve their monster. With Multi-Asset NFTs, it is not necessary to have centralized control over metadata to replace it, nor is it necessary to airdrop another NFT into the user's wallet - instead, a new Raichu asset is minted onto Pikachu, and if accepted, the Pikachu asset is gone, replaced by Raichu, which now has its own attributes, values, etc.

Alternative example of this, could be version control of an IoT device's firmware. An asset could represent its current firmware and once an update becomes available, the current asset could be replaced with the one containing the updated firmware.

Specification


The key words “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.


The getAssetMetadata function returns the asset's metadata URI. The metadata, to which the metadata URI of the asset points, MAY contain a JSON response with the following fields:


While this is the suggested JSON schema for the asset metadata, it is not enforced and MAY be structured completely differently based on implementer's preference.

Rationale


Designing the proposal, we considered the following questions:

  1. Should we use Asset or Resource when referring to the structure that comprises the token?
    The original idea was to call the proposal Multi-Resource, but while this denoted the broadness of the structures that could be held by a single token, the term asset represents it better.
    An asset is defined as something that is owned by a person, company, or organization, such as money, property, or land. This is the best representation of what an asset of this proposal can be. An asset in this proposal can be a multimedia file, technical information, a land deed, or anything that the implementer has decided to be an asset of the token they are implementing.
  2. Why are EIP-712 permit-style signatures to manage approvals not used?
    For consistency. This proposal extends ERC-721 which already uses 1 transaction for approving operations with tokens. It would be inconsistent to have this and also support signing messages for operations with assets.
  3. Why use indexes?
    To reduce the gas consumption. If the asset ID was used to find which asset to accept or reject, iteration over arrays would be required and the cost of the operation would depend on the size of the active or pending assets arrays. With the index, the cost is fixed. A list of active and pending assets arrays per token need to be maintained, since methods to get them are part of the proposed interface.
    To avoid race conditions in which the index of an asset changes, the expected asset ID is included in operations requiring asset index, to verify that the asset being accessed using the index is the expected asset.
    Implementation that would internally keep track of indices using mapping was attempted. The average cost of adding an asset to a token increased by over 25%, costs of accepting and rejecting assets also increased 4.6% and 7.1% respectively. We concluded that it is not necessary for this proposal and can be implemented as an extension for use cases willing to accept this cost. In the sample implementation provided, there are several hooks which make this possible.
  4. Why is a method to get all the assets not included?
    Getting all assets might not be an operation necessary for all implementers. Additionally, it can be added either as an extension, doable with hooks, or can be emulated using an indexer.
  5. Why is pagination not included?
    Asset IDs use uint64, testing has confirmed that the limit of IDs you can read before reaching the gas limit is around 30.000. This is not expected to be a common use case so it is not a part of the interface. However, an implementer can create an extension for this use case if needed.
  6. How does this proposal differ from the other proposals trying to address a similar problem?
    After reviewing them, we concluded that each contains at least one of these limitations:
    • Using a single URI which is replaced as new assets are needed, this introduces a trust issue for the token owner.
    • Focusing only on a type of asset, while this proposal is asset type agnostic.
    • Having a different token for each new use case, this means that the token is not forward-compatible.

Multi-Asset Storage Schema

Assets are stored within a token as an array of uint64 identifiers.

In order to reduce redundant on-chain string storage, multi asset tokens store assets by reference via inner storage. An asset entry on the storage is stored via a uint64 mapping to asset data.

An asset array is an array of these uint64 asset ID references.

Such a structure allows that, a generic asset can be added to the storage one time, and a reference to it can be added to the token contract as many times as we desire. Implementers can then use string concatenation to procedurally generate a link to a content-addressed archive based on the base SRC in the asset and the token ID. Storing the asset in a new token will only take 16 bytes of storage in the asset array per token for recurrent as well as tokenId dependent assets.

Structuring token's assets in such a way allows for URIs to be derived programmatically through concatenation, especially when they differ only by tokenId.

Propose-Commit pattern for asset addition

Adding assets to an existing token MUST be done in the form of a propose-commit pattern to allow for limited mutability by a 3rd party. When adding an asset to a token, it is first placed in the "Pending" array, and MUST be migrated to the "Active" array by the token's owner. The "Pending" assets array SHOULD be limited to 128 slots to prevent spam and griefing.

Asset management

Several functions for asset management are included. In addition to permissioned migration from "Pending" to "Active", the owner of a token MAY also drop assets from both the active and the pending array -- an emergency function to clear all entries from the pending array MUST also be included.

Backwards Compatibility


The MultiAsset token standard has been made compatible with ERC-721 in order to take advantage of the robust tooling available for implementations of ERC-721 and to ensure compatibility with existing ERC-721 infrastructure.

Test Cases


Tests are included in multiasset.ts.

To run them in terminal, you can use the following commands:


Reference Implementation


See MultiAssetToken.sol.

Security Considerations


The same security considerations as with ERC-721 apply: hidden logic may be present in any of the functions, including burn, add asset, accept asset, and more.

Caution is advised when dealing with non-audited contracts.

Copyright


Copyright and related rights waived via CC0.