WEB3 的世界

探索 WEB3 的技術與應用,是進入數位新時代的關鍵。

智慧合約的基礎

說明 Solidity、Vyper 等語言特性與合約設計原則。

智慧合約的基礎

智慧合約結構概覽

智慧合約基礎:什麼是合約?

本篇文章將帶你深入了解智慧合約的核心:什麼是合約?從概念到實際應用,我們會以輕鬆有趣的方式說明。
你可能想知道,合約不只是紙上談兵,而是執行在區塊鏈上的自動化協議。接著我們會剖析它的結構、功能,甚至給你一段簡易的 Solidity 範例,讓你親手寫下第一個合約。

智慧合約基礎:什麼是合約?

在區塊鏈的世界裡,智慧合約就像是自動執行的魔法契約,當條件滿足時,它會自動把事情完成,完全不需要任何人來干預。

合約的兩大要素
  • 邏輯:一系列可以被執行的函式(functions)。
  • 資料:合約內部儲存的變數(state variables),像是帳戶餘額、所有權資訊等。
為什麼合約會被稱為「智慧」
  • 它在沒有任何第三方的情況下,根據預先設定好的條件自動執行。
  • 所有操作都在區塊鏈上公開透明,任何人都可以驗證其正確性。
合約的運作流程
  1. 用戶發送交易到區塊鏈。
  2. 交易被礦工打包進區塊,並付出 gas。
  3. 合約程式碼在虛擬機上執行,根據邏輯改變狀態。
  4. 執行結果寫入全網共識的區塊。
範例:簡易存儲合約

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

contract SimpleStorage {
uint256 public storedData;

function set(uint256 x) external {
    storedData = x;
}

function get() external view returns (uint256) {
    return storedData;
}

}

常見合約類型表格
類型 應用場景 主要功能
ERC‑20 代幣發行 可轉帳、餘額查詢
ERC‑721 NFT 唯一性資產管理
DAO 去中心化自治組織 投票、決策執行
進一步閱讀

常見的合約開發語言:Solidity、Vyper 與 Rust

若你正在踏進區塊鏈的世界,想知道哪些語言能讓你的智慧合約跑起來,那就先把畫面拉回到「語言」這個核心。<br><br>在 dApp 與生態系統的海洋裡,Solidity、Vyper 與 Rust 就像三條不同風格的航道:<br>Solidity 以以太坊為起點,Vyper 追求更簡潔與安全,Rust 則以其零成本抽象和高效運算成為多鏈新興選擇。<br><br>了解它們的差異,能幫你挑選最適合專案需求、又符合未來維護成本的開發語言。

常見的合約開發語言:Solidity、Vyper 與 Rust

在區塊鏈開發的世界裡,語言就像工具箱裡的各式扳手。以下面三個最受歡迎的語言為例,說明它們各自的特色、適用場景與學習曲線。

Solidity
  • 起源:以太坊官方推薦的語言,最早於 2015 年推出。<br> - 特色:面向合約導向,類似 JavaScript 或 C++ 的語法,支援事件、繼承與多重委派。<br> - 生態:擁有大量開源合約範例、工具鏈(Hardhat, Truffle)與社群資源。<br> - 學習曲線:對程式新手友善,但安全漏洞(如 reentrancy)常在實務中被突顯,需要謹慎審計。
// 典型的 ERC‑20 範例(簡化版)
pragma solidity ^0.8.17;

contract SimpleToken {
    string public name = "SimpleToken";
    string public symbol = "SIM";
    uint8 public decimals = 18;
    uint256 public totalSupply;

    mapping(address => uint256) balances;

    event Transfer(address indexed from, address indexed to, uint256 value);

    constructor(uint256 _initialSupply) {
        totalSupply = _initialSupply;
        balances[msg.sender] = _initialSupply;
    }

    function transfer(address _to, uint256 _value) external returns (bool) {
        require(balances[msg.sender] >= _value, "Insufficient balance");
        balances[msg.sender] -= _value;
        balances[_to] += _value;
        emit Transfer(msg.sender, _to, _value);
        return true;
    }
}
Vyper
  • 設計理念:以安全為導向,去除許多 Solidity 內的難懂特性。<br> - 語法:更接近 Python,強制使用明確類型與可預測的執行流程。<br> - 優勢:減少程式邏輯錯誤、降低複雜度,適合對安全要求極高的專案。<br> - 限制:功能相較 Solidity 更少,開發社群與工具鏈仍在成長階段。
