Estándar de Activo Digital de Aptos
El estándar de Activo Digital (DA) es un estándar moderno de Token No Fungible (NFT) para Aptos. Los NFTs representan activos únicos en la cadena, y se almacenan en colecciones. Estos NFTs pueden ser personalizados para luego ser transferidos, vinculados al alma, quemados, mutados, o personalizados vía tus propios contratos inteligentes.
Este estándar reemplaza el legado Estándar de Token de Aptos. Las mejoras más importantes a notar son:
Mejora | Descripción |
---|---|
Extensión de Token | Los tokens pueden ser fácilmente extendidos ya que están implementados usando Objetos de Move. |
Transferencia Directa de NFT | Ahora puedes transferir NFTs directamente sin que el receptor “opte-in” en la cadena. |
Composabilidad de NFT | Los NFTs pueden poseer otros NFTs para fácil composabilidad. |
Si quieres una forma simple de acuñar NFTs sin la capacidad de personalizar o extender su funcionalidad, puedes usar el módulo aptos_token
que implementa el estándar DA (ve la sección sobre cómo usarlo abajo).
Usando el Estándar de Activo Digital
Sección titulada «Usando el Estándar de Activo Digital»Este estándar está implementado con dos Objetos:
Collection
s - Un conjunto de NFTs con un nombre y un poco de contexto para el grupo.Token
s - Activos digitales que representan activos únicos. Estos a menudo se usan para representar NFTs y usualmente usan un enlaceuri
para apuntar a más información sobre el activo (ej. un enlace a una imagen, video, etc.).
Todos los Token
s están requeridos a tener una referencia a una Collection
padre, pero la Collection
padre no posee el Token
. Los Token
s recién acuñados usualmente son poseídos por el creador. Desde ahí, pueden ser transferidos a otras cuentas.
Colecciones
Sección titulada «Colecciones»Campo | Descripción |
---|---|
Description | Una cadena opcional más pequeña que 2048 caracteres (modificable con un MutatorRef ). |
Name | Una cadena requerida para identificar la Collection . El nombre debe ser único dentro de cada cuenta. Eso significa que una sola cuenta creadora no puede crear más de una Collection con el mismo nombre. |
Royalty | Una estructura Royalty opcional que indica qué % del precio de venta va al creador de la Collection . Esto puede ser cambiado con un MutatorRef generado por el módulo Royalty. El módulo Royalty es una extensión para el estándar DA. Ve ejemplo de uso en aptos_token.move . |
URI length | Una cadena opcional que es más pequeña que 512 caracteres que enlaza a contenido relevante para la Collection (modificable con un MutatorRef ). |
Creando una Collection
Sección titulada «Creando una Collection»Hay dos formas de crear una Collection
dependiendo de si quieres que haya un suministro máximo de Token
s que puede contener.
Suministro Máximo Fijo
Sección titulada «Suministro Máximo Fijo»Para hacer una Collection
con un suministro fijo puedes usar collection::create_fixed_collection
así:
use aptos_token_objects::collection;use std::option::{Self, Option};use aptos_framework::string;
public entry fun create_collection(creator: &signer) { let max_supply = 1000; let royalty = option::none();
// El suministro máximo no puede ser cambiado después de la creación de la colección collection::create_fixed_collection( creator, string::utf8(b"Mi Descripción de Colección"), max_supply, string::utf8(b"Mi Colección"), royalty, string::utf8(b"https://mycollection.com"), );}
Suministro Ilimitado
Sección titulada «Suministro Ilimitado»Para crear una Collection
con suministro ilimitado puedes usar collection::create_unlimited_collection
:
use std::option::{Self, Option};use aptos_framework::string;
public entry fun create_collection(creator: &signer) { let royalty = option::none();
collection::create_unlimited_collection( creator, string::utf8(b"Mi Descripción de Colección"), string::utf8(b"Mi Colección"), royalty, string::utf8(b"https://mycollection.com"), );}
Customizing a Collection
Sección titulada «Customizing a Collection»Since each Collection
is a Move Object, you can customize it by generating permissions called Ref
s. Each Ref
allows you to modify an aspect of the Object later on. Beyond the normal Object Refs, Collection
s can also get a MutatorRef
by calling get_mutator_ref
like so:
use std::option::{Self, Option};use aptos_framework::string;
public entry fun create_collection(creator: &signer) { let royalty = option::none(); let collection_constructor_ref = &collection::create_unlimited_collection( creator, string::utf8(b"My Collection Description"), string::utf8(b"My Collection"), royalty, string::utf8(b"https://mycollection.com"), ); let mutator_ref = collection::get_mutator_ref(collection_constructor_ref); // Store the mutator ref somewhere safe}
You can further customize your Collection
by adding more resources or functionalities via smart contract. For example, a Collection
can track when it was created in order to limit when Token
s can be minted like so:
use std::option::{Self, Option};use aptos_framework::string;
struct MyCollectionMetadata has key { creation_timestamp_secs: u64,}
public entry fun create_collection(creator: &signer) { let royalty = option::none(); // Constructor ref is a non-storable struct returned when creating a new object. // It can generate an object signer to add resources to the collection object. let collection_constructor_ref = &collection::create_unlimited_collection(creator, string::utf8(b"My Collection Description"), string::utf8(b"My Collection"), royalty, string::utf8(b"https://mycollection.com"), ); // Constructor ref can be exchanged for signer to add resources to the collection object. let collection_signer = &object::generate_signer(collection_constructor_ref); move_to(collection_signer, MyCollectionMetadata { creation_timestamp_secs: timestamp::now_seconds() } })}
Field | Description |
---|---|
Description | An optional string smaller than 2048 characters (modifiable with a MutatorRef ). |
Name | A required string to identify the Collection that is unique within each Collection . This means a single Collection account cannot have more than one Token with the same name. |
Royalty | An optional Royalty struct indicating what % of the sale price goes to the creator of the Collection . This can be changed with a MutatorRef generated by the Royalty module (an extension for the DA standard. See example usage in aptos_token.move ). Usually royalty is set on collections, but setting it on Token s allows the individual Token to have a custom royalty amount. |
URI length | An optional string that is smaller than 512 characters which links to relevant content for the Collection (modifiable with a MutatorRef ). |
Creating Tokens
Sección titulada «Creating Tokens»There are a few ways to create a Token
:
- Named tokens. These use the name of the
Token
to generate a named Object. This makes it easy to find the address for the token if you know the token andCollection
name, but named Objects are not deletable. Trying to delete the a named token will only delete the data, not the Object itself.
use aptos_token_objects::token;use std::option::{Self, Option};
public entry fun mint_token(creator: &signer) { let royalty = option::none(); token::create_named_token( creator, "Collection Name", "Description", "Token Name", royalty, "https://mycollection.com/my-named-token.jpeg", );}
- “Unnamed” tokens. These create unnamed Objects (which are deletable) but still have a
Token
name. Because the Object address is not deterministic, you must use an Indexer to find the address for them.
use aptos_token_objects::token;use std::option::{Self, Option};use aptos_framework::string;
public entry fun mint_token(creator: &signer) { let royalty = option::none(); token::create( creator, string::utf8(b"Collection Name"), string::utf8(b"Description"), string::utf8(b"Token Name"), royalty, string::utf8(b"https://mycollection.com/my-named-token.jpeg"), );}
Finding Unnamed Token Addresses via Indexer
Sección titulada «Finding Unnamed Token Addresses via Indexer»You can find the addresses of your recently created “unnamed” Token
s by using the Aptos Indexer with queries like the following:
- Looking up the collection id by using your account address and the name of the
Collection
.
- Then look up the address (
token_data_id
) of theToken
by using thecollection_id
(from above) and the name of the token:
Using Tokens
Sección titulada «Using Tokens»Transfer Tokens
Sección titulada «Transfer Tokens»Transferring a Token
can be done by calling object::transfer
.
public entry fun transfer<T: key>(owner: &signer, object: object::Object<T>, to: address)
Burning Tokens
Sección titulada «Burning Tokens»Burning / deleting a Token
requires storing a BurnRef
with token::generate_burn_ref
, then calling token::burn
.
module 0x42::example { use std::option; use aptos_token_objects::token::{Self, BurnRef, Token}; use std::string::utf8; use aptos_framework::object::{Self, Object};
struct CustomData has key, drop { burn_ref: BurnRef, }
public entry fun mint_token(creator: &signer) { let token_constructor_ref = &token::create( creator, utf8(b"My Collection"), utf8(b"My named Token description"), utf8(b"My named token"), option::none(), utf8(b"https://mycollection.com/my-named-token.jpeg"), );
let token_signer = &object::generate_signer(token_constructor_ref);
let burn_ref = token::generate_burn_ref(token_constructor_ref);
// Store the burn ref somewhere safe move_to(token_signer, CustomData { burn_ref, }); }
public entry fun burn_token(token: Object<Token>) acquires CustomData { let token_address = object::object_address(&token); // Remove all custom data from the token object. // Retrieve the burn ref from storage let CustomData { burn_ref } = move_from<CustomData>(token_address); // Burn the token token::burn(burn_ref); }}
Modifying Tokens After Creation
Sección titulada «Modifying Tokens After Creation»Mutating a Token
’s URI
or description
requires a MutatorRef
(which must be generated when creating the Token
, then stored for later).
module 0x42::example { use std::option; use aptos_token_objects::token::{Self, MutatorRef, Token}; use std::string::utf8; use aptos_framework::object::{Self, Object};
struct CustomData has key, drop { mutator_ref: MutatorRef, }
public entry fun mint_token(creator: &signer) { // Constructor ref is a non-storable struct returned when creating a new object. // It can be exchanged for signer to add resources to the token object. let token_constructor_ref = &token::create( creator, utf8(b"My Collection"), utf8(b"My named Token description"), utf8(b"My named Token"), option::none(), utf8(b"https://mycollection.com/my-named-token.jpeg"), );
let token_signer = &object::generate_signer(token_constructor_ref);
let mutator_ref = token::generate_mutator_ref(token_constructor_ref);
// Store the mutator ref somewhere safe move_to(token_signer, CustomData { mutator_ref, }); }
public entry fun mutate_token(token: Object<Token>) acquires CustomData { let token_address = object::object_address(&token); // Retrieve the mutator ref from storage let CustomData { mutator_ref } = move_from<CustomData>(token_address); // Change token description token::set_description(&mutator_ref, utf8(b"This is my named Token description")); }}
Extending Tokens
Sección titulada «Extending Tokens»Token
s can be extended either by adding additional resources (since they are an Object) or using Ref
s to modify the Object.
Aptos Token
Sección titulada «Aptos Token»For NFT creators who want to avoid writing their own logic for how your NFT should work, you can use the aptos_token
module to mint an NFT. This module is already deployed at 0x4
and allows you to:
- Mint a
Token
you can transfer with royalties. - Mint a soulbound
Token
. - Manage the resources your NFT has.
See the aptos_token
reference docs for all the helper functions you can use.
Minting with aptos_token
Sección titulada «Minting with aptos_token»Minting a Token
using aptos_token
requires the same parameters as any token that implements the DA standard. In addition though, the aptos_token
module allows you to specify a property map of key/value pairs for any other properties your specific NFT may require.
You can mint your Token
by calling aptos_token::mint
like so:
public entry fun mint( creator: &signer, collection: String, description: String, name: String, uri: String, property_keys: vector<String>, property_types: vector<String>, property_values: vector<vector<u8>>,) acquires AptosCollection, AptosToken
Soulbound Tokens
Sección titulada «Soulbound Tokens»To mint a soul bound Token
, you can call aptos_token::mint_soul_bound
instead:
public entry fun mint_soul_bound( creator: &signer, collection: String, description: String, name: String, uri: String, property_keys: vector<String>, property_types: vector<String>, property_values: vector<vector<u8>>, soul_bound_to: address,) acquires AptosCollection