查看原文
其他

Aptos Token Object V2 | Move dApp 极速入门(贰拾肆)

Aladeen 李大狗LDG
2024-11-19

作者介绍:

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

继续滑动看下一个
李大狗LDG
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存