Aptos Token Object V2 | Move dApp 极速入门(贰拾肆)
Leeduckgo
2023-08-19 22:29
订阅此专栏
收藏此文章

作者介绍:

I’m Aladeen, fresh graduate student and novi blockchain developer. I love meeting people across the globe and make new connections. I’m looking for people that have interest in coding and problem solving to join me for a wonderful journey so if you’re interested feel free to reach out. Cheers!

作者 Github:https://github.com/Aladeenb

Move Learning Camp:

https://github.com/NonceGeek/Web3-dApp-Camp

「Token」一词通常是指链上同质化代币和非同质化代币。随着区块链的发展,定义代币的标准和模型也在不断发展。在 Aptos 中,「Token V2」是指升级后的非同质化代币标准。原始模型「Token V1」使用资源 Resource 作为链上代币的表示方式,而新模型则使用 Object。这一升级打破了初始版本的限制,使其能从对象模型中受益。

0x01 Token V1:概述

Aptos 区块链中的原始同质化代币模型称为「Token V1」,使用资源作为在链上表示代币的方式。这种模式有优点也有缺点。

1.1 优点

「Token V1」可存储在链上资源中,可以最大限度地减少与模块 Modules 本身的手动交互次数,并确保 Token 属性的不变性。

它还使用「PropertyMap」表示 Token 在链上的特征。这允许更多的可扩展性,这意味着我们可以动态存储各种数据类型的属性,以便在初始创建后向 Token 添加更多特征。它还使用允许存储不同类型的数据通过 Binary Canonical Serialization (BCS) 的序列化和反序列化后的结果

1.2 缺点

在此 Token 模型中,数据存储在资源帐户中,这意味着 Token 可以嵌套在多层数据中,从而导致各种问题,例如查询所有者。

「PropertyMap」提供了很强的灵活性和稳健性,但这是以增加内存使用和计算开销为代价的。

0x02 Token V2:新时代

Token V2 是指 Aptos 区块链内升级的非同质化代币标准,使用的是对象模型。

2.1 Token V2 组件

Aptos token object model 由以下模块组成:

  • collection.move:定义基于对象的集合。
  • token.move:定义基于对象的 Token(TokenV2)的核心逻辑。
  • royalty.move:定义基于对象的版税系统。版税可用于 Token 合集(Collection)或独立 Token。
  • aptos_token.move:定义无代码解决方案的基本 Token,类似于 0x3::token 模块中的原始 Token。具有基本的 Token 和 Collection 功能。允许创建者控制 Token 如何变化以及其是否可冻结、可焚毁和可铸币。它还具有传输对象和相关事件的标准方法,以及元数据的属性类型。
    • property_map.move:为「AptosToken」提供通用元数据帮助。它是“SimpleMap”的特定版本,通过利用常量 u64 来表示类型并以 bcs 格式存储值,确保精确的数据类型并节省存储空间。

2.2 Token V2 的特点

Token V2 构建在对象模型之上,这意味着 Token 是属于集合(也是对象)一部分的对象。这提供了多种新功能,同时成本仍然低廉。

对象模型将所有权与数据分离,这意味着所有对象资源都是顶级数据,使它们可以全局寻址和查询。

在可扩展性方面,即使在最初创建对象之后,您也可以向对象添加资源,这允许将来具有更多的可扩展性和灵活性。

在可组合性方面,对象与帐户非常相似,它们甚至可以拥有其他对象,这使得能够创建真正的链上对象可组合性,即彼此存储 native, typed objects 的能力。

点击阅读有关对象模型的更多信息:

https://noncegeek.medium.com/aptos-object-model-learning-move-0x01-550708f0fd33

2.3 Token V2 的生命周期

  • Entity 调用顶级对象类型上的 create。
  • 顶级对象类型在其 direct ancestor 上调用 create 。
  • 重复此操作,直到最顶层的 ancestor 是「Object」结构,该结构定义了create_object函数。
  • create_object 生成一个新地址,在 ObjectGroup 资源组内的该地址存储一个 Object 结构,并返回一个 ConstructorRef
  • 之前调用的创建函数可以使用ConstructorRef来获取签名者,在ObjectGroup资源中存储适当的结构,进行任何其他修改,然后将ConstructorRef返回堆栈。
  • 在对象创建堆栈中,任何模块都可以定义所有权、删除性、可转移性和可变性等属性。

