-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPoolAdapter.sol
157 lines (142 loc) · 5.49 KB
/
PoolAdapter.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
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
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./ICryptoPool.sol";
import "./ICryptoPool.sol";
/**
* @dev Specified for a three-level pool with two zaps
* Like Polygon WMATIC/TRICRYPTO (0x7bbc0e92505b485aeb3e82e828cb505daf1e50c6).
*
* Should be deployed for each pool (cause lp and zap differs).
* coins array starts with the wrapped native token, and then ERC20 tokens follow in order, as in the constructor of zap
*/
contract PoolAdapterCrypto {
address public immutable lp;
address public immutable zap;
address[6] public coins;
/**
* @param lp_ LP pool address;
* @param zap_ zap for pool address;
* @param coins_ order of token addresses in the zap;
*/
constructor(address lp_, address zap_, address[6] memory coins_) {
require(lp_ != address(0), "PoolAdapterCrypto: zero address");
require(zap_ != address(0), "PoolAdapterCrypto: zero address");
for (uint256 i; i < 6; i++) {
require(coins_[i] != address(0), "PoolAdapterCrypto: zero address");
}
lp = lp_;
zap = zap_;
coins = coins_;
}
/**
* @dev Adds liquidity to the pool.
*
* @param tokenIn The address of the input token to add liquidity;
* @param amountIn The amount of input token to add as liquidity;
* @param to Address where the LP tokens will be transferred;
* @param pool Address of the pool contract;
* @param minAmountOut The minimum amount of pool tokens expected to be received;
* @param i Index of the input token;
* @param emergencyTo Emergency to address in case of inconsistency.
*/
function addLiquidity(
address tokenIn,
uint256 amountIn,
address to,
address pool,
uint256 minAmountOut,
uint8 i,
address emergencyTo
) external returns (uint256 amountOut) {
IZap zapImpl = IZap(zap);
IERC20 erc20Impl = IERC20(tokenIn);
require(tokenIn == coins[i], "PoolAdapterCrypto: wrong params");
uint256[6] memory amounts;
amounts[i] = amountIn;
if (minAmountOut > zapImpl.calc_token_amount(pool, amounts)) {
SafeERC20.safeTransfer(erc20Impl, emergencyTo, amountIn);
return 0;
}
SafeERC20.safeIncreaseAllowance(erc20Impl, zap, amountIn);
zapImpl.add_liquidity(pool, amounts, 0);
amountOut = IERC20(lp).balanceOf(address(this));
require(amountOut >= minAmountOut, "PoolAdapter: min amount");
if (to != address(this)) {
SafeERC20.safeTransfer(IERC20(lp), to, amountOut);
}
}
/**
* @dev Swaps tokens in the pool.
*
* @param tokenIn Address of the token to swap;
* @param amountIn The amount of input token to be exchanged;
* @param to Address where the output tokens will be transferred;
* @param pool Address of the pool contract;
* @param minAmountOut Minimum amount of coin to receive;
* @param i Index of the input token;
* @param j Index of the output token;
* @param emergencyTo Emergency to address in case of inconsistency.
*/
function swap(
address tokenIn,
uint256 amountIn,
address to,
address pool,
uint256 minAmountOut,
uint8 i,
uint8 j,
address emergencyTo
) external returns (uint256 amountOut) {
IZap zapImpl = IZap(zap);
IERC20 erc20Impl = IERC20(tokenIn);
require(tokenIn == coins[i], "PoolAdapterCrypto: wrong params");
uint256 minDy = zapImpl.get_dy(pool, uint256(i), uint256(j), amountIn);
if (minAmountOut > minDy) {
SafeERC20.safeTransfer(erc20Impl, emergencyTo, amountIn);
return 0;
}
SafeERC20.safeIncreaseAllowance(erc20Impl, zap, amountIn);
amountOut = zapImpl.exchange(pool, uint256(i), uint256(j), amountIn, 0);
address tokenOut = coins[j];
if (to != address(this)) {
SafeERC20.safeTransfer(IERC20(tokenOut), to, amountOut);
}
}
/**
* @dev Removes liquidity from the pool.
*
* @param tokenIn Address of the lp;
* @param amountIn The amount of the lp to be removed;
* @param to Address where the output token will be transferred;
* @param pool Address of the pool contract;
* @param minAmountOut Minimum amount of coin to receive;
* @param j Index value of the coin to withdraw;
* @param emergencyTo Emergency to address in case of inconsistency.
*/
function removeLiquidity(
address tokenIn,
uint256 amountIn,
address to,
address pool,
uint256 minAmountOut,
uint8 j,
address emergencyTo
) external returns (uint256 amountOut) {
IZap zapImpl = IZap(zap);
IERC20 erc20Impl = IERC20(tokenIn);
require(tokenIn == lp, "PoolAdapterCrypto: wrong params");
uint256 minAmount = zapImpl.calc_withdraw_one_coin(pool, amountIn, uint256(j));
if (minAmountOut > minAmount) {
SafeERC20.safeTransfer(erc20Impl, emergencyTo, amountIn);
return 0;
}
SafeERC20.safeIncreaseAllowance(erc20Impl, zap, amountIn);
amountOut = zapImpl.remove_liquidity_one_coin(pool, amountIn, j, 0);
address tokenOut = coins[j];
if (to != address(this)) {
SafeERC20.safeTransfer(IERC20(tokenOut), to, amountOut);
}
}
}