GitHub リポジトリ:- https://github.com/PradhumnaPancholi/Figbot
こんにちは、みなさん!少し前に、スマート コントラクトを開発および監査するための素晴らしいツールがあるDapp Toolsについて学習していました。そして、私はその経験をとても気に入っていましたが、それが秘密の開発段階にあることをすぐに知りました.これは、カジュアル/個人ユーザーが、サポートと更新についてメンテナーに依存できないことを意味します。
それから私はファウンドリーに出くわしました。組み込みのシンボリック実行以外に、Dapp Tools が提供するすべての機能を備えています (Trail of Bits でManticor e を使用しているため、これは問題ではありません)。これは監査に関連しているため、想像力を働かせてもスマート コントラクトの開発を妨げるものではありません。
Foundry で少し働いた後、私はその経験を楽しんで、それを他の人と共有したいと思いました.ということで、この記事。
この記事では、Foundry の利点、インストール プロセス、NFT の開発 (誰もが興味を持っているため)、コントラクトのテスト、 Figment Datahubでの展開について説明します。
Foundry は、Rust で記述された Ethereum アプリケーション開発用の超高速でポータブルなモジュラー ツールキットです。
Foundry は、次の 3 つのコンポーネントで構成されています。
- Forge: Ethereum テスト フレームワーク (Truffle、Hardhat、Dapptools など)。
- キャスト: EVM スマート コントラクトとやり取りし、トランザクションを送信し、チェーン データを取得するためのスイス アーミー ナイフ。
- Anvil:ローカル イーサリアム ノード、Ganache、Hardhat Network に類似
今日の焦点はフォージです。しかし、今後数週間でカーストとアンビルに関する詳細な記事を投稿する予定です.
ファウンドリーを選ぶ理由:
Truffle、Hardhat、Brownie など、多くのスマート コントラクト開発ツールがあります。しかし、そもそも Dapp Tools を調べた主な理由の 1 つは、ネイティブの Solidity テストでした。 Hardhat や Brownie などのフレームワークを切り替える場合、スマート コントラクトを作成することは難しくありません。これらはプラグインを備えた素晴らしいツールですが、テストを実行するには JavaScript/TypeScript と Python に精通している必要があります。
Foundry を使用すると、Solidity でネイティブにテストを作成できます。これにより、新しい開発者のオンボーディングにかかる時間が大幅に節約され、プロセスがスムーズになります。人々がスマート コントラクト開発への道を進むのを支援してきた私の経験から、若手開発者が DAO/コミュニティで維持されているプロジェクトに関与するための最善かつ最も効率的な方法は、テストを作成し、コード ベース自体について学ぶことであることがわかりました。 Scupy Trooplesが、Bankless でAlchemix Finance を開発する際に同じアプローチを使用したと述べたことがあることを覚えています。
それに加えて、組み込みのファジング、チート コード、Cast、および Anvil により、スマート コントラクトをテストするための堅実なスイートになります。これらのコンポーネントについては、近日中に詳細な記事を掲載する予定です。 【静的アナライザーの組み込みが簡単】
それでは、NFT プロジェクトを作成してみましょう。
インストール:
Mac または Linux を使用している場合は、次の 2 つのコマンドを実行するだけです。
curl -L https://foundry.paradigm.xyz | bash
foundryup
foundryup
を実行する前に、必ずターミナルを閉じてください。
そして出来上がり!これで完了です。
Windows の場合、Rust をインストールしてから:
cargo install --git https://github.com/foundry-rs/foundry --locked
プロジェクトのセットアップ:
この記事では、Figbots という単純な NFT プロジェクトを作成します。
まず、「Figbots」というディレクトリを作成します。ディレクトリに入ったらforge init
を実行します。このコマンドは、 git
が初期化されたファウンドリ プロジェクトを作成します。
フォルダ構造を簡単に見てみましょう。 src、lib、および test という 3 つのプライマリ フォルダーがあります。コントラクトはsrc
に記述し、テストはtest
に記述します。lib には、インストールしたすべてのライブラリ ( lib
など) が含まれます。それに加えて、これらのフレームワークを使用した場合は、 hardhat.config.js
やbrownie-config.yaml
と同じように、すべての構成を含むfoundry.toml
を取得します。もう 1 つの便利な機能は、Github アクションを記述できる .github です。チームで作業するときのテストに非常に役立ちます。
構築を始めましょう! Figbot と呼ばれる、供給、コスト (鋳造用)、および引き出しが制限された単純な NFT を作成します。このアプローチにより、さまざまなテストのエッジをカバーできます。まず、 Contract.sol
とtest/Contract.t.sol
の名前をそれぞれFigbot.sol
とFigbot.t.sol
に変更します。さて、Openzeppelin なしではスマート コントラクトを作成できませんね。
Foundry でのライブラリのインストールは、Hardhat や Brownie とは少し異なります。 npm または pip パッケージはありません。 Foundry のソース (GitHub リポジトリ) からライブラリを直接インストールします。
forge install Openzeppelin/openzeppelin-contracts
これで、ERC721URIStorage.sol 拡張機能をインポートして NFT を作成できます。すべてが問題ないことを確認するために、コマンドforge build
を実行すると、プロジェクトがコンパイルされます。何か問題がある場合、コンパイラはあなたに怒鳴ります。それ以外の場合、コンパイルは成功します。
依存関係の管理
他のパッケージ マネージャーと同様に、Forge ではforge install <lib>,
forge remove <lib>
、およびforge update <lib>
を使用して依存関係を管理できます。
NFT契約を完了しましょう:
Openzeppelin からの 3 つの契約を使用します。カウンター、ERC721URIStorage、Ownable。 Pinataを使用してアセットを IPFS にアップロードします。 Ownable コントラクトを使用して展開アドレスowner
を設定し、 onlyOwner
修飾子にアクセスして、所有者のみが資金を引き出すことができるようにします。 NFT コントラクトをシンプルに保つためのトークン ID とERC721URIStorage
をサポートするCounters
。
状態変数の設定:
-
MAX_SUPPLY
を 100 に COST
から 0.69 イーサTOKEN_URI
から CID へ、ピニャータから受け取ります
-
トークン ID にカウンターを使用する:
-
using Counters for Counters.Counter;
-
Counters.Counter private tokenIds;
-
ERC721 コンストラクター:
-
constructor() ERC721(“Figbot”, “FBT”) {}
-
ミント機能:
-
msg.value
がCOST
より大きいかどうかを確認します tokenIds.current()
がMAX_SUPPLY
以上かどうかを確認します_safeMint
と_setTokenURI
を実行する
-
引き出し機能:
-
function withdrawFunds() external onlyOwner { uint256 balance = address(this).balance; require(balance > 0, "No ether left to withdraw"); (bool success, ) = (msg.sender).call{value: balance}(""); require(success, "Withdrawal Failed"); emit Withdraw(msg.sender, balance); }
-
TotalSupply 関数:
-
function totalSupply() public view returns (uint256) { return _tokenIds.current(); }
-
契約のテスト:
ご存知のように、スマート コントラクトをテストすることは非常に重要です。このセクションでは、 forge test
をしっかりと理解し、ネイティブの堅牢性でテストを書くことに慣れるために、いくつかのテストを書いていきます。テスト シナリオに合わせてアカウントの状態を管理するために、3 つのFoundry チート コードを使用します (大好きです!)。
次のシナリオでテストを行います。
- 最大供給量
- 成功したミント
- 残高不足によるミント失敗
- 撤回(所有者による)
チートコード
スマート コントラクトに複雑なロジックを含めることができるためです。そして、それらは状態、呼び出しに使用されたアカウント、時間などに応じて異なる動作をすることが期待されています。そのようなシナリオに対処するために、チートコードを使用してブロックチェーンの状態を管理できます。 Foundry のTest
ライブラリの一部であるvm
インスタンスを使用して、これらのチートコードを使用できます。
テストでは 3 つのチートコードを使用します。
startPrank
:stopPrank
が呼び出されるまで、後続のすべての呼び出しに対してmsg.sender
を設定します。stopPrank
:startPrank
によって開始されたアクティブないたずらを停止し、msg.sender
とtx.origin
をstartPrank
が呼び出される前の値にリセットします。deal
: アドレス提供アドレスの残高を、指定された残高に設定します。
設定
Foundry には組み込みのテスト ライブラリが付属しています。まず、このテスト ライブラリ、コントラクト (テストしたいもの) をインポートし、テストを定義し、変数を設定し、 setUp
関数を設定します。
pragma solidity ^0.8.13; import"forge-std/Test.sol"; import "../src/Figbot.sol"; contract FigbotTest is Test { Figbot figbot; address owner = address(0x1223); address alice = address(0x1889); address bob = address(0x1778); function setUp() public { vm.startPrank(owner); figbot = new Figbot(); vm.stopPrank(); } }
状態変数については、タイプFigbot
の変数figbot
を作成します。これは、私がユーザー アカウントを定義するのが好きな場所でもあります。 Foundry では、構文address(0x1243)
を使用してアドレスを記述できます。これには任意の 4 文字の英数字を使用できます。 owner、Alice、bob という名前のアカウントをそれぞれ作成しました。
次にsetUp
関数です。これは、Foundry でテストを作成するための要件です。これは、すべての展開とその性質のことを行う場所です。 startPrank
を使用して、ユーザーを「所有者」に切り替えました。デフォルトでは、Foundry は特定のアドレスを使用してテスト コントラクトをデプロイします。しかし、これにより、 withdrawFunds
のような特別な権限を持つ関数をテストすることが難しくなります。したがって、この展開の「所有者」アカウントに切り替えます。
MaxSupply をテストします。
Foundry の規則を学ぶための簡単なアサーション テストから始めます。慣例により、すべてのテスト関数には接頭辞test
が必要です。 assertEq
を使用して、2 つの値が等しいかどうかをテストします。
コントラクトで説明したように、 MaxSupply
関数を呼び出して、結果の値が 100 かどうかをテストします。そして、テストを実行するためにforge test
を使用します。
そして出来上がり!!!テストに合格しました。
テストミント:
簡単なテストを書いたので、チートコードを使って書いてみましょう。私たちの契約の主な機能。
- ユーザー アカウントを Alice に切り替えます。
- Alice の残高を 1 イーサに設定します
- ミント関数を呼び出す
balanceOf
Alice が 1 かどうかを確認する
TestFail ミント:
失敗すると予想されるテストに使用される別のテスト関数があります。このようなテストに使用されるプレフィックスはtestFail
です。呼び出し元の資金が不十分な場合にmint
関数が元に戻るかどうかをテストします。
- ユーザー アカウントを Bob に切り替えます
- ボブの残高を 0.5 イーサに設定します (NFT は 0.69 イーサです)
- mint 関数を呼び出します (十分な資金がないため、元に戻されます)
-
balanceOf
Bob が 1 かどうかを確認する
mint が通過しなかったため、Bob の残高は 1 になりません。したがって、それは失敗します。これは、まさにtestFail
を使用する目的です。したがって、 forge test
を実行すると、パスします。
テスト撤回:
ここでは、「所有者」だけが正常に実行できる機能をテストします。このテストでは、次のことを行います。
- ユーザーをボブに切り替える
- ボブの口座に 1 イーサの残高を与える
- Bob のアカウントから Figbot を作成します (これにより、コントラクトに 0.69 イーサの残高が与えられます)
- ユーザーを所有者アカウントに切り替えます
withdrawFunds
機能を実行します(成功した場合、所有者の残高は0.69イーサになります)- 確認するために、所有者の残高が 0.69 イーサであるかどうかをアサートします
展開:
コントラクトをテストしたので、それをデプロイします。ウォレットへの秘密鍵 (いくつかの Rinkeby テスト ETH を含む) と RPC URL が必要です。 RPC URL にはFigment DataHuを使用します。
Figment DataHub は、Web 3 で開発するためのインフラストラクチャを提供してくれます。Ethereum、Celo、Solana、Terra などの複数のチェーンをサポートしています。
Figment DataHub のセットアップ:
- Figment DataHubでアカウントを作成します。
- 「新しいアプリを作成」をクリックします。
- アプリ名を入力します。
- 環境は「ステージング」を選択。
- 提供されたオプションから「イーサリアム」を選択します。
「プロトコル」タブから、Rinkeby の RPC URL を取得できます。
ターミナルを開いて、これらの両方を環境変数として入力します。
export FIG_RINKEBY_URL=<Your RPC endpoint> export PVT_KEY=<Your wallets private key>
環境変数を取得したら、すべてデプロイする準備が整いました
forge create Figbot --rpc-url=$FIG_RINKEBY_URL --private-key=$PVT_KEY
検証:
これでほぼ完了です。これまでのところ、Foundry と Figment DataHub を使用してスマート コントラクトを作成、テスト、デプロイしました。しかし、まだ完全に終わったわけではありません。現在、契約内容を確認中です。そのためには、 Etherscan API キーを設定する必要があります。
export ETHERSCAN_API=<Your Etherscan API Key>
これで、スマート コントラクトを検証できます。
forge verify-contract --chain-id <Chain-Id> --num-of-optimizations 200 --compiler-version <Compiler Version> src/<Contract File>:<Contract> $ETHERSCAN_API
おめでとう!これで、Foundry を使用してスマート コントラクトを作成、テスト、デプロイできるようになりました。この記事を楽しんで学んでいただければ幸いです。これを書くのは本当に楽しかったです。それについてのあなたの考えを私に知らせてください。