0x03 Token V1 与 Token V2 的比较

Token V1Token V2
基于资源模型基于对象模型
将其特征存储在链上的成本昂贵在链上存储其特征的成本低廉
无法拥有 Token可以拥有 Token
可扩展更具可扩展性
在某些情况下,数据既不可寻址也不可查询数据始终是全局可寻址和可查询的

总之,从 Token V1 到 Token V2 的演变代表了 Aptos 区块链的 Token 标准的超级重大飞跃。

新模型提供了更大的灵活性、可扩展性和可组合性,为更复杂和动态的链上交互铺平了道路。

0x04 Tolem V2 的实际应用:hero.move

在学习语言的过程中,没有比其先驱学习更好的方法了。Aptos 实验室在 aptos-core repository 中提供了如何使用新代币模型的示例:

https://github.com/aptos-labs/aptos-core/tree/main/aptos-move/move-examples/token_objects/hero

截至撰写本文时,「hero.move」是 token V2 最简单但完整的示例。

智能合约允许创建 Hero,为其添加属性,并将 Hero 本身及其属性转移到另一个帐户:

struct Hero has key {
        armor: Option<Object<Armor>>,
        gender: String,
        race: String,
        shield: Option<Object<Shield>>,
        weapon: Option<Object<Weapon>>,
        mutator_ref: token::MutatorRef,
    }

“hero”是 token,“armor”、“gender”、“race”、“shield”、“weapon”是“hero”中代表其属性的 tokens。

  • “hero”可以拥有“armor”、“shield”和“weapon”。
  • “weapon”、“shield”和“armor”可以有“gems”。
  • “gems”可以改变“weapon”、“shield”和“armor”的“攻击”和“防御”值。它们还具有“魔法”属性。

代码的生命周期如下所示:

4.1 初始化模块

在创建 hero 前,我们需要初始化模块

fun init_module(account: &signer) {
    let collection = string::utf8(b"Hero Quest!");
    collection::create_unlimited_collection(
        account,
        string::utf8(b"collection description"),
        collection,
        option::none(),
        string::utf8(b"collection uri"),
    );

    let on_chain_config = OnChainConfig {
        collection,
    };
    move_to(account, on_chain_config);
    }

这是通过创建一个集合并将其存储在“OnChainConfig”资源中来完成的,该资源具有“key”关键字来全局存储它。稍后将对集合进行简单查询。

struct OnChainConfig has key {
        collection: String,
    }

4.2 创建 Hero

public fun create_hero(
    creator: &signer,
    description: String,
    gender: String,
    name: String,
    race: String,
    uri: String,
): Object<Hero> acquires OnChainConfig {
    let constructor_ref = create(creator, description, name, uri);
    let token_signer = object::generate_signer(&constructor_ref);

    let hero = Hero {
        armor: option::none(),
        gender,
        race,
        shield: option::none(),
        weapon: option::none(),
        mutator_ref: token::generate_mutator_ref(&constructor_ref),
    };
    move_to(&token_signer, hero);

    object::address_to_object(signer::address_of(&token_signer))
}

Hero 本质上是一个对象。create_hero 函数创建一个 Hero 并在函数结束之前返回它。

public fun create_hero(
    
): Object<Hero>

...

object::address_to_object()

新创建的 Hero 数据存储在资源帐户中。

let hero = Hero {
armor: option::none(),
gender,
race,
shield: option::none(),
weapon: option::none(),
mutator_ref: token::generate_mutator_ref(&constructor_ref),
};
move_to(&token_signer, hero);

constructor_ref 是对 hero 对象的引用。它生成一个用于完成存储操作的签名人。

create_hero 最终将被包裹在入口函数 mint_hero 中。

