Aptos 数字资产标准
数字资产(DA)标准是 Aptos 上现代的非同质化代币(NFT)标准.NFT 代表链上的独特资产,并存储在集合中.这些 NFT 可以自定义,后续可通过你的智能合约进行转移,灵魂绑定,销毁,变更或扩展.
该标准取代了旧的 Aptos Token Standard.主要改进如下:
改进项 | 描述 |
---|---|
Token 扩展性 | Token 通过 Move Objects 实现,易于扩展. |
直接 NFT 转账 | 现在可以直接转移 NFT,无需接收方在链上”预先注册”. |
NFT 组合性 | NFT 可以拥有其他 NFT,便于组合. |
如果你只需要简单铸造 NFT,无需自定义或扩展功能,可以使用实现了 DA 标准的 aptos_token
模块(见下文用法).
使用数字资产标准
Section titled “使用数字资产标准”该标准通过两个 Object 实现:
Collection
- 具有名称和上下文信息的 NFT 集合.Token
- 代表独特资产的数字资产.通常用于表示 NFT,通常使用uri
链接指向资产的更多信息(如图片,视频等).
所有 Token
必须引用一个父 Collection
,但父 Collection
不拥有 Token
.新铸造的 Token
通常归创建者所有,之后可以转移给其他账户.
集合(Collections)
Section titled “集合(Collections)”字段 | 描述 |
---|---|
Description | 可选字符串,少于 2048 字符(可通过 MutatorRef 修改). |
Name | 必填字符串,用于标识 Collection .名称在每个账户内必须唯一,即单个创建者账户不能创建多个同名 Collection . |
Royalty | 可选 Royalty 结构体,表示销售价格中归创作者的分成比例.可通过 Royalty 模块 生成的 MutatorRef 修改.该模块是 DA 标准的扩展.示例见 aptos_token.move . |
URI length | 可选字符串,少于 512 字符,链接到 Collection 相关内容(可通过 MutatorRef 修改). |
创建 Collection
Section titled “创建 Collection”根据是否需要最大 Token 数量限制,有两种方式创建 Collection
.
固定最大供应量
Section titled “固定最大供应量”如需固定供应量的 Collection
,可使用 collection::create_fixed_collection
:
use aptos_token_objects::collection;use std::option::{Self, Option};
public entry fun create_collection(creator: &signer) { let max_supply = 1000; let royalty = option::none();
// 创建后最大供应量不可更改 collection::create_fixed_collection( creator, "My Collection Description", max_supply, "My Collection", royalty, "https://mycollection.com", );}
如需无限供应量的 Collection
,可使用 collection::create_unlimited_collection
:
use std::option::{Self, Option};
public entry fun create_collection(creator: &signer) { let royalty = option::none();
collection::create_unlimited_collection( creator, "My Collection Description", "My Collection", royalty, "https://mycollection.com", );}
自定义 Collection
Section titled “自定义 Collection”每个 Collection
都是 Move Object,可通过生成权限 Ref
进行自定义.每个 Ref
允许你后续修改 Object 的某一方面.除了常规 Object Refs,Collection
还可通过 get_mutator_ref
获取 MutatorRef
:
use std::option::{Self, Option};
public entry fun create_collection(creator: &signer) { let royalty = option::none(); let collection_constructor_ref = &collection::create_unlimited_collection( creator, "My Collection Description", "My Collection", royalty, "https://mycollection.com", ); let mutator_ref = collection::get_mutator_ref(collection_constructor_ref); // 将 mutator ref 安全存储}
你还可以通过智能合约为 Collection
添加更多资源或功能.例如,可以记录创建时间以限制 Token 铸造时间:
use std::option::{Self, Option};
struct MyCollectionMetadata has key { creation_timestamp_secs: u64,}
public entry fun create_collection(creator: &signer) { let royalty = option::none(); // Constructor ref 是创建新 object 时返回的不可存储结构体。 // 可生成 object signer 以向 collection object 添加资源。 let collection_constructor_ref = &collection::create_unlimited_collection( creator, "My Collection Description", "My Collection", royalty, "https://mycollection.com", ); // Constructor ref 可换取 signer 以向 collection object 添加资源。 let collection_signer = &object::generate_signer(collection_constructor_ref); move_to(collection_signer, MyCollectionMetadata { creation_timestamp_secs: timestamp::now_seconds() })}
字段 | 描述 |
---|---|
Description | 可选字符串,少于 2048 字符(可通过 MutatorRef 修改). |
Name | 必填字符串,用于标识 Collection ,在每个 Collection 内唯一.即单个 Collection 账户不能有多个同名 Token . |
Royalty | 可选 Royalty 结构体,表示销售价格中归创作者的分成比例.可通过 Royalty 模块 生成的 MutatorRef 修改(该模块为 DA 标准扩展,示例见 aptos_token.move ).通常 royalty 设置在 collection 上,但也可为单独的 Token 设置自定义分成比例. |
URI length | 可选字符串,少于 512 字符,链接到 Collection 相关内容(可通过 MutatorRef 修改). |
创建 Token
Section titled “创建 Token”有几种方式可以创建 Token
:
- 命名 Token.使用
Token
名称生成命名 Object.这样如果知道 token 和Collection
名称,便于查找 token 地址,但命名 Object 不可删除.尝试删除命名 token 只会删除数据,Object 本身不会被删除.
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", );}
- “未命名” token.创建未命名 Object(可删除),但仍有
Token
名称.由于 Object 地址不可预测,需通过 Indexer 查找其地址.
use aptos_token_objects::token;use std::option::{Self, Option};
public entry fun mint_token(creator: &signer) { let royalty = option::none(); token::create( creator, "Collection Name", "Description", "Token Name", royalty, "https://mycollection.com/my-named-token.jpeg", );}
通过 Indexer 查找未命名 Token 地址
Section titled “通过 Indexer 查找未命名 Token 地址”你可以通过 Aptos Indexer 查询最近创建的”未命名” Token
地址,示例如下:
- 通过账户地址和
Collection
名称查找 collection id.
- 再通过 collection_id(上一步结果)和 token 名称查找
Token
的地址(token_data_id
):
Token 用法
Section titled “Token 用法”Token 转账
Section titled “Token 转账”可通过 object::transfer
转移 Token
.
public entry fun transfer<T: key>(owner: &signer, object: object::Object<T>, to: address)
Token 销毁
Section titled “Token 销毁”销毁 / 删除 Token
需先用 token::generate_burn_ref
生成 BurnRef
,再调用 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);
// 将 burn ref 安全存储 move_to(token_signer, CustomData { burn_ref, }); }
public entry fun burn_token(token: Object<Token>) acquires CustomData { let token_address = object::object_address(&token); // 删除 token object 上的所有自定义数据。 // 从存储中取出 burn ref let CustomData { burn_ref } = move_from<CustomData>(token_address); // 销毁 token token::burn(burn_ref); }}
Token 创建后修改
Section titled “Token 创建后修改”要修改 Token
的 URI
或 description
,需在创建时生成 MutatorRef
并存储,后续使用.
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 是创建新 object 时返回的不可存储结构体。 // 可换取 signer 以向 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);
// 将 mutator ref 安全存储 move_to(token_signer, CustomData { mutator_ref, }); }
public entry fun mutate_token(token: Object<Token>) acquires CustomData { let token_address = object::object_address(&token); // 从存储中取出 mutator ref let CustomData { mutator_ref } = move_from<CustomData>(token_address); // 修改 token 描述 token::set_description(&mutator_ref, utf8(b"This is my named Token description")); }}
Token 扩展
Section titled “Token 扩展”Token
可通过添加额外资源(作为 Object)或使用 Ref
修改 Object 进行扩展.
Aptos Token
Section titled “Aptos Token”如果你不想自定义 NFT 逻辑,可直接使用 aptos_token
模块铸造 NFT.该模块已部署在 0x4
,支持:
- 铸造可转让,带分成的
Token
. - 铸造灵魂绑定
Token
. - 管理 NFT 的资源.
所有可用辅助函数见 aptos_token
参考文档.
使用 aptos_token
铸造
Section titled “使用 aptos_token 铸造”使用 aptos_token
铸造 Token
所需参数与实现 DA 标准的 token 相同.此外,aptos_token
模块允许你指定属性键值对(property map)以满足 NFT 的其他需求.
可通过调用 aptos_token::mint
铸造 Token
:
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
灵魂绑定 Token
Section titled “灵魂绑定 Token”如需铸造灵魂绑定 Token
,可调用 aptos_token::mint_soul_bound
:
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