-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathpuppet-v2.challenge.js
110 lines (90 loc) · 4.78 KB
/
puppet-v2.challenge.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
const pairJson = require("@uniswap/v2-core/build/UniswapV2Pair.json");
const factoryJson = require("@uniswap/v2-core/build/UniswapV2Factory.json");
const routerJson = require("@uniswap/v2-periphery/build/UniswapV2Router02.json");
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { setBalance } = require("@nomicfoundation/hardhat-network-helpers");
describe('[Challenge] Puppet v2', function () {
let deployer, player;
let token, weth, uniswapFactory, uniswapRouter, uniswapExchange, lendingPool;
// Uniswap v2 exchange will start with 100 tokens and 10 WETH in liquidity
const UNISWAP_INITIAL_TOKEN_RESERVE = 100n * 10n ** 18n;
const UNISWAP_INITIAL_WETH_RESERVE = 10n * 10n ** 18n;
// @audit-info 1DVT = ~0.1 ETH
// @audit-info After we dump DVT: 1DVT = ~0.001 ETH
const PLAYER_INITIAL_TOKEN_BALANCE = 10000n * 10n ** 18n;
const PLAYER_INITIAL_ETH_BALANCE = 20n * 10n ** 18n;
const POOL_INITIAL_TOKEN_BALANCE = 1000000n * 10n ** 18n;
before(async function () {
/** SETUP SCENARIO - NO NEED TO CHANGE ANYTHING HERE */
[deployer, player] = await ethers.getSigners();
await setBalance(player.address, PLAYER_INITIAL_ETH_BALANCE);
expect(await ethers.provider.getBalance(player.address)).to.eq(PLAYER_INITIAL_ETH_BALANCE);
const UniswapFactoryFactory = new ethers.ContractFactory(factoryJson.abi, factoryJson.bytecode, deployer);
const UniswapRouterFactory = new ethers.ContractFactory(routerJson.abi, routerJson.bytecode, deployer);
const UniswapPairFactory = new ethers.ContractFactory(pairJson.abi, pairJson.bytecode, deployer);
// Deploy tokens to be traded
token = await (await ethers.getContractFactory('DamnValuableToken', deployer)).deploy();
weth = await (await ethers.getContractFactory('WETH', deployer)).deploy();
// Deploy Uniswap Factory and Router
uniswapFactory = await UniswapFactoryFactory.deploy(ethers.constants.AddressZero);
uniswapRouter = await UniswapRouterFactory.deploy(
uniswapFactory.address,
weth.address
);
// Create Uniswap pair against WETH and add liquidity
await token.approve(
uniswapRouter.address,
UNISWAP_INITIAL_TOKEN_RESERVE
);
await uniswapRouter.addLiquidityETH(
token.address,
UNISWAP_INITIAL_TOKEN_RESERVE, // amountTokenDesired
0, // amountTokenMin
0, // amountETHMin
deployer.address, // to
(await ethers.provider.getBlock('latest')).timestamp * 2, // deadline
{ value: UNISWAP_INITIAL_WETH_RESERVE }
);
uniswapExchange = await UniswapPairFactory.attach(
await uniswapFactory.getPair(token.address, weth.address)
);
expect(await uniswapExchange.balanceOf(deployer.address)).to.be.gt(0);
// Deploy the lending pool
lendingPool = await (await ethers.getContractFactory('PuppetV2Pool', deployer)).deploy(
weth.address,
token.address,
uniswapExchange.address,
uniswapFactory.address
);
// Setup initial token balances of pool and player accounts
await token.transfer(player.address, PLAYER_INITIAL_TOKEN_BALANCE);
await token.transfer(lendingPool.address, POOL_INITIAL_TOKEN_BALANCE);
// Check pool's been correctly setup
expect(
await lendingPool.calculateDepositOfWETHRequired(10n ** 18n)
).to.eq(3n * 10n ** 17n);
expect(
await lendingPool.calculateDepositOfWETHRequired(POOL_INITIAL_TOKEN_BALANCE)
).to.eq(300000n * 10n ** 18n);
});
it('Execution', async function () {
/** CODE YOUR SOLUTION HERE */
const AttackerContractFactory = await ethers.getContractFactory("AttackPuppetV2", player);
this.attackerContract = await AttackerContractFactory.deploy(
lendingPool.address, uniswapRouter.address, token.address
)
await token.connect(player).transfer(this.attackerContract.address, PLAYER_INITIAL_TOKEN_BALANCE);
await this.attackerContract.attack({value: PLAYER_INITIAL_ETH_BALANCE - 4n * 10n ** 17n});
});
after(async function () {
/** SUCCESS CONDITIONS - NO NEED TO CHANGE ANYTHING HERE */
// Player has taken all tokens from the pool
expect(
await token.balanceOf(lendingPool.address)
).to.be.eq(0);
expect(
await token.balanceOf(player.address)
).to.be.gte(POOL_INITIAL_TOKEN_BALANCE);
});
});