entry fun mint_hero(
    account: &signer,
    description: String,
    gender: String,
    name: String,
    race: String,
    uri: String,
) acquires OnChainConfig {
    create_hero(account, description, gender, name, race, uri);
}

4.3 创建 Shield、Armor、Weapon 和 Gem

创建这些对象遵循与创建 Hero 相同的模式。

    public fun create_weapon(
        creator: &signer,
        attack: u64,
        description: String,
        name: String,
        uri: String,
        weapon_type: String,
        weight: u64,
    ): Object<Weapon> acquires OnChainConfig {
        let constructor_ref = create(creator, description, name, uri);
        let token_signer = object::generate_signer(&constructor_ref);

        let weapon = Weapon {
            attack,
            gem: option::none(),
            weapon_type,
            weight,
        };
        move_to(&token_signer, weapon);

        object::address_to_object(signer::address_of(&token_signer))
    }

4.4 添加 / 删除 Hero 属性

为 Hero 添加属性(或为 Weapon, Armor, Shield 添加 Gem)的步骤很简单:

  1. 获取对象
  2. 将对象放置入 Hero 对象中
  3. 将对象转移给新的所有人
public fun weapon_equip_gem(owner: &signer, weapon: Object<Weapon>, gem: Object<Gem>) acquires Weapon {
    let weapon_obj = borrow_global_mut<Weapon>(object::object_address(&weapon));
    option::fill(&mut weapon_obj.gem, gem);
    object::transfer_to_object(owner, gem, weapon);
}

删除属性也是一样的,只是我们需要检查英雄对象中是否存在该属性。

public fun weapon_unequip_gem(owner: &signer, weapon: Object<Weapon>, gem: Object<Gem>) acquires Weapon {
    let weapon_obj = borrow_global_mut<Weapon>(object::object_address(&weapon));
    let stored_gem = option::extract(&mut weapon_obj.gem);
    assert!(stored_gem == gem, error::not_found(EINVALID_GEM_UNEQUIP));
    object::transfer(owner, gem, signer::address_of(owner));
}

0x05 参考

  • Token v1 代码库:https://github.com/aptos-labs/aptos-core/tree/main/aptos-move/framework/aptos-token
  • Token v2 代码库:https://github.com/aptos-labs/aptos-core/tree/main/aptos-move/framework/aptos-token-objects
  • 对象模型文章:https://noncegeek.medium.com/aptos-object-model-learning-move-0x01-550708f0fd33
  • Gas 计算规则:https://aptos.dev/concepts/base-gas/#instruction-gas
  • hero.move:https://github.com/aptos-labs/aptos-core/tree/main/aptos-move/move-examples/token_objects/hero

可編程交易塊 | Move dApp 極速入門(貳拾叁)
Aptos 密鑰輪換 | Move dApp 極速入門(貳拾貳)
Aptos 对象模型 | Move dApp 极速入门(贰拾壹)
Aptos Moveflow SDK 使用指南 | Move dApp 极速入门(贰拾)
Sui 上简单 Swap 的实现 | Move dApp 极速入门(拾玖)
用 Elixir 交互 Aptos |  Move dApp 极速入门(拾捌)
Sui 链上数据查询 | Move dApp 极速入门(拾柒)
SUI 合约测试攻略 | Move dApp 极速入门(拾陆)
Sui 数据类型详解 | Move dApp 极速入门(十五)
Airdropper Contract in Aptos | Move dApp 极速入门(拾肆)
Sandwich 合约案例实践 | Move dApp 极速入门(拾叁)
Sui  | Move dApp 
Move  | 
Move  | 
scaffold-aptos  | Move dApp 
Aptos NFT  | Move dApp 
 DID Document  | Move dApp 
DID | Move dApp 
Aptos  | Move dApp 
Aptos CLI使REPL | Move dApp 
 DID  | Move dApp 
 | Move dApp 
 | Move dApp
 Move dApp | Move dApp
Hello Move | Move dApp

【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。

Leeduckgo
数据请求中
查看更多

推荐专栏

数据请求中
在 App 打开