跳至主要内容
Change page

智慧型合約的程式語言

頁面最後更新時間: 2026年2月26日

以太坊一大好處是,對開發者而言,編寫智慧型合約的語言相對簡單。 若您有 Python 或任何花括號語言 (opens in a new tab)的使用經驗,您就能找到語法熟悉的語言。

兩種最熱門、最受管理的語言為:

  • Solidity
  • Vyper

Remix 整合開發環境提供一個全面的開發環境,用於透過 Solidity 和 Vyper 語言建立和測試合約。 試用瀏覽器內的 Remix IDE (opens in a new tab) 開始編寫程式。

經驗更豐富的開發者可能也會想使用 Yul (一種 Ethereum Virtual Machine 的中介語言),或 Yul+ (Yul 的擴充)。

若你有興趣,且想協助測試還處於大力開發階段的新語言,可以實驗仍在發展初期的新興智慧型合約語言 Fe。

先決條件

如果已經有編程語言的知識,特別是 JavaScript 或 Python,可以幫助你瞭解智慧型合約語言的差異。 同時,我們建議你在深入理解語言差異之前,先理解智慧型合約的概念。 智能合約簡介

Solidity

  • 實作智慧型合約的物件導向高階語言。
  • 深受 C++ 語言影響的大括號語言。
  • 靜態類型(編譯時已知變數類型)。
  • 支援:
    • 繼承(你可以延展其他合約)。
    • 資料庫(你可以建立能從不同的合約調用的可重複使用代碼,如同其他物件導向程式語言中的靜態類別靜態函數)。
    • 複雜的使用者定義類型。

合約範例

1// SPDX-License-Identifier: GPL-3.0
2pragma solidity >= 0.7.0;
3
4contract Coin {
5 // 「public」關鍵字使變數
6 // 可從其他合約存取
7 address public minter;
8 mapping (address => uint) public balances;
9
10 // 事件讓用戶端對您宣告的
11 // 特定合約變更做出反應
12 event Sent(address from, address to, uint amount);
13
14 // 建構函式程式碼只會在合約
15 // 建立時執行
16 constructor() {
17 minter = msg.sender;
18 }
19
20 // 傳送一定數量的新代幣到某個地址
21 // 只能由合約建立者呼叫
22 function mint(address receiver, uint amount) public {
23 require(msg.sender == minter);
24 require(amount < 1e60);
25 balances[receiver] += amount;
26 }
27
28 // 從任何呼叫者傳送一定數量的現有代幣
29 // 到某個地址
30 function send(address receiver, uint amount) public {
31 require(amount <= balances[msg.sender], "餘額不足。");
32 balances[msg.sender] -= amount;
33 balances[receiver] += amount;
34 emit Sent(msg.sender, receiver, amount);
35 }
36}
顯示全部

這個範例應該能讓你瞭解 Solidity 的合約語法。 關於函式和變數的詳細說明,請參閱文件 (opens in a new tab)

Vyper

  • Python 程式語言
  • 強輸入類型
  • 精巧易懂的編譯器代碼
  • 有效率的產生位元組碼
  • 為了提升合約安全性並更容易審核,特意提供比 Solidity 更少功能。 Vyper 不支援:
    • 修飾符
    • 繼承
    • 行內組譯
    • 函數重載
    • 運算子重載
    • 遞迴調用
    • 無限長度迴圈
    • 二進制定點

更多資訊,請閱讀 Vyper 設計理念 (opens in a new tab)

範例

1# 公開拍賣
2
3# 拍賣參數
4
5# 受益人從最高出價者收到款項
6
7beneficiary: public(address)
8auctionStart: public(uint256)
9auctionEnd: public(uint256)
10
11# 目前拍賣狀態
12
13highestBidder: public(address)
14highestBid: public(uint256)
15
16# 結束時設為 true,不允許任何變更
17
18ended: public(bool)
19
20# 追蹤已退款的出價,以便遵循提款模式
21
22pendingReturns: public(HashMap[address, uint256])
23
24# 建立一個簡單的拍賣,競標時間為 `_bidding_time`
25
26# 秒,代表受益人地址 `_beneficiary`。
27
28@external
29def __init__(_beneficiary: address, _bidding_time: uint256):
30 self.beneficiary = _beneficiary
31 self.auctionStart = block.timestamp
32 self.auctionEnd = self.auctionStart + _bidding_time
33
34# 以與此交易一起傳送的價值
35
36# 參與競標。
37
38# 只有在未贏得拍賣時,
39
40# 價值才會被退還。
41
42@external
43@payable
44def bid():
45 # 檢查競標期是否結束。
46 assert block.timestamp < self.auctionEnd
47 # 檢查出價是否夠高
48 assert msg.value > self.highestBid
49 # 追蹤前一個最高出價者的退款
50 self.pendingReturns[self.highestBidder] += self.highestBid
51 # 追蹤新的最高出價
52 self.highestBidder = msg.sender
53 self.highestBid = msg.value
54
55# 提領先前已退款的出價。這裡使用提款模式
56
57# 以避免安全問題。如果退款是直接
58
59# 作為 bid() 的一部分傳送,惡意的競標合約可能會阻止
60
61# 這些退款,從而阻止新的更高出價進入。
62
63@external
64def withdraw():
65 pending_amount: uint256 = self.pendingReturns[msg.sender]
66 self.pendingReturns[msg.sender] = 0
67 send(msg.sender, pending_amount)
68
69# 結束拍賣並將最高出價
70
71# 傳送給受益人。
72
73@external
74def endAuction():
75 # 將與其他合約互動的函式 (即呼叫函式或傳送以太幣)
76 # 分為三個階段是一個好的指導方針:
77 # 1. 檢查條件
78 # 2. 執行動作 (可能改變條件)
79 # 3. 與其他合約互動
80 # 如果這些階段混雜在一起,其他合約可能會
81 # 回呼目前的合約,並修改狀態或導致
82 # 效果 (以太幣支付) 被多次執行。
83 # 如果內部呼叫的函式包含與外部
84 # 合約的互動,它們也必須被視為與
85 # 外部合約的互動。
86
87 # 1. 條件
88 # 檢查拍賣結束時間是否已到
89 assert block.timestamp >= self.auctionEnd
90 # 檢查此函式是否已被呼叫過
91 assert not self.ended
92
93 # 2. 效果
94 self.ended = True
95
96 # 3. 互動
97 send(self.beneficiary, self.highestBid)
顯示全部

