今天,我們終於要來點有成就感的實作了——發行屬於我們自己的加密貨幣(代幣)!
在以太坊上,發行代幣最普及的標準就是 ERC20。幾乎所有你在交易所買賣的非原生代幣(例如 USDT、USDC、UNI 等)都是基於這個標準構建的。今天,我們將在 Foundry 開發環境中,實作並部署一個符合資安標準的 ERC20 代幣。
什麼是 ERC20 標準?
在早期的區塊鏈發展中,每個人寫代幣合約的格式都不一樣,這導致錢包軟體(如 MetaMask)和交易所要花極大的力氣去客製化對接每一個代幣。
為了解決這個問題,以太坊社群提出了 ERC20(Ethereum Request for Comments 20)標準。它本質上就是一個「介面(Interface)」,規定了代幣合約必須實作的幾個核心函數與事件,例如:
資安鐵則:不要重新發明輪子 (Don't Roll Your Own Crypto)
身為資安系的學生,我們都聽過一句名言:「永遠不要自己發明密碼學演算法」。在 Web3 世界,這句話同樣適用:「永遠不要從零手寫標準合約的底層邏輯」。
即使 ERC20 的邏輯看起來只是簡單的加減法,但如果在處理整數溢位、授權檢查時漏掉了一個細節,都可能導致代幣被駭客無限增發。因此,業界的標準作法是直接繼承經過無數頂尖資安公司稽核過的開源函式庫——OpenZeppelin。
實戰:在 Foundry 中使用 OpenZeppelin 發幣
首先,打開我們在 Day 9 建立的 Foundry 專案,在終端機輸入以下指令來安裝 OpenZeppelin 函式庫:
'''
forge install OpenZeppelin/openzeppelin-contracts --no-commit
'''
接著,在專案的 src/ 資料夾下建立一個名為 MySecureToken.sol 的檔案,寫下我們的代幣合約:
'''
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// 引入 OpenZeppelin 的 ERC20 核心與 Ownable 權限控制模組
import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-contracts/contracts/access/Ownable.sol";
// 我們的合約同時繼承了 ERC20 與 Ownable
contract MySecureToken is ERC20, Ownable {
// 建構子:在部署時設定代幣名稱為 "Secure IoT Token",代號為 "SIT"
// 同時將部署者 (msg.sender) 設為合約的 Owner
constructor() ERC20("Secure IoT Token", "SIT") Ownable(msg.sender) {
// 在部署的瞬間,先發行 1,000,000 顆代幣給部署者
// 注意:Solidity 沒有小數點,ERC20 預設有 18 位小數,所以要乘上 10**18
_mint(msg.sender, 1000000 * 10 ** decimals());
}
// 新增一個鑄造函數,允許合約擁有者未來繼續增發代幣
// onlyOwner 修飾子確保了只有 Owner 可以呼叫這個函數!
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
'''
程式碼資安解析
短短不到 30 行程式碼,我們就完成了一個具備完整功能且極度安全的代幣合約。
1.繼承力量大:透過 is ERC20,我們自動擁有了 transfer、balanceOf 等所有標準函數,且這些底層邏輯都已經內建了防溢位機制。
2.存取控制 (Access Control):我們引入了 Ownable 模組,並在 mint 函數加上了 onlyOwner 修飾子。如果今天駭客試圖呼叫 mint 來幫自己印鈔票,這筆交易會在執行第一步時就被 EVM 直接拒絕並退回 (Revert)。
存檔後,在終端機執行 forge build。如果出現編譯成功的綠字,恭喜你,你的第一顆 ERC20 代幣合約已經誕生了!
今天我們見識到了 OpenZeppelin 的強大,它讓我們能站在巨人的肩膀上,避開常見的初階資安陷阱,快速且安全地發行代幣。
但是,代幣發行出來後,如果不能交易,就只是一串沒有價值的數字。明天,在「Day 12: DeFi 應用實作:簡易的去中心化交易所 (DEX) 交易邏輯」中,我們將會實作一個讓代幣可以進行兌換的資金池邏輯。