---
# System prepended metadata

title: Fundamental

---

# Sui Move
Version: 0.1.0

Move 是一個重視資源移動的語言，由原本的 Diem 團隊開發，後來 Diem 團隊解散拆分為 Sui 跟 Aptos 兩大公鏈，Sui 跟 Aptos 都是採用 Move 來開發智能合約，但對於自身的架構做了些調整，所以在找教學時，會發現 Sui 上寫的智能合約跟 Aptos 的需要分開處理，因此這邊我們只討論 Sui Move。

這篇主要是對 Sui Move 有個大致上的了解，會有一些程式碼語法做舉例，但不會有實作步驟

> Note: 內容中會採用 Solidity 做對比，若沒有 Solidity 基礎的人可以忽略該部分

# Fundamental

在解釋 Sui Move 前，應該先了解 Sui 在基礎架構上做了哪些調整，個人認爲 Sui 最大的調整在於 Account 存儲的資料變多了，從 Solidity 一個 Account(address) 只能紀錄 nonce balance，到 Sui 當中，多了**能紀錄一個 object 的資料**，這個 object 在 Sui 裡面比較常用的詞是**資源**，但再通俗點說，就是 NFT / Fungible Token 等等資產，在程式中 object 以 struct 的資料型態為底，並在上面附加一些屬性（後面會介紹）

//Ref solidity account link

在 Solidity 當中，紀錄 token 發行狀況通常是利用合約 mapping 的方式，也就是 address 對應 balance，但這些資料都是存在於合約裡面的，在區塊鏈上，並不依附於你個人，這意思是，假設這個合約要是之後損壞或遺失，你的 token 就會全數遺失，因為紀錄**你有多少 token** 的資訊存在於合約中

但如果是 Sui，調用合約所產生出來的 token 會是以 object 的形式，並且存在於 Account 底下，那在 Sui 上資料就會顯示，這個帳戶多了一個 token object

總結一下兩者差別，假設我需要找一個 0x12 這個 Account 有多少 USDT
- 在 Solidity，我需要找到 USDT 的合約，並且調用合約中的 `balanceOf`，並且放入 0x12 當作參數來尋找
- 在 Sui，直接找尋這個 0x12 底下擁有的 object，並且 type 為 Token，找裡面的欄位來得到妳想要的資料，不需要知道發行這個 Token 得合約為何

# Module

Move 是一個基於 Rust 改寫的語言，因此在裡面會看到很多與 Rust 相似的語法

在 Sui 中，建立 `module` keyword 就是建立合約，接著再宣告 package 跟 module，在 Sui 中發布合約都是以 package 為單位，一個 package 裡面可以裝數個 module，且在發布之後會給這個 package 一個 package id，類似於 Solidity 裡面的 contract address

```rust
module package_name::module_name {
		// module code goes here
}
```

# Object

在 Sui 中，建立 object 的方法是使用 `struct` 關鍵字，但如果只是 `struct` 還不能算是 Sui 的 object，要加上 **Abilities**，這些 abilities 可以看作是為 struct 添加屬性，例如 key 使得有個全域的 ID，copy 讓其 data 可以被複製等等

//todo Ref ability link

要成為 Sui object 必須要有 **key**，這樣在轉移的時侯才可以透過 id 知道要轉移哪個 object
底下例子可以看到，建立一個 SumObject object，包含以下資訊
- 有 key 這個 ability
- 有以下欄位
	- id，型別為 UID(from sui package)
	- number_1，型別為 u8 
	- number_2，型別為 u8

<!-- todo: store 的屬性要說明清楚 -->

```rust
use sui::object::UID; // import package

struct SumObject has key {
    id: UID,
    number_1: u8,
    number_2: u8,
}
```

# Safety

## Without drop

這邊簡單寫一個 `create()`，用於創建一個新的 object

解釋一下這個 function，前三個參數用來創建 object，最後一個 ctx 可以把他當作呼叫這個 function 會帶的交易資訊，例如 sender 之類的，在 SDK 呼叫這個 function 會自動帶入這個參數

```kotlin
struct Color has key {
	id: UID,
	red: u8,
	green: u8,
	blue: u8
}

public entry fun create(red: u8, green: u8, blue: u8, ctx: &mut TxContext){
	let Color = new Color(red, gree, blue);
} //Scope end

```

再回過頭看這個 function，乍看之下沒有問題，但實際執行下去會報錯，錯誤訊息應該是這個 struct 沒有 drop 屬性，這邊就引出一個 Sui 對於 object 的安全保護機制，也就是 **object 被創建後不能被任意丟棄**