# 典型的 Vyper ERC‑20 範例(簡化版)
name: public(String[64]) = "SimpleToken"
symbol: public(String[32]) = "SIM"
decimals: public(uint256) = 18
total_supply: public(uint256)
balances: HashMap[address, uint256]

@external
def __init__(_initial_supply: uint256):
    self.total_supply = _initial_supply
    self.balances[msg.sender] = _initial_supply

@external
def transfer(_to: address, _value: uint256) -> bool:
    assert self.balances[msg.sender] >= _value, "Insufficient balance"
    self.balances[msg.sender] -= _value
    self.balances[_to] += _value
    log Transfer(msg.sender, _to, _value)
    return True
Rust (Solang / Ink!)
  • 起源:原生於 Substrate 與 Polkadot,亦可透過 Solang 轉譯至以太坊。<br> - 特色:零成本抽象、所有權模型與型別安全,能在執行前捕捉大量錯誤。<br> - 生態:Ink! 提供開發框架,Solang 讓 Rust 能直接編譯為 EVM bytecode。<br> - 適用場景:需要高效能、低延遲或跨鏈執行的專案。
// 典型的 Ink! 合約範例(簡化版)
#![cfg_attr(not(feature = "std"), no_std)]

use ink_lang as ink;

#[ink::contract]
mod simple_token {
    #[ink(storage)]
    pub struct SimpleToken {
        total_supply: Balance,
        balances: Mapping<AccountId, Balance>,
    }

    impl SimpleToken {
        #[ink(constructor)]
        pub fn new(initial_supply: Balance) -> Self {
            let mut balances = Mapping::new();
            let caller = Self::env().caller();
            balances.insert(&caller, &initial_supply);
            Self { total_supply: initial_supply, balances }
        }

        #[ink(message)]
        pub fn transfer(&mut self, to: AccountId, value: Balance) -> bool {
            let from = Self::env().caller();
            let from_balance = self.balances.get(&from).unwrap_or(0);
            if from_balance < value { return false; }
            self.balances.insert(&from, &(from_balance - value));
            let to_balance = self.balances.get(&to).unwrap_or(0);
            self.balances.insert(&to, &(to_balance + value));
            true
        }
    }
}
何時選 Solidity?
  • 最適合於以太坊及其兼容鏈,因為語法與工具已成熟。<br> - 想快速迭代、利用大量現成合約或 NFT 標準者,Solidity 是首選。
何時選 Vyper?
  • 當安全性是首要考量,且想用更簡潔、可預測的語法撰寫合約。<br> - 避免複雜繼承或動態函式呼叫的專案適合。
何時選 Rust?
  • 要在 Substrate 系統中開發,或需要高效能與低延遲。<br> - 想利用 Rust 的型別安全、所有權模型,降低執行時錯誤。<br> - 想將同一份代碼部署至多條鏈(以太坊、Polkadot)時,Rust 轉譯工具能提供便利。
資源清單

透過對比這三種語言,你可以在 dApp 的藍圖中,挑選最適合的「開發語言」來搭建堅固、可維護且安全的智慧合約。

部署流程:從本地測試到主網上線

本篇教學將帶你從在開發環境裡跑測試,到最後把合約部署到公鏈主網。你會學到怎麼設定測試網、撰寫部署腳本,甚至如何確認合約已正確上線。
在這裡,我們會一步步拆解每個階段,並配合實際範例讓你能馬上落地。

部署流程:從本地測試到主網上線

1️⃣ 環境準備
  • 安裝 Node.js 與 npm,並全域安裝 Hardhat:npm install -g hardhat
  • 建立專案資料夾並執行 npm init -yhardhat init,選擇「Create an empty hardhat.config.js」
2️⃣ 撰寫合約與測試
  • contracts/ 資料夾放置 Solidity 檔案,例如 MyToken.sol
  • test/ 資料夾撰寫 JavaScript/TypeScript 測試,例如:

const { expect } = require("chai");
describe("MyToken", function () {
it("should deploy correctly", async function () {
const [deployer] = await ethers.getSigners();
const Token = await ethers.getContractFactory("MyToken");
const token = await Token.deploy();
await token.deployed();
expect(await token.owner()).to.equal(deployer.address);
});
});

3️⃣ 部署到測試網
  • hardhat.config.js 加入測試網路設定,例如 Goerli:

