智慧型合約語言
最後編輯: @K0ue1(opens in a new tab), 2024年6月17日
以太坊一大好處是,對開發者而言,編寫智慧型合約的語言相對簡單。 如你熟悉 Python 或任何大括號語言(opens in a new tab),會發現其實他們的語法非常相似。
兩種最熱門、最受管理的語言為:
- Solidity
- Vyper
經驗更豐富的開發者可能也會想使用 Yul,這是以太坊虛擬機的中階語言,或是使用 Yul 的延伸語言 Yul+。
若你有興趣,且想協助測試還處於大力開發階段的新語言,可以實驗仍在發展初期的新興智慧型合約語言 Fe。
基本資訊
如果已經有編程語言的知識,特別是 JavaScript 或 Python,可以幫助你瞭解智慧型合約語言的差異。 同時,我們建議你在深入理解語言差異之前,先理解智慧型合約的概念。 智慧型合約簡介。
Solidity
- 實作智慧型合約的物件導向高階語言。
- 深受 C++ 語言影響的大括號語言。
- 靜態類型(編譯時已知變數類型)。
- 支援:
- 繼承(你可以延展其他合約)。
- 資料庫(你可以建立能從不同的合約調用的可重複使用代碼,如同其他物件導向程式語言中的靜態類別靜態函數)。
- 複雜的使用者定義類型。
重要連結
- 文件(opens in a new tab)
- Solidity 語言入口網站(opens in a new tab)
- Solidity by Example(opens in a new tab)
- Github(opens in a new tab)
- Solidity Gitter Chatroom(opens in a new tab) 橋接 Solidity Matrix Chatroom(opens in a new tab)
- 懶人包(opens in a new tab)
- Solidity 部落格(opens in a new tab)
- Solidity Twitter(opens in a new tab)
合約範例
1// SPDX-License-Identifier: GPL-3.02pragma solidity >= 0.7.0;34contract Coin {5 // 關鍵字 "public" 使變量可以被其它合約訪問6 address public minter;7 mapping (address => uint) public balances;89 // 事件Events允許客戶讀取你聲明的特定合約變更。10 event Sent(address from, address to, uint amount);1112 // Constructor構造代碼僅在合約創建時執行一次。13 constructor() {14 minter = msg.sender;15 }1617 // 發送一定數量新創建的代幣到某個地址。18 // 只有合約創建者可以調用。19 function mint(address receiver, uint amount) public {20 require(msg.sender == minter);21 require(amount < 1e60);22 balances[receiver] += amount;23 }2425 // 發送一定量已經存在的代幣26 // 從調用者到任意地址27 function send(address receiver, uint amount) public {28 require(amount <= balances[msg.sender], "Insufficient balance.");29 balances[msg.sender] -= amount;30 balances[receiver] += amount;31 emit Sent(msg.sender, receiver, amount);32 }33}顯示全部複製
這個範例應該能讓你瞭解 Solidity 的合約語法。 關於函數和變數的詳細描述,請參閱文件(opens in a new tab)。
Vyper
- Python 程式語言
- 強輸入類型
- 精巧易懂的編譯器代碼
- 有效率的產生位元組碼
- 為了提升合約安全性並更容易審核,特意提供比 Solidity 更少功能。 Vyper 不支援:
- 修飾符
- 繼承
- 內嵌組譯碼
- 函數重載
- 運算子重載
- 遞迴調用
- 無限長度迴圈
- 二進制定點
如需更多資訊,請參閱 Vyper 原理(opens in a new tab)。
重要鏈結
- 文件(opens in a new tab)
- Vyper by Example(opens in a new tab)
- 更多 Vyper by Example(opens in a new tab)
- Github(opens in a new tab)
- Vyper 社群 Discord 聊天(opens in a new tab)
- 懶人包(opens in a new tab)
- Vyper 的智慧型合約開發框架與工具
- VyperPunk:瞭解如何保障與駭客攻擊 Vyper 智慧型合約(opens in a new tab)
- VyperExamples:Vyper 漏洞範例(opens in a new tab)
- 支援開發的 Vyper Hub(opens in a new tab)
- Vyper 最熱門的智慧型合約範例(opens in a new tab)
- 出色的 Vyper 精選資源(opens in a new tab)
範例
1# Open Auction23# Auction params4# Beneficiary receives money from the highest bidder5beneficiary: public(address)6auctionStart: public(uint256)7auctionEnd: public(uint256)89# Current state of auction10highestBidder: public(address)11highestBid: public(uint256)1213# Set to true at the end, disallows any change14ended: public(bool)1516# Keep track of refunded bids so we can follow the withdraw pattern17pendingReturns: public(HashMap[address, uint256])1819# Create a simple auction with `_bidding_time`20# seconds bidding time on behalf of the21# beneficiary address `_beneficiary`.22@external23def __init__(_beneficiary: address, _bidding_time: uint256):24 self.beneficiary = _beneficiary25 self.auctionStart = block.timestamp26 self.auctionEnd = self.auctionStart + _bidding_time2728# Bid on the auction with the value sent29# together with this transaction.30# The value will only be refunded if the31# auction is not won.32@external33@payable34def bid():35 # Check if bidding period is over.36 assert block.timestamp < self.auctionEnd37 # Check if bid is high enough38 assert msg.value > self.highestBid39 # Track the refund for the previous high bidder40 self.pendingReturns[self.highestBidder] += self.highestBid41 # Track new high bid42 self.highestBidder = msg.sender43 self.highestBid = msg.value4445# Withdraw a previously refunded bid. The withdraw pattern is46# used here to avoid a security issue. If refunds were directly47# sent as part of bid(), a malicious bidding contract could block48# those refunds and thus block new higher bids from coming in.49@external50def withdraw():51 pending_amount: uint256 = self.pendingReturns[msg.sender]52 self.pendingReturns[msg.sender] = 053 send(msg.sender, pending_amount)5455# End the auction and send the highest bid56# to the beneficiary.57@external58def endAuction():59 # It is a good guideline to structure functions that interact60 # with other contracts (i.e. they call functions or send ether)61 # into three phases:62 # 1. checking conditions63 # 2. performing actions (potentially changing conditions)64 # 3. interacting with other contracts65 # If these phases are mixed up, the other contract could call66 # back into the current contract and modify the state or cause67 # effects (ether payout) to be performed multiple times.68 # If functions called internally include interaction with external69 # contracts, they also have to be considered interaction with70 # external contracts.7172 # 1. Conditions73 # Check if auction endtime has been reached74 assert block.timestamp >= self.auctionEnd75 # Check if this function has already been called76 assert not self.ended7778 # 2. Effects79 self.ended = True8081 # 3. Interaction82 send(self.beneficiary, self.highestBid)顯示全部複製
此範例應該能讓你瞭解 Solidity 的合約語法。 關於函數和變數的詳細描述,請參閱文件(opens in a new tab)。
Yul 和 Yul+
如果你是以太坊新手並且尚未使用過智慧型合約語言編碼,建議你從 Solidity 或 Vyper 開始。 只有在你熟悉智慧型合約安全性最佳案例和使用以太坊虛擬機的具體細節後,才可投入 Yul 或 Yul+。
Yul
- 以太坊的中階語言。
- 支援以太坊虛擬機和 eWASM(opens in a new tab),一種以太坊風格的 WebAssembly,目的在於成為兩個平台均可使用的通用工具。
- 高級最佳化階段的優良目標,能使以太坊虛擬機和 eWASM 平台均等受益。
Yul+
- Yul 的低階高效延伸語言。
- 最初設計用於樂觀卷軸合約。
- Yul+ 可以被視為 Yul 的實驗性升級建議,為其添加新功能。
重要鏈結
- Yul 文件(opens in a new tab)
- Yul+ 文件(opens in a new tab)
- Yul+ 訓練場(opens in a new tab)
- Yul+ 介紹文章(opens in a new tab)
合約範例
以下簡單範例採用冪函數。 它可以使用 solc --strict-assembly --bin input.yul
編譯。 這個範例應該 儲存在 input.yul 檔案中。
1{2 function power(base, exponent) -> result3 {4 switch exponent5 case 0 { result := 1 }6 case 1 { result := base }7 default8 {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 月推出。
重要鏈結
- Github(opens in a new tab)
- Fe 發布聲明(opens in a new tab)
- Fe 2021 開發藍圖(opens in a new tab)
- Fe Discord 聊天室(opens in a new tab)
- Fe Twitter(opens in a new tab)
合約範例
以下為採用 Fe 的簡單合約。
1type BookMsg = bytes[100]23contract GuestBook:4 pub guest_book: map<address, BookMsg>56 event Signed:7 book_msg: BookMsg89 pub def sign(book_msg: BookMsg):10 self.guest_book[msg.sender] = book_msg1112 emit Signed(book_msg=book_msg)1314 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)