-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLiquidityPool.sol
More file actions
167 lines (131 loc) · 4.78 KB
/
LiquidityPool.sol
File metadata and controls
167 lines (131 loc) · 4.78 KB
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "./TokenPool.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
contract LiquidityPool is Ownable, TokenPool {
IERC20 public token0;
IERC20 public token1;
uint private reserve0;
uint private reserve1;
bool public initialized;
modifier onlyTokenInPool(address _tokenIn) {
require(
_tokenIn == address(token0) || _tokenIn == address(token1),
"token is not supported!"
);
_;
}
constructor() {}
function initPool(address _token0, address _token1)
external
onlyOwner
{
require(!initialized, 'initialization not allowed!');
require(_token0 != address(0) && _token1 != address(0), "zero address not allowed!");
token0 = IERC20(_token0);
token1 = IERC20(_token1);
initialized = true;
}
function getLatestReserves()
public
view
returns (uint _reserve0, uint _reserve1)
{
_reserve0 = reserve0;
_reserve1 = reserve1;
}
function _updateReserves(uint _reserve0, uint _reserve1)
private
{
reserve0 = _reserve0;
reserve1 = _reserve1;
}
function swap(uint _amountOut, address _to, address _tokenIn)
external
{
require(_amountOut > 0, "amountOut should be greater than zero!");
(IERC20 tokenIn, IERC20 tokenOut, uint reserveIn, uint reserveOut) = getReserves(_tokenIn);
require(_amountOut < reserveOut, "not enough reserveOut!");
IERC20(tokenOut).transfer(_to, _amountOut);
uint balance0 = tokenIn.balanceOf(address(this));
uint balance1 = tokenOut.balanceOf(address(this));
( uint newReserve0, uint newReserve1 ) =
_tokenIn == address(token0) ? (balance0, balance1) : (balance1, balance0);
_updateReserves(newReserve0, newReserve1);
require(newReserve0 * newReserve1 >= reserveIn * reserveOut, "swap failed!");
}
function getReserves(address _tokenIn)
public
view
returns (IERC20 tokenIn, IERC20 tokenOut, uint reserveIn, uint reserveOut)
{
bool isToken0 = _tokenIn == address(token0);
(
tokenIn, tokenOut, reserveIn, reserveOut
) = isToken0
? (token0, token1, reserve0, reserve1)
: (token1, token0, reserve1, reserve0);
}
function getTokensOutAmount(address _tokenIn, uint _amountIn)
external
view
onlyTokenInPool(_tokenIn)
returns (uint amountOut)
{
(,, uint reserveIn, uint reserveOut) = getReserves(_tokenIn);
amountOut = (reserveOut * _amountIn)/(reserveIn + _amountIn);
}
function getTokenPairRatio(address _tokenIn, uint _amountIn)
external
view
onlyTokenInPool(_tokenIn)
returns (uint tokenOut)
{
(,, uint reserveIn, uint reserveOut) = getReserves(_tokenIn);
tokenOut = (reserveOut * _amountIn) / reserveIn;
}
function addLiquidity(address _to)
external
returns (uint shares)
{
(uint _reserve0, uint _reserve1) = getLatestReserves();
uint _balance0 = token0.balanceOf(address(this));
uint _balance1 = token1.balanceOf(address(this));
uint _amount0 = _balance0 - _reserve0;
uint _amount1 = _balance1 - _reserve1;
require(_amount0 != 0 && _amount1 != 0, "Liquidity amount should not be zero!");
if(totalSupply == 0) {
shares = Math.sqrt(_amount0 * _amount1);
}
else {
shares = Math.min(
(_amount0 * totalSupply) / _reserve0,
(_amount1 * totalSupply) / _reserve1
);
}
require(shares > 0, "shares equals 0");
_mint(_to, shares);
_updateReserves(
token0.balanceOf(address(this)),
token1.balanceOf(address(this))
);
(_reserve0, _reserve1) = getLatestReserves();
}
function removeLiquidity(address _to)
external
returns (uint amount0, uint amount1)
{
uint balance0 = token0.balanceOf(address(this));
uint balance1 = token1.balanceOf(address(this));
uint shares = balanceOf(address(this));
amount0 = (shares * balance0) / totalSupply;
amount1 = (shares * balance1) / totalSupply;
require(amount0 > 0 && amount1 > 0, "amount0 or amount1 = 0");
_burn(address(this), shares);
_updateReserves(balance0 - amount0, balance1 - amount1);
token0.transfer(_to, amount0);
token1.transfer(_to, amount1);
}
}