require("@nomiclabs/hardhat-ethers");
module.exports = {
solidity: "0.8.17",
networks: {
goerli: {
url: process.env.GOERLI_RPC_URL,
accounts: [process.env.PRIVATE_KEY],
},
},
};

  • 執行部署腳本:npx hardhat run scripts/deploy.js --network goerli
4️⃣ 驗證部署
  • 在 Goerli 上使用區塊瀏覽器(如 Etherscan)確認合約地址與交易紀錄。
  • 也可以使用 Hardhat 的 verify 任務:

npx hardhat verify --network goerli 0xYourContractAddress "Constructor args if any"

5️⃣ 上線主網
  • 重複第3步,但把 --network goerli 改成主網(例如:mainnet
  • 確保你已備妥主網私鑰並擁有足夠的 ETH 以支付 gas。

小結

  • 從本地到測試網再到主網,部署流程雖多步驟,但只要按順序操作,就能確保合約安全且可靠。
  • 建議使用 CI/CD 流程自動化測試與部署,減少人為失誤。

開發工具與環境設置

IDE 與框架:Remix、Hardhat、Truffle

在這篇文章裡,我們將帶你走進 Web3 開發的三個熱門 IDE 與框架:Remix、Hardhat 以及 Truffle。這些工具各有千秋,無論你是初學者還是資深開發者,都能在其中找到適合自己的開發環境。
接下來,我們會先簡介每個工具的核心功能,再提供實際範例與使用技巧,讓你能快速上手並寫出第一個可部署的 dApp。

Remix

Remix 主要是一個基於瀏覽器的 IDE,你只要打開網頁即可開始寫 Solidity 合約,特別適合快速迭代與測試。它內建了

  • 即時編譯:每次保存都會自動編譯,錯誤訊息即時顯示。
  • 合約部署:直接連結到 MetaMask 或內建的測試網路,省去繁瑣設定。
  • 插件擴充:可安裝各種擴充功能,例如 Solidity 靜態分析、單元測試等。

以下是一段簡短的 HelloWorld 合約範例:

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

contract HelloWorld {
string public greeting = "Hello, Remix!";

function setGreeting(string memory _greeting) public {
    greeting = _greeting;
}

function getGreeting() public view returns (string memory) {
    return greeting;
}

}

在 Remix 編輯器右側,你可以直接點擊「Compile」按鈕編譯,接著使用「Deploy & Run Transactions」面板部署合約並測試函式。

測試環境:Ganache、Foundry 與 Hardhat Network

本篇文章將帶你快速了解三大熱門測試環境:Ganache、Foundry 與 Hardhat Network。

這些工具不僅能幫你在本地模擬以太坊區塊鏈,還能提供快速部署、測試與除錯的便利。無論你是剛踏入 Web3 開發的新手,或是想提升開發效率的老手,都能從中找到適合自己的解法。

Ganache:以太坊測試鏈的老將

Ganache 由 Truffle 團隊推出,提供 GUI 與 CLI 兩種介面。GUI 讓人一眼就能看見交易記錄、區塊高度與帳戶餘額,適合視覺化操作;CLI 版本則能透過腳本快速產生多筆測試帳戶,方便自動化流程。

安裝方式

npm install -g ganache-cli # CLI 版本

ganache-cli --port 8545 --accounts 10 --defaultBalanceEther 1000

使用小技巧

  • 預設每筆交易都會立即確認,適合快速迭代。
  • 可利用 --deterministic 讓所有帳戶地址固定,方便寫測試。

Foundry:Rust + Solidity 的高效開發框架

Foundry 由 Paradigm 團隊打造,核心工具包括 forge(編譯、測試)與 cast(區塊鏈互動)。它採用 Rust 編譯器,編譯速度快且佔用記憶體小。

安裝方式

curl -L https://foundry.paradigm.xyz | bash # 下載並安裝

foundryup  # 更新工具
forge init myproject
cd myproject
forge build

測試範例
src/Counter.sol 中寫一個簡單的計數器,接著於 test/Counter.t.sol 撰寫 Solidity 測試:

// Counter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract Counter {
    uint256 count;
    function increment() public { count += 1; }
    function getCount() public view returns (uint256) { return count; }
}
// Counter.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "forge-std/Test.sol";
import "../src/Counter.sol";

