最近正在學習使用 Foundry,它是一個開發智能合約的工具包,作為與區塊鏈進行簡單互動的工具也很方便,由於測試與部署都是使用 solidity,也能幫助熟悉與練習這門語言。
Foundry (鑄造廠) 包含四個主要指令: forge (鍛造), cast (投擲), anvil (鐵砧) 和 chisel (鑿子),目前比較常用的只有 forge 和 cast。
forge 可以用來部署合約 (create, script)、測試合約 (test)、檢查合約 (inspect);cast 可以用來查詢資料 (call)、送交易 (send)、轉換資料 (to-hex, to-ascii)等等。
這系列應該許多地方會用到 foundry 的指令來進行說明,有興趣的人可以下載玩玩看。
今日打算帶大家做以下幾件事:
在 MacOS/Linux 環境底下可以使用
curl -L https://foundry.paradigm.xyz | bash
或參考官方文件 https://book.getfoundry.sh/getting-started/installation
安裝好後確認指令跑得動
forge -h
cast -h
開一個新的資料夾,在資料夾內下:
forge init
openzepplin 是 solidity 的套件包,可以先把它安裝起來:
forge install OpenZeppelin/openzeppelin-contracts
或是貼上 github 專案的 url,它會以 git submodules 的形式儲存
forge install https://github.com/Vectorized/solady.git
solady 也是一個合約的套件包。
在根目錄新增 remappings.txt,並寫上
@openzeppelin/=lib/openzeppelin-contracts/
為了在 solidity 引用 openzeppelin 時比較符合慣例,例如:
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
我自己為了方便下指令,如 --rpc-url=$sepolia
,因此會把一些常用的 rpc url 放在全域的環境變數,例如 .zshrc 或 .bashrc 裡面:
export sepolia=https://ethereum-sepolia-rpc.publicnode.com
export mainnet=https://ethereum-rpc.publicnode.com
你可以在 https://publicnode.com/ 或 https://chainlist.org/ 找到需要的 rpc url,或是到 alchemy 申請 api key 使用更穩定的節點。
為了方便使用 cast 送交易,不想每次都複製貼上私鑰,也為了安全性,可以將私鑰使用 cast wallet 儲存在 ~/.foundry/keystore
。
查看目前已建立的錢包
cast wallet list
印出一把新的公私鑰對
cast wallet new
新增私鑰到錢包,名稱叫 dev,最後要設定密碼
cast wallet import dev --private-key=<0x...>
使用私鑰簽章
cast sign "hello" --account dev
刪除錢包的話就直接把檔案刪掉( ⚠️ 請確保錢包裡沒有重要資產,或私鑰已得到妥善保存 ‼️
rm ~/.foundry/keystore/dev
為了使用 forge script 部署合約,在專案的根目錄新增 .env 檔,填上一個部署合約要用的私鑰。
PRIVATE_KEY=0x
ETHERSCAN_API_KEY=
加入 ETHERSCAN_API_KEY 可以讓我們在部署合約時,使用 --verify
讓合約在 etherscan 上被驗證。
-v
: verbosity,愈多 v 會印出愈多資訊,-vv
可以印出 logs。最多五個 -vvvvv
。--match-path
: 指定測試檔路徑,簡寫 --mp
。(簡寫可查閱 forge test -h
。)
forge test --mp test/Counter.t.sol -vvvv
--match-test
: 指定 function name 進行測試,若測試 function 名稱相同就一起跑。
forge test --mt test_Increment
修改預設的 script/Counter.s.sol,使用 .env 內的私鑰來部署合約。
function run() public {
uint256 deployer = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployer);
new Counter();
vm.stopBroadcast();
}
forge script script/Counter.s.sol --rpc-url $sepolia --broadcast --verify
如果不加 --broadcast 就只會在本地跑測試,合約不會部署上鏈。
如果合約的 constructor 簡單或者沒有 parameter,用這個部署挺方便~
forge create --rpc-url $sepolia --account dev test/utils/send.sol:A
使用 cast call 查詢合約資料
cast call \
0x060dE2a6a809d45Acb441cAEfE511842f4F109CD \
"number()" \
--rpc-url $sepolia
使用 cast send 送交易
cast send --account dev \
--rpc-url $sepolia \
0x060dE2a6a809d45Acb441cAEfE511842f4F109CD \
"setNumber(uint256)" \
20