編集中です。hardhatの使い方をよく聞かれるんですが、とにかく便利なfoundryを使いましょう!公式ドキュメントがしっかりしているので、それを読めば解決すると思いますが、サクッとまとめたものから随時アップしていきます。
はじめに
hardhatで開発するよりも断然効率よく開発できるのでfoundryがおすすめです。
Foundryのインストール
https://book.getfoundry.sh/getting-started/installation
VSCode環境構築
VSCodeを使用している方は、下記のページの設定を行うのがおすすめです。
https://book.getfoundry.sh/config/vscode
Foundryの準備を始める
まずは、リポジトリを作成
forge init hello_foundry
次にパッケージのインストールなどを行なっていきます。
下記のインストールは、サブモジュール方式になります。(おすすめです!)
forge install dapphub/ds-test
forge install openzeppelin/openzeppelin-contracts
forge install chiru-labs/ERC721A
forge install transmissions11/solmate
forge install thirdweb-dev/contracts
forge install dmfxyz/murky
forge install ProjectOpenSea/operator-filter-registry
※私がよく使っているものを記載しています。
次にリマッピングを行なっていきます。
forge remappings
を実行すると、すでに適用されているリマッピングが表示されます。
@chainlink/contracts/src/=lib/contracts/node_modules/@chainlink/contracts/src/
@ds-test/=lib/contracts/lib/ds-test/src/
@openzeppelin/=lib/contracts/node_modules/@openzeppelin/
@std/=lib/contracts/lib/forge-std/src/
ERC721A/=lib/ERC721A/contracts/
OpenSea-NFT-Template/=lib/OpenSea-NFT-Template/src/
contracts/=lib/contracts/contracts/
ds-test/=lib/ds-test/src/
erc4626-tests/=lib/operator-filter-registry/lib/openzeppelin-contracts/lib/erc4626-tests/
erc721a-upgradeable/=lib/contracts/node_modules/erc721a-upgradeable/
erc721a/=lib/contracts/node_modules/erc721a/
forge-std/=lib/forge-std/src/
murky/=lib/murky/src/
openzeppelin-contracts-upgradeable/=lib/operator-filter-registry/lib/openzeppelin-contracts-upgradeable/contracts/
openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/
operator-filter-registry/=lib/operator-filter-registry/src/
solmate/=lib/solmate/src/
フォルダ直下にremappings.txt
のファイルを作成し、その中に記載することで自由にリマッピングすることができます。
テスト作る際にちょこちょこ変更しますが、基本的に下記のものは常に記載しています。
@thirdweb/=lib/contracts/contracts/
@openzeppelin/=lib/openzeppelin-contracts/
erc721a/=lib/ERC721A/
operator-filter-registry/=lib/operator-filter-registry/src/
一旦テストを行なって、正常に動くか試してみましょう。
forge build
forge test
インストールされたテストが正常にパスすることが確認できると思います。
テストする際は、下記のようにコントラクトを指定してテストすることもできます。
forge test --match-contract Counter --match-test testIncrement
forge test --match-path test/Counter.t.sol
ログ表示については、複数段階あります。必要に応じて切り替えて使ってくださいね。
Level 1 (-v)
Level 2 (-vv)
Level 3 (-vvv)
Level 4 (-vvvv)
Level 5 (-vvvvv)
たとえば、このような使い方です
forge test -vvvvv
パッケージのインストールなど
サブモジュールでのインストール
forge install openzeppelin/openzeppelin-contracts
コミットしたくない場合は、--no-commit
をつける
forge install openzeppelin/openzeppelin-contracts --no-commit
パッケージのアップデート
forge update
forge update openzeppelin/openzeppelin-contracts
パッケージさよなら
forge remove lib/openzeppelin-contracts
forge remove openzeppelin/openzeppelin-contracts
バグった時はとりあえず
forge clean
コマンドまとめ
setUp
必ず毎回呼ばれる関数
試しに、console.log("setUp")と書いて動かせば、毎回setUpが呼ばれることがわかると思います
function名
通常:test<***>
失敗することをテストする場合:testFail<***>
よく使うコマンド一覧
アドレス関係
vm.address | vm.addr(uint256 privateKey); | address alice = vm.addr(1); | |
makeAddrAndKey | makeAddrAndKey(string ***); | (address alice, uint256 key) = makeAddrAndKey("alice"); | |
vm.deal | vm.deal(address who, uint256 newBalance); | vm.deal(alice, 1 ether); | |
deal | deal(address token, address to, uint256 give); | deal(address(dai), alice, 10000e18); |
msg.senderやtx.origin
vm.prank | vm.prank(address sender, address origin) | msg.senderとtx.originの設定 | vm.prank(owner,anotherContract); |
vm.startPrank | vm.startPrank(address sender, address origin) | stopPrankまでmsg.senderを変更する | vm.startPrank(alice) |
vm.stopPrank | vm.stopPrank() | vm.stopPrank() | |
hoax | hoax(address who, address origin, uint256 give) | addressとgiveは省略可能 | hoax(owner, 1 ether) |
startHoax | startHoax(address who, address origin, uint256 give) | startHoax(owner,anotherContract,1 ether); | |
changePrank | changePrank(address who) | vm.stopPrank + vm.startPrank | changePrank(alice) |
expect
vm.expectRevert | vm.expectRevert(bytes("error message")) | bytes("error message")は省略可能 | vm.expectRevert(bytes("You can't withdraw yet")) |
vm.expectEmit | vm.expectEmit( bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData ) | eventがemitされるかどうかをチェック テスト側にイベントを取り込む必要あり。checkTopicは、eventの引数にindexedがあるかないかに連動 | vm.expectEmit(false, false, false, true); |
timestamp
vm.warp | vm.warp(uint256) | 指定したblock.timestampに移動 | vm.warp(3600) |
skip | skip(uint256) | 指定した時間分だけ進める | skip(1000) |
rewind | rewind(uint256) | 指定した時間分だけ戻す | rewind(1000) |