-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathPuppetV2Pool.sol
101 lines (84 loc) · 2.87 KB
/
PuppetV2Pool.sol
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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
import {UniswapV2Library} from "./UniswapV2Library.sol";
interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
function balanceOf(address account) external returns (uint256);
}
/**
* @title PuppetV2Pool
* @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz)
*/
contract PuppetV2Pool {
address private _uniswapPair;
address private _uniswapFactory;
IERC20 private _token;
IERC20 private _weth;
mapping(address => uint256) public deposits;
event Borrowed(
address indexed borrower,
uint256 depositRequired,
uint256 borrowAmount,
uint256 timestamp
);
error NotEnoughTokenBalance();
error TransferFailed();
constructor(
address wethAddress,
address tokenAddress,
address uniswapPairAddress,
address uniswapFactoryAddress
) {
_weth = IERC20(wethAddress);
_token = IERC20(tokenAddress);
_uniswapPair = uniswapPairAddress;
_uniswapFactory = uniswapFactoryAddress;
}
/**
* @notice Allows borrowing `borrowAmount` of tokens by first depositing three times their value in WETH
* Sender must have approved enough WETH in advance.
* Calculations assume that WETH and borrowed token have same amount of decimals.
*/
function borrow(uint256 borrowAmount) external {
if (_token.balanceOf(address(this)) < borrowAmount)
revert NotEnoughTokenBalance();
// Calculate how much WETH the user must deposit
uint256 depositOfWETHRequired = calculateDepositOfWETHRequired(
borrowAmount
);
// Take the WETH
_weth.transferFrom(msg.sender, address(this), depositOfWETHRequired);
// internal accounting
deposits[msg.sender] += depositOfWETHRequired;
if (!_token.transfer(msg.sender, borrowAmount)) revert TransferFailed();
emit Borrowed(
msg.sender,
depositOfWETHRequired,
borrowAmount,
block.timestamp
);
}
function calculateDepositOfWETHRequired(uint256 tokenAmount)
public
view
returns (uint256)
{
return (_getOracleQuote(tokenAmount) * 3) / 10**18;
}
// Fetch the price from Uniswap v2 using the official libraries
function _getOracleQuote(uint256 amount) private view returns (uint256) {
(uint256 reservesWETH, uint256 reservesToken) = UniswapV2Library
.getReserves(_uniswapFactory, address(_weth), address(_token));
return
UniswapV2Library.quote(
amount * (10**18),
reservesToken,
reservesWETH
);
}
}