Solidity程式語言教學 2026

20171

文章核心摘要
Solidity 是以太坊智能合約的主流程式語言,掌握它等於掌握了去中心化金融(DeFi)的開發鑰匙。本文從核心概念(型別、繼承、事件)出發,帶你實作一個具備基本金庫功能的合約,並深入探討 Gas 優化、常見安全漏洞(重入攻擊、整數溢位)以及進階設計模式。無論你是想打造自己的 DeFi 協議,還是想理解鏈上套利策略的底層邏輯,這篇進階指南都能幫助你扎穩根基。

📌 重點速覽

3+核心觀念
1完整實作案例
5Gas 優化技巧
3常見漏洞預防

1. Solidity 的核心型別與繼承機制

在進入進階主題前,我們先快速複習 Solidity 的基礎。雖然讀者已有基礎,但釐清型別與繼承的細節能避免日後踩坑。

Solidity 是靜態型別語言,支援值型別(uint、int、bool、address、bytes1~32)與參考型別(string、bytes、array、struct、mapping)。進階開發者需特別注意 mapping 不可迭代、struct 不能包含 mapping 以外的動態型別(如 array)等限制。

繼承方面,Solidity 使用 C3 線性化來解決鑽石問題,並支援 virtual/override 關鍵字。以下表格比較三種常見的繼承關鍵字組合:

關鍵字組合 用途 範例場景
virtual / override 允許子合約覆寫父合約函數 標準 ERC20 中的 transfer
abstract / virtual 定義抽象合約,強制子合約實作 OpenZeppelin 的 Ownable
interface / override 實作外部合約定義的函數簽名 IERC721 介面

Solidity 型別層級值型別uint, int, bool, addressbytes1~32, enum參考型別string, bytes, arraystruct, mapping特化型別address payablecontract type記憶體佈局不同可互相轉換圖 1:Solidity 主要型別分類

2. 事件(Event)與日誌(Log)的進階用法

事件是 Solidity 中將鏈上資料外洩的唯一方式,也是 DApp 前端監聽狀態變更的核心。進階開發者應該了解「索引參數」與「非索引參數」的 Gas 差異:最多三個 indexed 參數,每個會多花費 375 Gas(用於 topic),而非索引參數則被塞入 data 區域,成本較低。

此外,事件與 Solidityemit 語法從 0.8.0 版後強制使用。以下表格比較事件與函數回傳值的差異:

特性 事件 (Event) 函數回傳值
儲存至區塊鏈 ✅ 永久儲存於交易收據 ❌ 僅在執行時存在
外部讀取 ✅ 可被外部索引(如 The Graph) ❌ 需主動呼叫
Gas 成本 低(約 375+) 零(但可能增加運算)

事件參數 Gas 成本比較無 indexed~200 Gas1 個 indexed~575 Gas (200+375)3 個 indexed~1325 Gas (200+3*375)Gas圖 2:事件參數 indexed 數量對 Gas 影響

3. 實戰:建立一個具備金庫功能的合約

現在我們用 Solidity 打造一個簡單的金庫(Vault)合約,允許使用者存入 ETH,並在鎖倉期後提取。這是 DeFi 中常見的「時間鎖金庫」雛形。合約會使用 OpenZeppelin 的 ReentrancyGuard 防止重入攻擊。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract TimeLockVault is ReentrancyGuard {
    mapping(address => uint256) public balances;
    mapping(address => uint256) public unlockTime;
    uint256 public constant LOCK_PERIOD = 7 days;

    event Deposited(address indexed user, uint256 amount);
    event Withdrawn(address indexed user, uint256 amount);

    function deposit() external payable {
        require(msg.value > 0, "Zero deposit");
        balances[msg.sender] += msg.value;
        unlockTime[msg.sender] = block.timestamp + LOCK_PERIOD;
        emit Deposited(msg.sender, msg.value);
    }

    function withdraw() external nonReentrant {
        require(block.timestamp >= unlockTime[msg.sender], "Still locked");
        uint256 amount = balances[msg.sender];
        require(amount > 0, "No balance");
        balances[msg.sender] = 0;
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
        emit Withdrawn(msg.sender, amount);
    }
}
    

上述合約展示了 Solidity 中常見的存款、鎖倉、提取模式。注意我們使用了 call{value}() 而非 transfer(),因為後者 Gas 上限限制在 2300,可能導致轉帳失敗。