contract CounterTest is Test {
    Counter counter;

    function setUp() public { counter = new Counter(); }

    function testIncrement() public {
        counter.increment();
        assertEq(counter.getCount(), 1);
    }
}
forge test --ffi

優點

  • 不需要額外的測試鏈;forge test 內建 anvil(類似 Ganache)
  • 支援 Solidity 本身的測試語法,無需額外框架。

Hardhat Network:以太坊開發環境的萬用工具

Hardhat 本身是一個完整的開發框架,內建測試網路與部署工具。其 hardhat network 能在本機即時啟動區塊鏈,並支援多種插件。

安裝與啟動

npm init -y

npm install --save-dev hardhat
npx hardhat init  # 建議先選擇腳本執行方式

hardhat.config.js 中設定網路:

module.exports = {
  solidity: '0.8.19',
  networks: {
    hardhat: {},
    localhost: { url: 'http://127.0.0.1:8545', chainId: 31337 }
  },
};

測試範例(使用 JavaScript)

// test/Counter.js
const { expect } = require('chai');
const { ethers } = require('hardhat');

describe('Counter', function () {
  let counter;
  before(async function () { counter = await ethers.getContractFactory('Counter').deploy(); });

  it('should increment', async function () { await counter.increment(); expect(await counter.getCount()).to.equal(1); });
});
npx hardhat test

這三者比較

工具 初學者友好度 編譯速度 內建測試鏈 生態系統
Ganache ★★★★ 中等 內建 Truffle
Foundry ★★★★☆ ★★★★★ 內建(Anvil) Paradigm
Hardhat ★★★★☆ ★★★★ 內建 ethers.js, Waffle 等

小貼士

  • 若你偏好 GUI,Ganache 是第一選擇;若追求最快編譯與測試速度,Foundry 會更適合。
  • Hardhat 支援多種插件(如 Waffle、Ethers)與 TypeScript,適合需要完整開發流程的專案。
  • 無論使用哪個工具,都建議先在本機執行 forge inithardhat create 產生範例專案,快速上手。

版本控制:Git、GitHub 與 GitLab 的最佳實踐

在這篇文章中,我們將深入探討版本控制的核心工具—Git、GitHub 與 GitLab,並且學習如何在 dApp 開發中運用它們來保護智慧合約與前端程式碼的完整性。
從基礎指令、分支策略,到最佳實踐與 CI/CD 整合,透過實例示範,你將能夠快速上手並建立一個乾淨、可維護且安全的開發流程。

1. 為什麼要使用 Git?

  • 版本追蹤:每一次修改都會被精準記錄,方便回溯。
  • 協作便利:多位開發者可同時在不同分支上工作,最後再合併。

2. Git 基本指令速查

git init          # 初始化專案
git add .         # 將檔案加入暫存區
git commit -m "訊息"  # 建立快照
git status        # 檢查目前狀態

3. 分支策略:GitFlow、Feature Branch、Release

  • GitFlow:適合大型專案,明確分隔開發與發布。
  • Feature Branch:每個功能一條獨立分支,完成後再合併到 main。
  • Release:在正式發布前,用來整合測試與 bug 修復。

4. GitHub 與 GitLab:差異與選擇

功能 GitHub GitLab
CI/CD Actions(免費) Pipelines(更細粒度設定)
Issue 跟踪 Issues、Projects Issue、Boards、Epics
存取權限 組織/個人、Public/Private 群組、Project、角色權限
預算 免費版足夠小型專案 完整功能在免費版也能使用

5. Pull Request / Merge Request 的最佳實踐

  • 寫清楚變更說明,並附上相關 Issue 編號。
  • 先執行 CI 測試,確保合併不會破壞現有功能。
  • 指派至少一名審查者,確保程式碼品質。

6. CI/CD 與 Smart Contract 測試整合

# .github/workflows/ci.yml
name: CI Pipeline
on:
  push:
    branches: [ main ]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install dependencies
        run: npm ci
      - name: Run tests
        run: npx hardhat test

7. 安全最佳實踐:SSH 金鑰、GPG 簽名

  • 產生 SSH 金鑰並加入 GitHub/GitLab,避免輸入帳號密碼。
  • 使用 GPG 進行 commit 簽名,提升可信度。

8. 常見陷阱與解決方案

  • 衝突 (Merge Conflicts):定期拉取主分支,使用 git rebase 先整合。
  • 錯誤提交到 main:使用 pre‑commit 或 CI 檢查 linttest
  • 倉庫過大:使用 .gitignore 排除大型檔案,必要時用 Git LFS。

