Solidity 智能合約簡介
作者 Daniel Idowu
Solidity 智能合約有多種用途,從多重簽章錢包到去中心化交易所都有。Solidity 是專為建立智能合約而生的主要 web3 程式語言之一,因此普及度持續上升。
本文將介紹 Solidity 智能合約、其運作方式與特性。我們也會帶你了解 Solidity 智能合約的語法與資料型別,讓你開始能夠與 Solidity 智能合約互動,運用在你的下一個專案中。若想進一步充實你的 Solidity 知識,可以完成 Alchemy University 的免費 Solidity 語法課程。
什麼是 Solidity 智能合約?
Solidity 智能合約是一個以 Solidity 撰寫、部署到 Ethereum 區塊鏈、並在 Ethereum Virtual Machine(EVM)中執行的程式。Ethereum 會將智能合約的程式碼與資料(其狀態)儲存在指定的位址上。
當預先設定的條件成立時,儲存在區塊鏈上的程式(即智能合約)便會執行,不需要中介者參與。換句話說,智能合約是控制 Ethereum 狀態內帳戶行為的程式。
你可以用 Solidity 或任何其他相容 EVM 的程式語言撰寫智能合約。這些程式必須先編譯成位元組碼(bytecode),才能與 EVM 相容。
Solidity 是一種物件導向、高階的智能合約撰寫語言。以 Solidity 撰寫的智能合約可用於各種用途,例如投票、群眾募資、盲拍以及多重簽章錢包。
智能合約如何運作?
智能合約是儲存在區塊鏈上的程式。智能合約以程式碼強化各方之間的協議,並在預設條件成立時自動執行規則。這代表智能合約涉及的所有各方能立即確定結果,不需耗費時間,也不需第三方介入。智能合約還能自動化工作流程,在執行後觸發下一個事件。
遵循 ERC20 標準的智能合約被視為 ERC20 代幣。ERC20 代幣允許代幣持有者之間互相轉移代幣。
Solidity 智能合約有哪些特性?
智能合約本質上是不可變且具確定性的。這代表一旦智能合約部署或建立在 Ethereum 上,除非其中已編寫觸發自毀(self-destruct)的條件,否則它將永遠存在。程式碼將永遠按其設定的條件執行。
此外,智能合約具有確定性,因為每個網路節點在給定相同輸入時,對同一個方法都能得出相同結果。若不同節點在執行智能合約時得出不同結果,便違反了共識協議,該智能合約也將無法使用。
智能合約也是無需許可(permissionless)的,這代表任何擁有 ETH 且能連上網際網路的人,都能在 Ethereum 上部署智能合約。
最後,智能合約具有可組合性(composable)。這代表你可以將其他專案的智能合約當作組件,用於自己的專案中。智能合約可以被視為開放的 API,使用者不需要自行撰寫智能合約就能成為 dApp 開發者,只需要知道如何與它們互動即可。
Solidity 智能合約語法
雖然坊間有許多資源可以幫助你開始學習 Solidity,本節將概述撰寫 Solidity 智能合約時所使用的語法。
1. 合約(Contracts)
Solidity 中的合約類似於物件導向語言中的類別(class)。每個合約可以包含狀態變數(State Variables)、函式(Functions)、函式修飾器(Function Modifiers)、事件(Events)、錯誤(Errors)、結構型別(Struct Types)以及列舉型別(Enum Types)的宣告。本文將更詳細討論建構子(Constructors)、狀態變數與整數變數。此外,合約還可以繼承其他合約。
還有一種特殊的合約,稱為函式庫(library)與介面(interface)。
2. 語意化版本控制
Solidity 和大多數軟體一樣,採用語意化版本控制(semantic versioning)。這代表除非更新的是主要版本號,否則不會有重大變更。你可以在文件上查看每個 Solidity 版本引入的主要重大變更。截至 2022 年 8 月,Solidity 最新的版本為 v0.8.16。
3. 建構子(Constructor)
建構子只會在部署(即合約建立)時被呼叫一次。建構子是使用 constructor 關鍵字宣告的選用函式,讓你能夠執行合約的初始化程式碼。
在建構子程式碼執行之前,狀態變數會先被初始化:若你以行內方式初始化,則設為指定值;若沒有,則設為預設值。
建構子執行完畢後,合約最終的程式碼便會部署到區塊鏈上。
如果沒有建構子,合約會採用預設建構子。
4. 狀態變數
狀態變數是其值儲存在合約儲存空間(storage)中的變數。每個函式都有自己的作用域,而狀態變數應該永遠定義在該作用域之外。
狀態變數遵循可見性(visibility)規則。你可以使用 public 可見性關鍵字將狀態變數設為公開,這會提供一個 getter 函式,讓其他智能合約可以存取。
5. 修飾(Modification)
在 Solidity 中,修飾器(modifier)以宣告方式修改函式的語意。換句話說,修飾器會改變其所附加函式的行為。修飾器有助於消除程式碼冗餘,並可在智能合約中的多個函式中重複使用,用於檢查相同的條件。
6. 整數變數
Solidity 中有兩種整數變數:無號整數(uint)與有號整數(int)。有號整數是一種可以儲存正值與負值的值型別。而無號整數則沒有符號,因此是一種必須為非負值的值型別。
Solidity 資料型別
如同其他程式語言,Solidity 有多種資料型別分類。然而,Solidity 的獨特之處在於,多種基本資料型別可以組合成更複雜的資料型別。本節將概述 Solidity 中的主要資料型別。
1. 布林值(Booleans)
布林值在 Solidity 中以 bool 表示,其可能的值為常數 true 與 false。
2. 字串(Strings)
字串字面值可以用雙引號或單引號撰寫。字串也可以拆分成多個連續的部分,這在處理長字串時會很有幫助。
3. 數字(Numbers)
Fixed 與 ufixed 分別代表各種大小的有號與無號定點數(fixed point numbers)。
4. 位元組(Bytes)
在 Solidity 中,byte 指的是 8 位元的有號整數。位元(bit)以二進位值 0 或 1 的形式儲存在記憶體中。在 Solidity 中,資料型別 byte 代表一連串的位元組。
Solidity 中有兩種位元組型別:固定大小位元組陣列(fixed-sized byte arrays)與動態大小位元組陣列(dynamically-sized byte arrays)。關鍵字 bytesX 用於定義變數,其中 X 代表位元組序列的長度,範圍從 1 到 32。
Solidity 中的 bytes 代表一個動態的位元組陣列。然而,它並非值型別(value type)。
5. 位址(Address)
address 儲存 20 位元組的值,這也是 Ethereum 位址的大小。通過位址檢查碼(checksum)測試的十六進位字面值屬於 address 型別。長度介於 39 到 41 位數之間、但未通過檢查碼測試的十六進位字面值會產生錯誤。你可以在整數型別前補零,或在 bytesNN 型別後補零,以消除該錯誤。
6. 可支付位址(Payable address)
可支付位址(payable address),以 address payable 表示,與 address 類似,但額外具有 transfer 與 send 成員。這樣的區分是必要的,因為一般的 address 可能是未設計成接收 Ether(ETH)的智能合約。address payable 則是可以向其發送 Ether 的位址。
7. 列舉(Enums)
列舉(Enums),在 Solidity 中也稱為 enumeration values,是建立使用者自定義型別的一種方式,可用來建立常數值,例如整數常數的名稱。相較於基本值型別,列舉能讓智能合約更容易閱讀與維護。
列舉可以顯式地與所有整數型別互相轉換,但不允許隱式轉換。從整數進行顯式轉換時,會在執行期檢查該值是否落在該列舉的範圍內,否則會導致 panic 錯誤。因此,列舉能降低程式碼中出現錯誤的機率。
列舉至少需要一個成員,宣告時的預設值為第一個成員。列舉最多不能超過 256 個成員。
8. 陣列(Arrays)
陣列是一組相同資料型別的變數,每個變數都有唯一的索引。陣列可以在編譯期就有固定大小,此時稱為固定陣列(fixed arrays);也可以有動態大小,此時稱為動態陣列(dynamic arrays)。
固定大小陣列在宣告時就有預先定義的大小。不能使用 new 關鍵字來新增額外的陣列成員,必須以行內方式初始化資料變數。
動態大小陣列在宣告時沒有預先定義的大小,其大小是在執行期決定的。
陣列元素可以是任何型別,包括 mapping 或 struct(一種使用者自定義的資料結構)。
9. 映射(Mappings)
在 Solidity 中,mapping 的運作方式類似於雜湊表(hash table),或其他程式語言中的字典(dictionary)。mapping 作為一種參考型別(reference type),以鍵值對的形式儲存資料,其中鍵可以是除了參考型別以外的任何內建資料型別,而值則可以是任何型別。
如果一個 mapping 型別的狀態變數是 public 的,Solidity 會自動為你建立一個 getter 函式。
10. 結構(Structs,使用者自定義型別)
struct(結構)讓你能夠定義新的資料型別。struct 型別可以用在 mapping 與陣列內部,並且它們本身也可以包含巢狀的 mapping 與陣列。然而,struct 不能包含其自身型別的成員,因為 struct 的大小必須是有限的。
什麼是智能合約情境(context)?
智能合約情境提供關於交易所在執行環境的資訊。 當智能合約函式透過交易被呼叫時,被呼叫的函式會收到一些額外傳入的資訊。在智能合約函式內,你可以存取這些情境變數。
你可以存取訊息發送者(message sender)、gas 價格,以及該交易所執行的測試。因此,你可以在程式碼邏輯中交替使用一系列的情境變數。
報名 Ethereum 開發者訓練營以進一步學習
在本文中,我們介紹了 Solidity 智能合約入門的基礎知識,並概述了關鍵的資料型別與語法,以增進你的理解。報名 Alchemy 的免費線上 Ethereum Developer Bootcamp,以進一步學習如何使用 Solidity 建立智能合約。如果開發者對開發完全是新手,Alchemy University 的三週 JavaScript for Ethereum 速成課程會是很好的先修課程。
相關總覽

打造區塊鏈魔法
Alchemy 結合最強大的 Web3 開發者產品與工具,並提供資源、社群與卓越的支援。