TimeLockVault 運作流程1. 使用者呼叫 deposit()發送 ETH2. 更新 balances設定 unlockTime3. 等待 7 天block.timestamp4. 呼叫 withdraw()傳送 ETH圖 3:金庫合約流程

4. Gas 優化技巧與常見錯誤

Solidity 開發中,Gas 成本直接影響使用者體驗。以下是五個經過實戰驗證的優化技巧:

技巧 做法 節省 Gas 量
使用 calldata 而非 memory 將 external 函數的陣列參數標為 calldata ~300+ per call
打包變數(packing) 將多個小於 256 bits 的變數放在一起 最高 2000+ per write
刪除不必要的 storage 寫入 使用 unchecked 或快取 storage 到 memory 2000+ per op
使用位元運算代替 if 判斷 value & 1 代替 value % 2 約 5~10 per op
避免重複的 SLOAD 將 storage 變數讀入 memory 再操作 2000+ per SLOAD
📝 小提醒: Gas 優化不能犧牲安全性。使用 unchecked 時務必手動處理溢位檢查。

5. 安全性:重入攻擊與整數溢位防護

Solidity 合約的安全漏洞歷史上造成數十億美元損失。最常見的是重入攻擊(Reentrancy)和整數溢位(Integer Overflow/Underflow)。從 0.8.0 版開始,Solidity 內建了溢位檢查(透過 require 自動拋出),但仍需注意 unchecked 區塊。重入攻擊可透過 ReentrancyGuard 或「檢查-生效-互動」模式防範。

以下表格摘要三種常見漏洞與對策:

漏洞類型 描述 防護方式
重入攻擊 攻擊者在提款時遞迴呼叫 withdraw 使用 nonReentrant 修飾符
整數溢位 加法超過 uint256 最大值 使用 Solidity 0.8+ 或 SafeMath
委託呼叫(delegatecall)混淆 錯誤使用 delegatecall 導致儲存槽被覆蓋 明確分隔邏輯合約與儲存合約

6. 進階設計模式:代理合約與庫

在大型 DeFi 專案中,Solidity 開發者常用「代理合約模式」實現可升級合約,避免重新部署後資料遺失。常見的標準有 EIP-1967 透明代理和 UUPS 模式。此外,library 可讓我們重複使用程式碼,減少部署成本。例如 OpenZeppelin 的 AddressArrays 等庫。

為了讓讀者快速上手,下方整理代理合約三種實作方式的比較:

模式 優點 缺點
透明代理 (Transparent) 簡單明瞭,管理員與使用者角色分離 每次呼叫需檢查 admin,Gas 較高
UUPS 升級邏輯寫在實作合約,Gas 較低 需小心升級函數被攻擊
信標代理 (Beacon) 多個代理共用同一實作,節省儲存 管理複雜,升級影響所有代理

FAQ:常見問題

Q1: Solidity 0.8 版之後還需要 SafeMath 嗎?

不需要。0.8 版內建了溢位檢查,a + b 若溢位會自動 revert。但若你在 unchecked 區塊中,仍需手動檢查。

Q2: 如何測試 Solidity 合約?

推薦使用 Foundry(forge)或 Hardhat。Foundry 速度快且支援 fuzz testing,是進階開發者的首選。

Q3: 什麼是 ABI?為什麼需要它?

ABI(Application Binary Interface)定義了合約函數的簽章與編碼規則。前端 DApp 透過 ABI 與合約互動,沒有 ABI 就無法呼叫合約函數。

Q4: Solidity 支援多繼承,順序會影響什麼?

繼承順序決定了 C3 線性化結果,影響 super 的呼叫鏈。若順序錯誤可能導致函數被意外覆蓋。

Q5: 部署合約到主網需要多少 ETH?

視合約大小與 Gas 價格而定。一個簡單的 ERC20 約需 0.01~0.05 ETH,複雜的 DeFi 協議可能需 0.5 ETH 以上。建議使用 Gas 估算工具。

結論:從學到用,開始你的 Solidity 實戰

本文帶你深入了 Solidity 的核心型別、事件進階用法、實戰金庫合約、Gas 優化、安全性以及代理模式。接下來,建議你實際撰寫一個簡單的 DeFi 協議(如 Uniswap V2 的精簡版),並使用 Foundry 進行測試。若想進一步將智能合約應用於理財策略,可參考本站的套利與期貨交易策略教學。

👉 立即學習套利策略

延伸閱讀

外部參考資源

Solidity智能合約以太坊DeFiGas 優化安全漏洞代理合約

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

返回頂端