Move 在 Scope 這部分的處理是，如果在 Scope 裡面創建的變數，脫離這個 Scope 後便會丟棄，這點跟 Rust 是一樣的（題外話，所以在 Rust 中傳入 struct 參數盡量會以 Reference 的形式傳入）

那以這個 function 為例，就是在 `create()` 這個 Scope 裡面建立 Color 這個 struct，接著在 //Scope end 這個地方，Color 被丟棄，但在 Sui 中，不允許資源被隨意丟棄 （除非有 drop 屬性）

因此，需要把創建出來的 object 做一個 transfer 的處理，明確定義這個 object 應該怎麼處理傳送到哪裡，而不是創建出來不管，放任被丟棄

這邊我們傳給對這個 function 發出交易的用戶

```rust
public entry fun create(red: u8, green: u8, blue: u8, ctx: &mut TxContext){
	let Color = new Color(red, gree, blue);
	// 轉移給 sender
	transfer::public_transfer(color_object, tx_context::sender(ctx))
}
```

這邊對 object 的處理，除了傳送給指定 Account 以外，也有其他選項，例如 Immutable / Share 等等，可以參考 //Ref ownership link

## onlyOwner

在 Solidity 中，我們要避免別人任意調用 function，通常會採用的做法是加上 `onlyOwner`的 modifier 來進行權限控管，但在 Sui 裡面，因為 object 架構的關係，從根本上避免了 onlyOwner 的問題

這邊寫一個能任意更動 token 發行量的 function
```rust
public fun setSupply(treasury: &mut Treasury, amount: u8){
	treasury.supply = amount;
}
```

這 function 需要將紀錄發行量的 treasury object 當作參數放入其中，並藉此更動發行量

但由於第一個參數是 object，在 Sui， object 的所有權依附在 account 底下，因此，能觸發這個 function 的 account，只有擁有 treasury 的 account，因為這樣才能將 object 當作參數放入 function 中

因為在 Sui 中，不能隨意存取別人的 object，將它當作參數放入，只能放入自己的 object，因此只要 treasury 的所有權沒有傳送出去，別人就不可能把不屬於他的 treasury object 放入上面的 function 藉此改變發行量

# 總結

## 資源導向的設計

Sui 官方強調的是，他們是主打遊戲跟資產的公鏈，我認為，如果遊戲內的物品多為 NFT 的形式，那 Sui 在遊戲上的支援相比與 EVM 要好上許多，因為 object 本身就可以視為一種 NFT，以及讓 object 附於 account 的架構，更貼近於現實世界，每個人都有自己的資產，且不能隨意掠奪他人的資產，也讓開發上更為直覺

## 同質化代幣

延續上點，因為所有的 object 都是類似於 NFT 的形式，因此反而在處理同質化代幣上變得有些難以處理，同質化代幣就相當於現實的錢，而 Sui 的紀錄上，token 是一堆一堆表示的，你可以隨意 merge 跟 split，並且每堆 token 都是一個 object，這個 object 裡面的欄位會紀錄 value 有多少，也因此，如果你想要傳送 token 給其他人，需要先將你想傳送的 vaule 從 object 中 split 出來，成為一個新的 object，再將這新 object 傳送出去，因為在 Sui 中，最小的傳送單位是 object，收到的人再將收到的 object merge 再一起 (object type 需要一樣)

也就是說，在 Sui 同質化代幣的處理上，需要不斷的 merge 跟 split，這部分要是開發者處理不好，就會造成多個散落的 object，在處理上比起 Solidity 單純做加減而言，是比較麻煩些

## 開發者資源匱乏

新語言新架構，會遇到文件不完整的狀況並不稀奇，但 Sui 還有遇到一些特殊的問題，例如說，因為 Sui 是以 Move 為基礎下去改良，Sui 文件上只有紀錄改動的部分，並沒有一個文件紀錄所有語法，需要先分別找出 Move 的語法，再搭配 Sui Standard Library，拼湊在壹起才能有一個比較好的學習體驗

另外在新手引導沒有比較完整的流程，在 Sui Docu 中雖然不斷強調資源導向，創建資源以及轉移是 Sui 主要的特點，但沒有**先提出 object 在這裡面扮演的角色為何**，資源是什麼，沒有一個比較具體的例子，因此雖然能照著文件建立 module 建立 object，但卻容易陷入不知道怎麼用的窘境 (因此在上述 Fundamental 中，先建立一個比較完整的認識)

至於 Sui SDK 的部分就很單純，文件還不夠齊備，以 sui.js 為例，常見的範例太少，蠻容易遇到 type 不知道怎麼轉換的問題，進一步考驗開發者的功力