參考資源

安全性與審計基礎

常見漏洞:重入、時間依賴與整數溢位

在區塊鏈世界裡,智慧合約就像是自動執行的程式碼,但如果寫得不夠慎重,可能會被攻擊者利用。

本文將聚焦三種常見漏洞:重入、時間依賴與整數溢位,帶你了解它們的危險、範例和防禦方法。

1️⃣ 重入漏洞(Reentrancy)

重入漏洞是指合約在向外部地址發送 Ether 或呼叫其他合約時,沒有先將狀態改變完成,導致攻擊者可以重複進入同一函式。

contract ReentrancyExample {
    mapping(address => uint) public balances;

    function deposit() external payable {
        balances[msg.sender] += msg.value;
    }

    // Vulnerable withdraw
    function withdraw() external {
        uint bal = balances[msg.sender];
        require(bal > 0, "No balance");
        (bool sent,) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send");
        balances[msg.sender] = 0; // <-- vulnerable point
    }
}

防禦方式:

  • Checks‑Effects‑Interactions 模式:先改變狀態,再發送 Ether。
  • 使用 pull payment 模式,讓使用者自己呼叫 withdraw
  • 在 Solidity 0.5+ 可用 ReentrancyGuard 合約來鎖定函式。

2️⃣ 時間依賴(Time Dependence)

許多合約會用 block.timestampnow 來做時間判斷,但這些值可以被礦工輕微操控,造成預期之外的行為。

function claimReward() external {
    require(block.timestamp >= unlockTime, "Too early");
    // ... 發放獎勵
}

防禦方式:

  • 使用 event logs 或外部或acles 來驗證時間。
  • 避免使用 block.timestamp 做為核心邏輯判斷,改用 交易序號區塊高度
  • 依賴複數礦工共識的時間判斷,減少單一礦工操控風險。

3️⃣ 整數溢位/下限(Integer Overflow & Underflow)

在 Solidity 0.8 之前,整數運算不會自動檢查溢位/下限,容易被利用為攻擊向量。

