通过官方合约学习Sui Move语法知识
https://github.com/MystenLabs/sui/blob/main/sui_programmability/examples/basics/sources/counter.move
功能说明:
任何人都可以创建并共享一个计数器
任何人都可以将计数器增加1
计数器的所有者可以将其重置为任何值
计数器的所有者可以将计数器对象删除
module basics::counter {
use sui::transfer;
use sui::object::{Self, UID};
use sui::tx_context::{Self, TxContext};
/// 计数器对象类型定义
struct Counter has key {
id: UID,
owner: address,
value: u64
}
public fun owner(counter: &Counter): address {
counter.owner
}
public fun value(counter: &Counter): u64 {
counter.value
}
/// 创建并设置计数器对象为共享对象
public entry fun create(ctx: &mut TxContext) {
transfer::share_object(Counter {
id: object::new(ctx),
owner: tx_context::sender(ctx),
value: 0
})
}
/// 计数器自增1(任何人可以调用)
public entry fun increment(counter: &mut Counter) {
counter.value = counter.value + 1;
}
/// 设置计数器的值(只有合约创建者可以调用)
public entry fun set_value(counter: &mut Counter, value: u64, ctx: &TxContext) {
assert!(counter.owner == tx_context::sender(ctx), 0);
counter.value = value;
}
/// 断言计数器的值
public entry fun assert_value(counter: &Counter, value: u64) {
assert!(counter.value == value, 0)
}
/// 删除计数器共享对象(只有合约创建者可以调用)
public entry fun delete(counter: Counter, ctx: &TxContext) {
assert!(counter.owner == tx_context::sender(ctx), 0);
let Counter {id, owner:_, value:_} = counter;
object::delete(id);
}
}
创建一个Sui object
需要一个唯一ID
可以根据当前TxContext
中的信息,使用 sui::object::new
函数来创建一个新的ID
能力定义对象(Object)的行为。一个对象类型最多拥有4项能力,分别是:
拥有 Key
和 Store
能力特性的定制类型被视为资产,资产可以在全局存储中存储,也可以在不同账号之间转移。
共享对象(Share object)
可以通过 sui::transfer::share_object
被共享,从而让所有人都可以使用。
因为该对象可以被任何人使用, 因此需要根据需求在逻辑中设计额外的安全检查,如:示例中的set_value
和delete
接口,只有合约创建者可以调用去设置计数器的值或删除计数器共享对象。
保存了当前执行交易的上下文信息。定义结构如下:
struct TxContext has drop {
/// The address of the user that signed the current transaction
sender: address,
/// Hash of the current transaction
tx_hash: vector<u8>,
/// The current epoch number
epoch: u64,
/// Timestamp that the epoch started at
epoch_timestamp_ms: u64,
/// Counter recording the number of fresh id's created while executing
/// this transaction. Always 0 at the start of a transaction
ids_created: u64
}
在示例代码中,通过tx_context::sender(ctx)
获取到当前交易的发起者地址,以便可以和合约中记录的创建者地址是否一致,用于一些特定接口调用的安全检查,来判断是否是合约创建者进行的调用。
相关汇总如下:
接口名 | 说明 |
---|---|
tx_context::sender(ctx) |
获取当前交易发起者(交易签署者)地址 |
tx_context::digest(ctx) |
获取当前交易Hash |
tx_context::epoch(ctx) |
获取当前世代 |
tx_context::epoch_timestamp_ms(ctx) |
以毫秒级别unix时间戳返回epoch开始时间 |
要删除一个Object
,先要解包这个Object
并且获取它的Object ID
。在调用object::delete
进行对象删除。
注:
不关心的参数可以使用_
以忽略
解包的操作只能够在定义了这个Object
的Module内进行
let Counter {id, owner:_, value:_} = counter;
object::delete(id);
https://github.com/MystenLabs/sui/blob/main/sui_programmability/examples/basics/sources/clock.move
功能说明:调用get_time
接口,将通过事件形式抛出当前毫秒级别时间戳。
module basics::clock {
use sui::clock::{Self, Clock};
use sui::event;
use sui::tx_context::TxContext;
struct TimeEvent has copy, drop {
timestamp_ms: u64,
}
/// Emit event with current time.
public entry fun get_time(clock: &Clock, _ctx: &mut TxContext) {
event::emit(TimeEvent { timestamp_ms: clock::timestamp_ms(clock) });
}
}
事件对于区块链系统至关重要,它是追踪链上行为的主要方法。
Sui
上面的事件也是以Objects
的形式表示。有几种系统层级的事件, 包括:Move event
、Publish event、Transfer object event
等。
事件对象定义仅需要具有copy
和drop
的能力,表明可以被复制并在作用域结束后被销毁。它不代表资产,我们只对其包含的数据感兴趣。
struct TimeEvent has copy, drop {
timestamp_ms: u64,
}
event::emit(TimeEvent { timestamp_ms: clock::timestamp_ms(clock) });
get_time
接口第一个参数是sui::clock::Clock
,Clock
是系统已经预置的硬编码的对象只读引用实例,地址是:0x6
,即:接口调用将0x6
作为Clock
参数的地址传入。
相关汇总如下:
地址 | 说明 |
---|---|
@0x5 | Sui System State Object |
@0x6 | Clock Object |
@0x7 | AuthenticatorState Object |
@0x8 | Random Object |
/// Test CTURD object basics (create, transfer, update, read, delete)
module basics::object_basics {
use sui::event;
use sui::object::{Self, UID};
use sui::tx_context::{Self, TxContext};
use sui::transfer;
struct Object has key, store {
id: UID,
value: u64,
}
struct Wrapper has key {
id: UID,
o: Object
}
struct NewValueEvent has copy, drop {
new_value: u64
}
public entry fun create(value: u64, recipient: address, ctx: &mut TxContext) {
transfer::public_transfer(
Object { id: object::new(ctx), value },
recipient
)
}
public entry fun transfer(o: Object, recipient: address) {
transfer::public_transfer(o, recipient)
}
public entry fun freeze_object(o: Object) {
transfer::public_freeze_object(o)
}
#[no_lint]
public entry fun set_value(o: &mut Object, value: u64) {
o.value = value;
}
// test that reading o2 and updating o1 works
public entry fun update(o1: &mut Object, o2: &Object) {
o1.value = o2.value;
// emit an event so the world can see the new value
event::emit(NewValueEvent { new_value: o2.value })
}
public entry fun delete(o: Object) {
let Object { id, value: _ } = o;
object::delete(id);
}
public entry fun wrap(o: Object, ctx: &mut TxContext) {
transfer::transfer(Wrapper { id: object::new(ctx), o }, tx_context::sender(ctx))
}
public entry fun unwrap(w: Wrapper, ctx: &TxContext) {
let Wrapper { id, o } = w;
object::delete(id);
transfer::public_transfer(o, tx_context::sender(ctx))
}
}
Object
对象嵌套进入Wrapper
对象Wrapper
对象具有key
能力,被包装的Object
对象必须具有store
的能力Object
对象就不再能单独根据object ID
来获取,它会变成Wrapper
对象的一部分Object
对象不能被作为参数进行传递,而只能通过Wrapper
对象进行获取示例中,将Object
对象包装进入Wrapper
对象后,转移给交易发起者:
public entry fun wrap(o: Object, ctx: &mut TxContext) {
transfer::transfer(Wrapper { id: object::new(ctx), o }, tx_context::sender(ctx))
}
解包后,将Wrapper
对象删除后,将被包装的Object
对象转移给交易发起者:
public entry fun unwrap(w: Wrapper, ctx: &TxContext) {
let Wrapper { id, o } = w;
object::delete(id);
transfer::public_transfer(o, tx_context::sender(ctx))
}
key
和 store
的对象才可以被随意转移key
能力的对象的所有权是不可以被随意转移的, 想要使只有 key
限制符对象可以变更所有权,必须创建一个自定义的转移函数transfer::public_freeze_object(o)
可以冻结Object
对象Object
对象变得不可变,将不可再被转移和改变module fungible_tokens::managed {
use std::option;
use sui::coin::{Self, Coin, TreasuryCap};
use sui::transfer;
use sui::tx_context::{Self, TxContext};
struct MANAGED has drop {}
#[allow(unused_function)]
fun init(witness: MANAGED, ctx: &mut TxContext) {
let (treasury_cap, metadata) = coin::create_currency<MANAGED>(witness, 2, b"MANAGED", b"", b"", option::none(), ctx);
transfer::public_freeze_object(metadata);
transfer::public_transfer(treasury_cap, tx_context::sender(ctx))
}
public entry fun mint(
treasury_cap: &mut TreasuryCap<MANAGED>, amount: u64, recipient: address, ctx: &mut TxContext
) {
coin::mint_and_transfer(treasury_cap, amount, recipient, ctx)
}
public entry fun burn(treasury_cap: &mut TreasuryCap<MANAGED>, coin: Coin<MANAGED>) {
coin::burn(treasury_cap, coin);
}
}
Capability
是一种常用的调整获取权限的设计模式mint
和burn
方法第一个参数是treasury_cap
,表示只有拥有TreasuryCap<MANAGED>
的人可以调用_
,表示立即进行消耗A
,在短暂的witness
资源被消耗后只能启动一次witness
资源在使用后必须立即被消耗或丢弃,确保它不能被重复使用以创建A
的多个实例实例中的代码是一次性见证(One Time Witness(OTW)
),它是Witness模式的一个子模式:利用模块init
函数来确保只创建一个witness
资源的实例。
TreasuryCap
是一种资产,通过一次性见证这种模式保证它是一个单体对象
如果一个类型的定义具有以下属性,那么它就被认为是一个OTW。
drop
的能力https://examples.sui-book.com/
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!