從 GitHub 上的 awesome-move 開始閱讀更多不同的 Move 合約

本文介紹了如何從 GitHub 上的 awesome-move 來看看 Move 的所有在 GitHub 上的相關資源,並比較了 Move 和 Solidity 的 ERC-20 相關函式,並點出兩者最大差異的部分。

作者:師大科技系 PecuLab 蔡芸琤 (Pecu)

前情提要【智能合約簡介 Move on Aptos】,在文末提到,會帶著讀者們閱讀更多不同的 Move 合約。本文便是要從 GitHub 上的 awesome-move 來看看 Move 的所有在 GitHub 上的相關資源。

當讀者進到 https://github.com/MystenLabs/awesome-move 時,會在 README.md 上看到一個紫色的 awesom 小勳章,就代表這是個目錄類的 Repository。

找到 awesome 當深入學習的目錄起點,節省網路大海中撈開源資料的時間。

在開始科普 GitHub 各種徽章的小知識前,剛好在網路上看到這篇說明文 https://github.com/hueitan/blog/blob/master/articles/%E6%88%91%E5%9C%A8%20GitHub%20%E4%B8%8A%E5%AD%B8%E7%BF%92%20Open%20Source%EF%BC%8D%E5%BE%BD%E7%AB%A0%E7%AF%87.md,就直接分享過來,有興趣的讀者可自行去了解 GitHub 徽章的意義。

接下來,我要從 awesome-move 挑篇仿造以太坊的 ERC-20 的 Move 合約來進行類比說明。原始碼 https://github.com/move-language/move/blob/main/language/documentation/examples/experimental/basic-coin/sources/BasicCoin.move

就先從 BasicCoin 開始,學習在 Move 上寫出一個類似 ERC-20 的合約。

在 ERC-20 中,我們使用 OpenZeppeline 的公版合約來進行比對說明 https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol

先看一下 OpenZeppeline 公版的 ERC20 有哪些 Function,可在 https://docs.openzeppelin.com/contracts/4.x/api/token/erc20#erc20 找到詳細列表。

要直接從 ERC20.sol 原始碼閱讀也可以,但有個總表對應,會比較容易有個全局的概念。在這裡的 function 命名規則是,若在最前頭加入底線,例如 _transfer 就代表是內部函式,反之為 public 的外部函式,只要連上合約的錢包,都可執行 public function。

再來看一下 Move 版的 ERC20 的 public fun 有哪些

public fun publish_balance
public fun mint
public fun burn
public fun balance_of
public fun transfer

對照到 OpenZeppeline 公版的 ERC20 的 public function 就是

沒有對應的函式和 public fun publish_balance 有關
只有內部函式 function _mint 內容是對應到 public fun mint
只有內部函式 function _burn 內容是對應到 public fun burn
function balanceOf = public fun balance_of
function transfer = public fun transfer

先解釋 public fun publish_balance 在 Aptos上的用途,這是以太坊 ERC20 沒有的部分。

因為在【智能合約簡介 Move on Aptos】有提到,你的資料不是你的資料,所以,你所發行的代幣也不是你的代幣,而是需要透過鑄幣或是轉帳來獲得自己創建的代幣。public fun publish_balance 就是由使用者以及發行者,在接收代幣之前要調用的函式。

推薦延伸閱讀【Aptos開發者必看的模組設計】

接下來,繼續講解一個可完全對應 ERC20 的 public fun balance_of。

    public fun balance_of<CoinType>(owner: address): u64 acquires Balance {
        borrow_global<Balance<CoinType>>(owner).coin.value
    }

    spec balance_of {
        pragma aborts_if_is_strict;
        aborts_if !exists<Balance<CoinType>>(owner);
    }
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

在 Move 中,有多了段 spec balance_of,也是 Solidity 沒有的,spec 是性質規範 (property specification),也是【在 Aptos 上,透過 Typescript SDK 創建一個公版 NFT】有提到過,對於每個帳戶中的代幣呈現形式 (representation),會強制要求確認,在安全性上,智能合約會進行 spec 上定義的檢查行為。

pragma aborts_if_is_strict; 代表著,請合約在執行時要嚴格檢查 public fun balance_of 的異常中止的可能,若出現了合約中沒有列出的中止條件,要回報錯誤訊息。

aborts_if !exists<Balance<CoinType>>(owner); 代表著,public fun balance_of 只有一種中止條件,就是當 owner 沒持有 Balance<CoinType> 類型的資源 (resource) 時。而資源的屬性可參考 https://move-book.com/resources/what-is-resource.html

Solidity 的資源放在合約中,若是合約的 owner 私鑰被盜取,那所有的資產都會被攻擊,而 Move 的資源放在使用者自己的帳戶中,資源的所有權屬於使用者,合約的 owner 沒有修改的權限。

雖然大部分 Move 程式邏輯能對應到 Solidity,但因為 Move 比 Solidity 多了更多安全性的考量,這篇先點出兩者最大差異的部分,下周再繼續講這份程式碼的其他 public function 的運作細節。