Aptos Token Object V2 | Move dApp Extreme Beginner

作者介绍:

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 结构,并返回一个 ConstructorRefThe
  • 之前调用的创建函数可以使用ConstructorRef来获取签名者,在ObjectGroup资源中存储适当的结构,进行任何其他修改,然后将ConstructorRef返回堆栈。
  • 在对象创建堆栈中,任何模块都可以定义所有权、删除性、可转移性和可变性等属性。

0x03 Token V1 与Token V2 的比较

Token V1Token V2
基于资源模型基于对象模型
将其特征存储在链上的成本昂贵在链上存储其特征的成本低廉
无法拥有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

The above content are reproduced from the Internet, does not represent the position of AptosNews, is not investment advice, investment risk, the market need to be cautious, in case of infringement, please contact the administrator to delete.

Like (0)
Donate WeChat Sweep WeChat Sweep Alipay Sweep Alipay Sweep
Previous July 20, 2023
Next July 20, 2023

Related posts

Leave a Reply

Please Login to Comment
WeChat Sweep
Baidu Sweep

Subscribe to AptosNews

Subscribe to AptosNews to stay on top of Aptos.


This will close in 25 seconds

This site has no investment advice, Investment risk, Enter the market with caution.