uint total = 2**256 - 1;
total += 1; // overflow to 0
```**防禦方式:**- 從 Solidity 0.8 開始,整數運算會自動檢查溢位/下限。
- 若使用舊版編譯器,可透過 OpenZeppelin 的 `SafeMath` 來包裝運算。
- 避免直接使用 `+=`, `-=` 等可能溢位的操作,改用安全函式。

#### 小結表格
| 漏洞 | 典型場景 | 防禦方式 |
|------|----------|-----------|
| 重入 | 以太幣轉移前未先更新狀態 | Checks‑Effects‑Interactions、ReentrancyGuard |
| 時間依賴 | `block.timestamp` 判斷是否達到特定時間 | 事件紀錄、外部 Oracle、使用區塊高度 |
| 整數溢位 | 大數運算導致 0 或負值 | Solidity 0.8+ 自動檢查、SafeMath |

>**小提醒**:在開發前先做安全審計,並持續觀察社群的最佳實踐,才能確保合約安全。

審計流程:從內部到第三方檢查

在 dApp 開發的生態系統裡,安全性像是防彈背心。審計不只是驗證程式碼沒有錯誤,更是對投資人、使用者的信任保證。今天我們從內部審計說起,接著走向第三方專家,最後把合約交到公眾的手上。

審計流程:從內部到第三方檢查

在 dApp 開發的生態系統裡,安全性像是防彈背心。審計不只是驗證程式碼沒有錯誤,更是對投資人、使用者的信任保證。今天我們從內部審計說起,接著走向第三方專家,最後把合約交到公眾的手上。

一、內部審計:團隊自檢

1️⃣ 先把合約拆成模組,逐塊跑單元測試。
2️⃣ 使用靜態分析工具(如 Slither、MythX)掃描潛在漏洞。
3️⃣ 交叉審查:至少兩位開發者對同一段程式碼進行手動審查。

以下是一個簡易的單元測試範例(Solidity + Hardhat):
describe('MyToken', function () {
it('should mint tokens correctly', async function () {
const [owner, addr1] = await ethers.getSigners();
const Token = await ethers.getContractFactory('MyToken');
const token = await Token.deploy();
await token.mint(addr1.address, 1000);
expect(await token.balanceOf(addr1.address)).to.equal(1000);
});
});

二、第三方安全公司審核

1️⃣ 選擇具備區塊鏈專業背景的審計機構(如 ConsenSys Diligence、Trail of Bits)。
2️⃣ 提供完整合約碼庫、開發文檔與測試報告。
3️⃣ 審計公司會進行靜態、動態及滲透測試,並發佈正式報告。

審計流程常見問答
問題 回覆
為什麼內部審計還要找第三方? 內部人可能忽略細節,第三方提供客觀視角。
第三方審計費用大概多少? 依合約大小、複雜度,通常 $10k ~ $50k 美金。
三、Bug Bounty:公眾驗證

1️⃣ 發布 Bug Bounty 計畫,吸引安全研究員尋找漏洞。
2️⃣ 提供獎金、認證,並在區塊鏈社群公布發現情況。
3️⃣ 收集所有報告後,修補漏洞並再次驗證。

四、審計報告發布與持續監控
  • 把最終審計報告公開於專案網站、GitHub 及區塊鏈瀏覽器。
  • 設定自動化監控腳本,偵測合約異常交易。
  • 定期重審:每 6 個月或合約功能升級後進行再審。

透過這套「內部 → 第三方 → 公眾」的審計流程,dApp 能夠在安全與信任兩端兼顧,讓投資人放心、使用者安心。

最佳實踐:代碼審查、函式隔離與最小權限原則

在這篇文章中,我們將探討如何透過代碼審查、函式隔離以及最小權限原則,讓智慧合約更安全、更可靠。

從實務角度出發,讀者將學會建立審查清單、撰寫安全的函式結構,並以範例程式碼說明每個概念如何落實。

代碼審查、函式隔離與最小權限原則

本章節將帶你從實務角度了解怎麼才能寫出更安全、更可靠的智慧合約。從代碼審查流程、函式隔離設計,到最小權限原則的落地實踐,結合範例程式碼說明。

1. 代碼審查的重要性
  • 確認程式邏輯無漏洞。
  • 及時發現潛在的資安風險。
  • 建立團隊共識,提升開發品質。
2. 審查流程(四步驟)

1️⃣ 建立審查清單:列出關鍵安全項目。
2️⃣ 靜態分析工具:利用 MythX、Slither 先自動掃描。
3️⃣ 人為審查:兩位以上開發者逐行閱讀。
4️⃣ 回饋迴圈:修正後再次自動測試。

3. 函式隔離:讓「功能」與「權限」分開

在 Solidity 中常見的做法是將外部可呼叫的函式設為 publicexternal,但內部邏輯則封裝成 private/internal,避免不必要的公開。以下是一個簡單範例:

pragma solidity ^0.8.24;

contract IsolationDemo {
    address public owner;

    constructor() payable {
        owner = msg.sender;
    }

    // 只有 owner 能呼叫的外部入口
    function setValue(uint256 _val) external onlyOwner {
        _updateInternal(_val);
    }

    // 內部邏輯,僅供本合約呼叫
    function _updateInternal(uint256 _val) internal {
        // ...
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not the owner");
        _;
    }
}
4. 最小權限原則(Least Privilege)
  • 限定存取:盡量使用 privateinternal 讓函式不被外部直接呼叫。
  • 權限分層:將全域管理者區隔為專門合約,其他功能則以 role 角色控制。
  • 動態調整:使用 OpenZeppelin 的 AccessControl,方便新增或刪減權限。
import "@openzeppelin/contracts/access/AccessControl.sol";

contract RoleBased is AccessControl {
    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN");

    constructor() {
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _setupRole(ADMIN_ROLE, msg.sender);
    }

    function privilegedAction() external onlyRole(ADMIN_ROLE) {
        // 只有 ADMIN 才能執行
    }
}
5. 實作小技巧與工具
工具 功能 為何推薦
MythX 靜態安全分析 產生漏洞報告
Slither 靜態代碼掃描 快速找出常見模式
Tenderly 部署測試網路 可視化交易跟蹤
6. 小結
  • 代碼審查:是發現漏洞的第一道防線。
  • 函式隔離:把「可調用」跟「實際演算」分開,降低面向攻擊的表面。
  • 最小權限:每個帳號只有執行其應該做的事,防止權限被濫用。

把這三個概念結合起來,就是打造安全 dApp 的基石。接下來,你可以在自己的專案裡先建立一個簡易審查清單,並用以上範例作為參考,慢慢將安全性融入日常開發。