Endless Digital Asset Standard
Last updated
Last updated
An is a non-fungible or data stored on a blockchain that uniquely defines ownership of an asset. NFTs were first defined in and later expanded upon in . NFTs are typically defined using the following properties:
name
: The name of the asset. It must be unique within a collection.
description
: The description of the asset.
uri
: A URL pointer to off-chain for more information about the asset. The asset could be media such as an image or video or more metadata.
supply
: The total number of units of this NFT. Many NFTs have only a single supply, while those that have more than one are referred to as editions.
Additionally, most NFTs are part of a collection or a set of NFTs with a common attribute, for example, a theme, creator, or minimally contract. Each collection has a similar set of attributes:
name
: The name of the collection. The name must be unique within the creator's account.
description
: The description of the collection.
uri
: A URL pointer to off-chain for more information about the asset. The asset could be media such as an image or video or more metadata.
supply
: The total number of NFTs in this collection.
maximum
: The maximum number of NFTs that this collection can have. If maximum
is set to 0, then supply is not tracked.
The was developed with the following as an improvement on the Endless Token standard. It has these ideas in mind:
Flexibility - NFTs are flexible and can be customized to accommodate any creative designs.
Composability - Multiple NFTs can be easily composed together, such that the final object is greater than the sum of its parts
Scalability - Greater parallelism between tokens
The base token only provides minimal functionalities and is meant to build upon to add more functionalities. All of its functions are non-entry and thus not callable directly from off chain. Creators need to write their own modules that use these functionalities or use "no code" solutions also provided in the framework. One such solution is endless_token which provides functionalities such as custom metadata (via PropertyMap) and soul bound.
Tokens can be easily extended with custom data and functionalities without requiring any changes in the framework
Transfers are simply a reference update
Direct transfer is allowed without an opt-in
NFTs can own other NFTs adding easy composability
Soul bound tokens can be easily supported
In this Token standard, both collections and tokens will be separate objects. They have their own distinct addresses and can be referenced both on and off chain by address. Each object can contain multiple resources so collections and tokens are extensible by default, allowing the creator to add custom data and functionalities without having to modify the framework.
On chain, another struct can include a reference to the collection or token objects like below:
where both my_collection
and my_token
are addresses (with Object<>
wrapper).
Off-chain, the address of the object can be passed along to replace object arguments in entry functions called by transaction creation. as arguments. For example:
Collection and token addresses will also be used to query data such as fetching all resources via fullnode API or against an indexing service.
See Endless Token for examples on how Royalty's MutatorRef
can be stored and used. Royalty can also be set directly on a token if it has a different royalty config than the collection's.
All Digital Asset modules are deployed at the reserved framework address 0x4
.
Every token belongs to a collection. The developer first needs to create a collection with:
A fixed maximum supply. Current supply is tracked and cannot exceed the maximum set.
Unlimited supply. Current supply is still tracked but there's no maximum enforced.
Note that both track the current supply. Maximum supply cannot be changed after the collection is created, and a collection cannot be converted from unlimited to fixed supply or vice versa.
A collection has the following attributes:
Collection name - unique within each account. This means a single creator account cannot create more than one collection with the same name.
Description - modifiable with a MutatorRef
and smaller than 2048 characters
URI length - modifiable with a MutatorRef
and smaller than 512 characters
Royalty - specifies how many % of the sale price goes to the creator of the collection. This can be changed with a MutatorRef
generated by the Royalty module.
A MutatorRef
, a storable struct that grants permissions to mutate, can be generated only during creation of the collection. If created, the holder of the MutatorRef
can change the description
and the URI length
of the collection.
A collection can be customized by adding more data (as resources) or functionalities. For example, a collection can track when it was created in order to limit when tokens can be minted.
Creators can mint tokens, which are separate objects from the collection. This allows for greater customization. Tokens can be created in two ways:
Named tokens. These tokens have deterministic addresses that are sha256 hash of the creator address, collection name, and token name, concatenated. This allows for predictable addresses and easier querying of tokens. However, named tokens are fully deletable and thus burning them will only delete the token data and not fully delete the underlying object
(Unnamed) tokens based on the creator account's GUID. These tokens have addresses are generated based on the creator account's incrementing GUID. The addresses of unnamed tokens are not deterministic as the account's GUID can change outside minting. Thus, querying for unnamed tokens is more difficult and requires indexing.
Creators should cautiously consider whether they should use create_named_token
or create
when building their custom collection/token. In general create
is recommended as it allows for clean deletion if the tokens are burnt and generally, deterministic addresses for tokens are not always necessary thanks to indexing services. One example that would prefer deterministic addresses and thus create_named_token
is a collection of soul bound tokens where each token's address is created from the holder's name.
Tokens by default have the following properties:
Token name - unique within each collection. A collection cannot have more than one token with the same name.
Token description - modifiable with a MutatorRef
and smaller than 2048 characters
Token URI length - modifiable with a MutatorRef
and smaller than 512 characters
Royalty - It's less common to have royalty setting on the token instead of collection. But this allows a token to have a different royalty setting than the collection's.
A MutatorRef
can be generated only during creation of the token.
More data can be added to the token as resources, similar to for collections.
Tokens can be burned by the creator if they generated and stored a BurnRef
during the creation of the token.
Note that if any custom data was added to the token objects, the burn_token
function needs to first remove those data. token::burn only deletes the object if it was created as an unnamed token. Named token will have all token data removed, but the object will stay, thus creating a "burned" defunct object.
Tokens can be simply transferred as objects to any user via object::transfer
Soul bound tokens which are non-transferable by holders
Custom defined properties stored in a PropertyMap, a simple map data structure of attribute name (string) -> values (bytes).
Freezing and unfreezing transfers of non-soul bound tokens
Creator management functionalities - modify a collection or token's metadata
Tokens can be minted using the provided endless_token::mint
. This is an entry function and can be called via a transaction directly.
To mint a soul bound token, the creator can call endless_token::mint_soul_bound
instead. This will create a token that the holder cannot transfer.
By default, the creator can do the following:
Mint and burn tokens, including soul bound tokens
Disallow transferring a token (freeze) and allow transferring a token (unfreeze)
Update the collection's description and URI
Add/Remove metadata properties from a token's property map
Update a collection's royalty setting
Update a token's name, description and URI
Endless Token is provided as a "no code" convenient solution, but it's not extensible. This is evident as most functions are entry functions and do not return any ref (constructor, mutator, etc.). The endless_token
module stores and manages the refs obtained from creating the collection and token objects and do not expose raw access to them.
If a creator wants more custom functionalities such as being able to forcefully transfer a soul bound token, they would need to write their own custom module that builds on top of the base Endless Digital Asset Standard. They can of course borrow inspiration and code from the Endless Token module.
This can be easily built by creating an asset that is both a Digital Asset (DA) and a Fungible Asset (FA), resulting in a Digital and Fungible Asset (DFA). After the creator creates the Armor collection and the Wooden Armor token, they can make the Wooden Armor token "fungible":
Now the creator can mint multiple instances of the same armor type and transfer them to players. The players can freely transfer the armor tokens to each other the same way they would transfer a fungible asset.
Digital Asset uses Endless rather than account resources traditionally used in Move. This allows for storing data outside the account and adding flexibility in this way.
Following the object extensibility pattern, royalties are added to collections or tokens as a resource with associated functionality provided by Royalty can be updated as long as a MutatorRef
, a storable struct that grants permissions, is generated at creation time and stored.
Endless is a "no code" solution that builds on top of the base Endless Digital Asset Standard and provides a more complete solution that allows creators to mint NFTs without writing any code. It provides the following main features:
Similar to in Token Standard v1, Endless Token provides an extensible that provides type safe, but generic properties for a given NFT. Creators can set pass initial properties when minting a token and can freely add or remove properties later.
Similar to , the Endless Digital Asset Standard also supports fungible tokens (also known as semi-fungible tokens). An example of this would be armor tokens in a game. Each armor token represents a type of armor and is a token in a collection with metadata (e.g. durability, defense, etc.) and can be minted and burned. However, there are multiple instances of the same armor type. For example, a player can have 3 wooden armors, where wooden armor is a token in the Armor collection.