作者介绍:
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。这一升级打破了初始版本的限制,使其能从对象模型中受益。
Aptos 区块链中的原始同质化代币模型称为「Token V1」,使用资源作为在链上表示代币的方式。这种模式有优点也有缺点。
「Token V1」可存储在链上资源中,可以最大限度地减少与模块 Modules 本身的手动交互次数,并确保 Token 属性的不变性。
它还使用「PropertyMap」表示 Token 在链上的特征。这允许更多的可扩展性,这意味着我们可以动态存储各种数据类型的属性,以便在初始创建后向 Token 添加更多特征。它还使用允许存储不同类型的数据通过 Binary Canonical Serialization (BCS) 的序列化和反序列化后的结果
在此 Token 模型中,数据存储在资源帐户中,这意味着 Token 可以嵌套在多层数据中,从而导致各种问题,例如查询所有者。
「PropertyMap」提供了很强的灵活性和稳健性,但这是以增加内存使用和计算开销为代价的。
Token V2 是指 Aptos 区块链内升级的非同质化代币标准,使用的是对象模型。
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 格式存储值,确保精确的数据类型并节省存储空间。Token V2 构建在对象模型之上,这意味着 Token 是属于集合(也是对象)一部分的对象。这提供了多种新功能,同时成本仍然低廉。
对象模型将所有权与数据分离,这意味着所有对象资源都是顶级数据,使它们可以全局寻址和查询。
在可扩展性方面,即使在最初创建对象之后,您也可以向对象添加资源,这允许将来具有更多的可扩展性和灵活性。
在可组合性方面,对象与帐户非常相似,它们甚至可以拥有其他对象,这使得能够创建真正的链上对象可组合性,即彼此存储 native, typed objects 的能力。
点击阅读有关对象模型的更多信息:
https://noncegeek.medium.com/aptos-object-model-learning-move-0x01-550708f0fd33
create_object
函数。create_object
生成一个新地址,在 ObjectGroup
资源组内的该地址存储一个 Object
结构,并返回一个 ConstructorRef
。ConstructorRef
来获取签名者,在ObjectGroup
资源中存储适当的结构,进行任何其他修改,然后将ConstructorRef
返回堆栈。Token V1 | Token V2 |
---|---|
基于资源模型 | 基于对象模型 |
将其特征存储在链上的成本昂贵 | 在链上存储其特征的成本低廉 |
无法拥有 Token | 可以拥有 Token |
可扩展 | 更具可扩展性 |
在某些情况下,数据既不可寻址也不可查询 | 数据始终是全局可寻址和可查询的 |
总之,从 Token V1 到 Token V2 的演变代表了 Aptos 区块链的 Token 标准的超级重大飞跃。
新模型提供了更大的灵活性、可扩展性和可组合性,为更复杂和动态的链上交互铺平了道路。
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 前,我们需要初始化模块
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,
}
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);
}
创建这些对象遵循与创建 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))
}
为 Hero 添加属性(或为 Weapon, Armor, Shield 添加 Gem)的步骤很简单:
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));
}
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。