初探Move語言:Part 4-撰寫並發佈第一個Sui Move智能合約

James Shieh
技術保鮮盒
Published in
9 min readJun 25, 2023

這一系列的文章,我想談談Move相較於Solidity有什麼特別之處,不過許多人可能對於這兩種語言都很陌生,甚至不太了解區塊鏈以及去中心化的概念,為了能與大家分享我研究新技術時的喜悅 — — 特別是它們能帶來什麼樣的可能性,我想盡可能地用簡短的文字幫大家建構區塊鏈的世界觀,這個世界觀不免有我主觀的想像,但我認為在這樣的脈絡下,比較容易講述程式語言對區塊鏈世界的影響。

他們說,「來吧,我們要建造一座城和一座塔,塔頂通天,為了揚我們的名,免得我們被分散到世界各地。」。但是耶和華降臨看到了世人所建造的城和塔。耶和華說,「看哪,他們都是一樣的人,說著同一種語言,如今他們既然能做起這事,以後他們想要做的事就沒有不成功的了。」讓我們下去,在那裡打亂他們的語言,讓他們不能知曉別人的意思。於是耶和華使他們分散到了世界各地,他們也就停止建造那座城。因為耶和華在那裡打亂了天下人的言語,使眾人分散到了世界各地,所以那座城名叫巴別。 — — 創世記11:4–9

上一篇:

建立一個Package

每個Sui的開發專案,都是以Pakage為單位,我們用以下指令建立一個新的package

sui move new hello_world #hello_world為package name

我們可以看到package中包含了一個用來放原始碼的sources目錄,以及一個專案的組態設定檔Move.toml:

cd hello_world/; ls; #顯示package下的所有檔案或目錄

撰寫智能合約

我們在sources下建立一個檔名為hello_world.move的move原始碼檔案:

touch ./sources/hello_world.move

撰寫一個hello world智能合約:

// 第一個hello_world為package name,第二個hello_world為module name
module hello_world::hello_world {
// imports
use std::string;
use sui::object::{Self, UID};
use sui::transfer;
use sui::tx_context::{Self, TxContext};
// types
struct HelloWorldObject has key, store {
id: UID,
text: string::String
}
// functions
public entry fun mint (ctx: &mut TxContext) {
let object = HelloWorldObject {
id: object::new(ctx),
text: string::utf8(b"Hello World!")
};
}
}

這是一個名為 hello_world 的 Move 模組的定義,它包含了一個名為 HelloWorldObject 的結構體和一個名為 mint 的公開函數。

以下是該模組的詳細解釋:

  • use std::string;:導入 string 模組,該模組提供了與字符串相關的功能。
  • use sui::object::{Self, UID};:導入 sui::object 模組,該模組可能提供了與物件相關的功能。SelfUID 是該模組中的兩個元素。
  • use sui::transfer;use sui::tx_context::{Self, TxContext};:導入其他模組和元素。
  • struct HelloWorldObject has key, store {...}:定義了一個名為 HelloWorldObject 的結構體,該結構體有兩個字段:idtexthas key, store 表示這個結構體是一個資源類型,它可以被存儲並且有一個唯一的鍵。
  • public entry fun mint (ctx: &mut TxContext) {...}:定義了一個名為 mint 的公開函數,該函數接受一個可變引用到 TxContext 類型的參數。在函數體中,創建了一個 HelloWorldObject 的實例並初始化了其字段。

將智能合約發佈到鏈上

執行以下命令將智能合約發佈到鏈上:

sui client publish --gas-budget 30000000 --skip-dependency-verification
  • sui client publish:這是主要的命令,表示要使用 sui client CLI來發布一個模組或腳本。
  • --gas-budget 30000000:這是一個選項,表示設置交易的 gas 預算為 30000000。在區塊鏈中,gas 是用來衡量執行交易所需的計算資源的單位,gas 預算就是執行這個交易所能使用的最大 gas 數量。
  • --skip-dependency-verification:表示在發布模組或腳本時跳過依賴性驗證。在一些情況下,一個模組或腳本可能依賴於其他的模組或腳本,依賴性驗證就是檢查這些依賴是否都已經被滿足。如果使用了這個選項,那麼就不會進行這種檢查。

發佈成功後,會得到一個Status: Success的輸出提示,同時我們還會得到這個合約的ID,如本例為0xbdbd425511b8237fa142c7f9594585bb13d090ca227f80f85b25d9d5918edb66

我們將合約ID儲存到環境變數中,以便待會使用:

export PACKAGE_ID=0xbdbd425511b8237fa142c7f9594585bb13d090ca227f80f85b25d9d5918edb66

調用合約中的函數

sui client call --package $PACKAGE_ID --gas-budget 300000000 --module hello_world --function mint
  • sui client call:這是主要的命令,表示要使用 sui Client CLI來呼叫一個函數。
  • --package $PACKAGE_ID:這是一個選項,表示要呼叫的函數所在的包的 ID。$PACKAGE_ID 是一個環境變數,它的值是要呼叫的函數所在的包的 ID。
  • --gas-budget 300000000:這是一個選項,表示設置交易的 gas 預算為 300000000。在區塊鏈中,gas 是用來衡量執行交易所需的計算資源的單位,gas 預算就是執行這個交易所能使用的最大 gas 數量。
  • --module hello_world:這是一個選項,表示要呼叫的函數所在的模組的名稱。
  • --function mint:這是一個選項,表示要呼叫的函數的名稱。

調用成功後我們會得到一個Status: Success的輸出提示:

這裡我們可以注意到幾件事情:

  1. Sui Client使用MoveCall調用了我們剛剛的合約ID下的hello_world模組中的mint函數:
MoveCall(0xbdbd425511b8237fa142c7f9594585bb13d090ca227f80f85b25d9d5918edb66::hello_world::mint()),
  1. Created Objects為我們調用合約時建立的物件,本例為0x25fe9c5cb0663cd26931cbca5b2f46efc0f5dd9be3b0f71cde4a5df67c5b4fb6

查詢鏈上資料

我們可以透過https://suiexplorer.com/這個服務來查詢鏈上資料,例如我們剛剛與合約互動的過程。首先,我們要先選擇Devnet作為查詢的鏈:

如果我們輸入剛剛的package id,可以看到合約的內容,或者你可以直接點擊此網址:https://suiexplorer.com/object/0xbdbd425511b8237fa142c7f9594585bb13d090ca227f80f85b25d9d5918edb66?network=devnet

這裡可以看到我們的合約以被轉換成Move Bytecode,Move採用一種介於組合語言與高階語言之間的Bytecode。

接著我們查詢剛剛調用mint函數建立的Object:

這裡我們可以注意幾件事情:

  1. 這個物件,如同程式碼所描述的,具有id與text兩個fields,其中text欄位也確實按照程式碼設定的,儲存為Hello World!
  2. 其中Type為我們的Package ID底下的hello_world模組下定義的HelloWorldObject

總結

至此,我們已經學會了如何撰寫並發佈一個智能合約。並知道如何查詢鏈上數據來驗證合約發佈與調用的過程。

--

--

James Shieh
技術保鮮盒

Find something more important than you are and dedicate your life to it.