✍️ Gate 廣場「創作者認證激勵計劃」優質創作者持續招募中!
Gate 廣場現正面向優質創作者開放認證申請!
立即加入,發布優質內容,參與活動即可瓜分月度 $10,000+ 創作獎勵!
📕 認證申請步驟:
1️⃣ 打開 App 首頁底部【廣場】 → 點擊右上角頭像進入個人主頁
2️⃣ 點擊頭像右下角【申請認證】,提交申請等待審核
注:請確保 App 版本更新至 7.25.0 或以上。
👉 立即報名:https://www.gate.com/questionnaire/7159
豪華代幣獎池、Gate 精美週邊、流量曝光等超 $10,000 豐厚獎勵等你拿!
📅 活動自 11 月 1 日起持續進行
在 Gate 廣場讓優質內容變現,創作賺取獎勵!
活動詳情:https://www.gate.com/announcements/article/47889
使用 Wake Printer 腳本自動化 Solidity 審計
前提條件和設置
在本教程中,我們將使用 workshop 倉庫作為範例專案:
wake up
Bash
複製
wake print
Bash
複製
按名稱運行特定的印表機:
教程 1:建立你的第一個印表機 – 列出合約
讓我們從一個簡單的印表機開始,它列出專案中的所有合約。此範例介紹了你將在更複雜的分析中使用的核心概念。
建立印表機結構
運行以下命令來搭建你的第一個印表機:
from __future__ import annotationsimport networkx as nximport rich_click as clickimport wake.ir as irimport wake.ir.types as typesfrom rich importprintfrom wake.cli import SolidityNamefrom wake.printers import Printer, printerclass ListContractsPrinter(Printer):def print(self) -> None:pass @printer.command(name=“list-contracts”)def cli(self) -> None:pass
Python
複製
以下是範本中每個部分的作用:
實作存取者模式
Wake 使用存取者模式來遍歷合約的抽象語法樹 (AST)。存取者模式允許 Wake 自動導航你的程式碼結構,使你能夠對特定元素(例如合約或函數定義)做出反應。
要列出合約,我們將覆寫 visit_contract_definition 方法,該方法會為程式庫中的每個合約呼叫。
將此方法加入你的 ListContractsPrinter 類別:
wake print list-contracts
Bash
複製
此命令運行你的印表機並列出在你的專案中找到的所有合約名稱。
改進輸出
基本實作顯示所有合約,包括介面和繼承的合約。讓我們改進它以僅顯示可部署的合約:
def visit_contract_definition(self, node: ir.ContractDefinition) -> None:iflen(node.child_contracts) != 0:returnif node.kind != ir.enums.ContractKind.CONTRACT:returnprint(node.name)
Python
複製
ContractDefinition 類別包含可用於篩選結果的屬性。有關完整參考,請參閱:
完整實作
這是最終版本,具有適當的關注點分離——在遍歷期間收集資料並在 print() 方法中顯示它:
教程 2:分析合約函數
了解哪些函數可從外部呼叫對安全性至關重要:公共 ‘withdraw’ 或 ‘transfer’ 函數通常定義了合約的攻擊面。讓我們建立一個印表機,透過列出所有公共和外部函數來繪製攻擊面。
設定函數印表機
建立一個新的印表機:
class ListFunctionsPrinter(Printer): contracts: list[ir.ContractDefinition] = []def visit_contract_definition(self, node: ir.ContractDefinition) -> None: self.contracts.append(node)
Python
複製
處理繼承層次結構
在 print() 方法中,我們遍歷從基合約到派生合約的繼承層次結構,顯示每個層級的可呼叫函數:
def get_callable_final_functions(self, contract: ir.ContractDefinition) -> list[ir.FunctionDefinition]:return [\ func for func in contract.functions\iflen(func.child_functions) == 0# 是最終實作\and func.visibility in [ir.enums.Visibility.PUBLIC, ir.enums.Visibility.EXTERNAL]\ ]
Python
複製
執行函數印表機
執行印表機以查看繼承層次結構和可呼叫函數:
Contract: ContextContract: OwnableFunctions: owner renounceOwnership transferOwnershipContract: SingleTokenVaultFunctions: constructor deposit withdraw emergencyWithdraw balanceOf setDepositLimits--------------------Contract: EIP712ExampleFunctions: constructor DOMAIN_SEPARATOR castVoteBySignature getVoteCounts--------------------Contract: ContextContract: IERC20Contract: IERC20MetadataContract: IERC20ErrorsContract: ERC20Functions: name symbol decimals totalSupply balanceOf transfer allowance approve transferFromContract: IERC20PermitContract: IERC5267Contract: EIP712Functions: eip712DomainContract: NoncesContract: ERC20PermitFunctions: permit nonces DOMAIN_SEPARATORContract: PermitTokenFunctions: constructor--------------------Contract: TokenFunctions: constructor mintTokens transfer transferWithBytes getBalance--------------------Contract: ContextContract: IERC20Contract: IERC20MetadataContract: IERC20ErrorsContract: ERC20Functions: name symbol decimals totalSupply balanceOf transfer allowance approve transferFromContract: MockERC20Functions: constructor--------------------
Bash
複製
輸出為你提供每個合約的繼承和可呼叫入口點的快速視覺化地圖。
@printer.command(name=“list-functions”)@click.option(“–contract-name”, type=str, required=False)def cli(self, contract_name: str | None) -> None: self.contract_name = contract_name
Python
複製
條件篩選邏輯
print() 方法現在檢查是否請求了特定的合約。如果沒有提供合約名稱,印表機將列出所有可部署的合約。如果指定了名稱,它將僅深入到該合約的層次結構中,即使它不是葉子合約也是如此。
完整實作與 CLI 選項
這是帶有可選合約篩選功能的最終印表機。
分析所有可部署的合约wake print list-functions## 專注於特定的合約wake print list-functions --contract-name Token
Bash
複製
後續步驟
印表機為你提供地圖;檢測器尋找漏洞。它們共同將 Solidity 審計從手動苦力轉變為結構化、有洞察力的過程。你撰寫的每個印表機都可以使複雜的程式碼更清晰——並增強你審查的智慧合約的安全性。
對於漏洞檢測,Wake 提供了一個單獨的檢測器系統,該系統超越了可視化來識別實際的安全問題。印表機為你提供地圖;檢測器尋找問題。
考慮將你的印表機貢獻回社群。分析工具在共享時最強大,你的自訂印表機可能會幫助其他審計員更有效地理解複雜的程式碼庫。