此範例應該能讓你瞭解 Solidity 的合約語法。 關於函式和變數的詳細說明,請參閱文件 (opens in a new tab)

Yul 和 Yul+

如果你是以太坊新手並且尚未使用過智慧型合約語言編碼,建議你從 Solidity 或 Vyper 開始。 只有在你熟悉智慧型合約安全性最佳案例和使用以太坊虛擬機的具體細節後,才可投入 Yul 或 Yul+。

Yul

  • 以太坊的中階語言。
  • 支援 EVMEwasm (opens in a new tab) (一種以太坊風格的 WebAssembly),其設計目標是成為這兩個平台可用的共同基準。
  • 高級最佳化階段的優良目標,能使以太坊虛擬機和 eWASM 平台均等受益。

Yul+

  • Yul 的低階高效延伸語言。
  • 最初是為樂觀卷軸合約所設計。
  • Yul+ 可以被視為 Yul 的實驗性升級建議,為其添加新功能。

合約範例

以下簡單範例採用冪函數。 可以使用 solc --strict-assembly --bin input.yul 進行編譯。 這個範例應該 儲存在 input.yul 檔案中。

1{
2 function power(base, exponent) -> result
3 {
4 switch exponent
5 case 0 { result := 1 }
6 case 1 { result := base }
7 default
8 {
9 result := power(mul(base, base), div(exponent, 2))
10 if mod(exponent, 2) { result := mul(base, result) }
11 }
12 }
13 let res := power(calldataload(0), calldataload(32))
14 mstore(0, res)
15 return(0, 32)
16}
顯示全部

如果您對智能合約已有豐富經驗,可以在這裡 (opens in a new tab)找到 Yul 的完整 ERC20 實作。

Fe

  • 用於以太坊虛擬機 (EVM) 的靜態類型語言。
  • 受 Python 和 Rust 所啟發。
  • 目標是讓以太坊生態系統的新手開發者,都能輕鬆學習這門語言。
  • Fe 還處於早期開發階段,其 Alpha 版本於 2021 年 1 月推出。

合約範例

以下為採用 Fe 的簡單合約。

1type BookMsg = bytes[100]
2
3contract GuestBook:
4 pub guest_book: map<address, BookMsg>
5
6 event Signed:
7 book_msg: BookMsg
8
9 pub def sign(book_msg: BookMsg):
10 self.guest_book[msg.sender] = book_msg
11
12 emit Signed(book_msg=book_msg)
13
14 pub def get_msg(addr: address) -> BookMsg:
15 return self.guest_book[addr].to_mem()
16
顯示全部

如何選擇

與任何其他編程語言一樣,重點在於根據合適的工作與個人偏好選擇正確工具。

如果你還沒有嘗試過任何一種語言,請考慮以下幾點:

Solidity 的優點是什麼?

  • 如果你是初學者,有不少使用教學和學習工具。 更多相關資訊,請參閱透過編碼學習一節。
  • 提供優良的開發者工具。
  • Solidity 擁有龐大的開發者社群,這表示你很可能會很快找到問題的答案。

Vyper 的優點是什麼?

  • 適合想要編寫智慧型合約的 Python 開發者入門。
  • Vyper 的功能較少,因此非常適合快速製作創意原型。
  • Vyper 的目的是容易審查並盡可能提高人類可讀性。

Yul 和 Yul+ 的優點是什麼?

  • 簡單而實用的低階語言。
  • 允許更接近原始以太坊虛擬機,有助於最佳化合約的燃料使用量。

語言比較

若要比較基本語法、合約生命週期、介面、運算子、資料結構、函式、控制流程等,請參閱這份 Auditless 快捷手冊 (opens in a new tab)

延伸閱讀

這篇文章對你有幫助嗎?