-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathIWell.sol
411 lines (366 loc) · 17.4 KB
/
IWell.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IERC20} from "oz/token/ERC20/IERC20.sol";
/**
* @title Call is the struct that contains the target address and extra calldata of a generic call.
*/
struct Call {
address target; // The address the call is executed on.
bytes data; // Extra calldata to be passed during the call
}
/**
* @title IWell is the interface for the Well contract.
*
* In order for a Well to be verified using a permissionless on-chain registry, a Well Implementation should:
* - Not be able to self-destruct (Aquifer's registry would be vulnerable to a metamorphic contract attack)
* - Not be able to change its tokens, Well Function, Pumps and Well Data
*/
interface IWell {
/**
* @notice Emitted when a Swap occurs.
* @param fromToken The token swapped from
* @param toToken The token swapped to
* @param amountIn The amount of `fromToken` transferred into the Well
* @param amountOut The amount of `toToken` transferred out of the Well
* @param recipient The address that received `toToken`
*/
event Swap(IERC20 fromToken, IERC20 toToken, uint256 amountIn, uint256 amountOut, address recipient);
/**
* @notice Emitted when liquidity is added to the Well.
* @param tokenAmountsIn The amount of each token added to the Well
* @param lpAmountOut The amount of LP tokens minted
* @param recipient The address that received the LP tokens
*/
event AddLiquidity(uint256[] tokenAmountsIn, uint256 lpAmountOut, address recipient);
/**
* @notice Emitted when liquidity is removed from the Well as multiple underlying tokens.
* @param lpAmountIn The amount of LP tokens burned
* @param tokenAmountsOut The amount of each underlying token removed
* @param recipient The address that received the underlying tokens
* @dev Gas cost scales with `n` tokens.
*/
event RemoveLiquidity(uint256 lpAmountIn, uint256[] tokenAmountsOut, address recipient);
/**
* @notice Emitted when liquidity is removed from the Well as a single underlying token.
* @param lpAmountIn The amount of LP tokens burned
* @param tokenOut The underlying token removed
* @param tokenAmountOut The amount of `tokenOut` removed
* @param recipient The address that received the underlying tokens
* @dev Emitting a separate event when removing liquidity as a single token
* saves gas, since `tokenAmountsOut` in {RemoveLiquidity} must emit a value
* for each token in the Well.
*/
event RemoveLiquidityOneToken(uint256 lpAmountIn, IERC20 tokenOut, uint256 tokenAmountOut, address recipient);
/**
* @notice Emitted when a Shift occurs.
* @param reserves The ending reserves after a shift
* @param toToken The token swapped to
* @param amountOut The amount of `toToken` transferred out of the Well
* @param recipient The address that received `toToken`
*/
event Shift(uint256[] reserves, IERC20 toToken, uint256 amountOut, address recipient);
/**
* @notice Emitted when a Sync occurs.
* @param reserves The ending reserves after a sync
* @param lpAmountOut The amount of LP tokens received from the sync.
* @param recipient The address that received the LP tokens
*/
event Sync(uint256[] reserves, uint256 lpAmountOut, address recipient);
//////////////////// WELL DEFINITION ////////////////////
/**
* @notice Returns a list of ERC20 tokens supported by the Well.
*/
function tokens() external view returns (IERC20[] memory);
/**
* @notice Returns the Well function as a Call struct.
* @dev Contains the address of the Well function contract and extra data to
* pass during calls.
*
* **Well functions** define a relationship between the reserves of the
* tokens in the Well and the number of LP tokens.
*
* A Well function MUST implement {IWellFunction}.
*/
function wellFunction() external view returns (Call memory);
/**
* @notice Returns the Pumps attached to the Well as Call structs.
* @dev Contains the addresses of the Pumps contract and extra data to pass
* during calls.
*
* **Pumps** are on-chain oracles that are updated every time the Well is
* interacted with.
*
* A Pump is not required for Well operation. For Wells without a Pump:
* `pumps().length = 0`.
*
* An attached Pump MUST implement {IPump}.
*/
function pumps() external view returns (Call[] memory);
/**
* @notice Returns the Well data that the Well was bored with.
* @dev The existence and signature of Well data is determined by each individual implementation.
*/
function wellData() external view returns (bytes memory);
/**
* @notice Returns the Aquifer that created this Well.
* @dev Wells can be permissionlessly bored in an Aquifer.
*
* Aquifers stores the implementation that was used to bore the Well.
*/
function aquifer() external view returns (address);
/**
* @notice Returns the tokens, Well Function, Pumps and Well Data associated
* with the Well as well as the Aquifer that deployed the Well.
*/
function well()
external
view
returns (
IERC20[] memory _tokens,
Call memory _wellFunction,
Call[] memory _pumps,
bytes memory _wellData,
address _aquifer
);
//////////////////// SWAP: FROM ////////////////////
/**
* @notice Swaps from an exact amount of `fromToken` to a minimum amount of `toToken`.
* @param fromToken The token to swap from
* @param toToken The token to swap to
* @param amountIn The amount of `fromToken` to spend
* @param minAmountOut The minimum amount of `toToken` to receive
* @param recipient The address to receive `toToken`
* @param deadline The timestamp after which this operation is invalid
* @return amountOut The amount of `toToken` received
*/
function swapFrom(
IERC20 fromToken,
IERC20 toToken,
uint256 amountIn,
uint256 minAmountOut,
address recipient,
uint256 deadline
) external returns (uint256 amountOut);
/**
* @notice Swaps from an exact amount of `fromToken` to a minimum amount of `toToken` and supports fee on transfer tokens.
* @param fromToken The token to swap from
* @param toToken The token to swap to
* @param amountIn The amount of `fromToken` to spend
* @param minAmountOut The minimum amount of `toToken` to take from the Well. Note that if `toToken` charges a fee on transfer, `recipient` will receive less than this amount.
* @param recipient The address to receive `toToken`
* @param deadline The timestamp after which this operation is invalid
* @return amountOut The amount of `toToken` transferred from the Well. Note that if `toToken` charges a fee on transfer, `recipient` may receive less than this amount.
* @dev Can also be used for tokens without a fee on transfer, but is less gas efficient.
*/
function swapFromFeeOnTransfer(
IERC20 fromToken,
IERC20 toToken,
uint256 amountIn,
uint256 minAmountOut,
address recipient,
uint256 deadline
) external returns (uint256 amountOut);
/**
* @notice Gets the amount of one token received for swapping an amount of another token.
* @param fromToken The token to swap from
* @param toToken The token to swap to
* @param amountIn The amount of `fromToken` to spend
* @return amountOut The amount of `toToken` to receive
*/
function getSwapOut(IERC20 fromToken, IERC20 toToken, uint256 amountIn) external view returns (uint256 amountOut);
//////////////////// SWAP: TO ////////////////////
/**
* @notice Swaps from a maximum amount of `fromToken` to an exact amount of `toToken`.
* @param fromToken The token to swap from
* @param toToken The token to swap to
* @param maxAmountIn The maximum amount of `fromToken` to spend
* @param amountOut The amount of `toToken` to receive
* @param recipient The address to receive `toToken`
* @param deadline The timestamp after which this operation is invalid
* @return amountIn The amount of `toToken` received
*/
function swapTo(
IERC20 fromToken,
IERC20 toToken,
uint256 maxAmountIn,
uint256 amountOut,
address recipient,
uint256 deadline
) external returns (uint256 amountIn);
/**
* @notice Gets the amount of one token that must be spent to receive an amount of another token during a swap.
* @param fromToken The token to swap from
* @param toToken The token to swap to
* @param amountOut The amount of `toToken` desired
* @return amountIn The amount of `fromToken` that must be spent
*/
function getSwapIn(IERC20 fromToken, IERC20 toToken, uint256 amountOut) external view returns (uint256 amountIn);
//////////////////// SHIFT ////////////////////
/**
* @notice Shifts at least `minAmountOut` excess tokens held by the Well into `tokenOut` and delivers to `recipient`.
* @param tokenOut The token to shift into
* @param minAmountOut The minimum amount of `tokenOut` to receive
* @param recipient The address to receive the token
* @return amountOut The amount of `tokenOut` received
* @dev Can be used in a multicall using a contract like Pipeline to perform gas efficient swaps.
* No deadline is needed since this function does not use the user's assets. If adding liquidity in a multicall,
* then a deadline check can be added to the multicall.
*/
function shift(IERC20 tokenOut, uint256 minAmountOut, address recipient) external returns (uint256 amountOut);
/**
* @notice Calculates the amount of the token out received from shifting excess tokens held by the Well.
* @param tokenOut The token to shift into
* @return amountOut The amount of `tokenOut` received
*/
function getShiftOut(
IERC20 tokenOut
) external returns (uint256 amountOut);
//////////////////// ADD LIQUIDITY ////////////////////
/**
* @notice Adds liquidity to the Well as multiple tokens in any ratio.
* @param tokenAmountsIn The amount of each token to add; MUST match the indexing of {Well.tokens}
* @param minLpAmountOut The minimum amount of LP tokens to receive
* @param recipient The address to receive the LP tokens
* @param deadline The timestamp after which this operation is invalid
* @return lpAmountOut The amount of LP tokens received
*/
function addLiquidity(
uint256[] memory tokenAmountsIn,
uint256 minLpAmountOut,
address recipient,
uint256 deadline
) external returns (uint256 lpAmountOut);
/**
* @notice Adds liquidity to the Well as multiple tokens in any ratio and supports
* fee on transfer tokens.
* @param tokenAmountsIn The amount of each token to add; MUST match the indexing of {Well.tokens}
* @param minLpAmountOut The minimum amount of LP tokens to receive
* @param recipient The address to receive the LP tokens
* @param deadline The timestamp after which this operation is invalid
* @return lpAmountOut The amount of LP tokens received
* @dev Can also be used for tokens without a fee on transfer, but is less gas efficient.
*/
function addLiquidityFeeOnTransfer(
uint256[] memory tokenAmountsIn,
uint256 minLpAmountOut,
address recipient,
uint256 deadline
) external returns (uint256 lpAmountOut);
/**
* @notice Gets the amount of LP tokens received from adding liquidity as multiple tokens in any ratio.
* @param tokenAmountsIn The amount of each token to add; MUST match the indexing of {Well.tokens}
* @return lpAmountOut The amount of LP tokens received
*/
function getAddLiquidityOut(
uint256[] memory tokenAmountsIn
) external view returns (uint256 lpAmountOut);
//////////////////// REMOVE LIQUIDITY: BALANCED ////////////////////
/**
* @notice Removes liquidity from the Well as all underlying tokens in a balanced ratio.
* @param lpAmountIn The amount of LP tokens to burn
* @param minTokenAmountsOut The minimum amount of each underlying token to receive; MUST match the indexing of {Well.tokens}
* @param recipient The address to receive the underlying tokens
* @param deadline The timestamp after which this operation is invalid
* @return tokenAmountsOut The amount of each underlying token received
*/
function removeLiquidity(
uint256 lpAmountIn,
uint256[] calldata minTokenAmountsOut,
address recipient,
uint256 deadline
) external returns (uint256[] memory tokenAmountsOut);
/**
* @notice Gets the amount of each underlying token received from removing liquidity in a balanced ratio.
* @param lpAmountIn The amount of LP tokens to burn
* @return tokenAmountsOut The amount of each underlying token received
*/
function getRemoveLiquidityOut(
uint256 lpAmountIn
) external view returns (uint256[] memory tokenAmountsOut);
//////////////////// REMOVE LIQUIDITY: ONE TOKEN ////////////////////
/**
* @notice Removes liquidity from the Well as a single underlying token.
* @param lpAmountIn The amount of LP tokens to burn
* @param tokenOut The underlying token to receive
* @param minTokenAmountOut The minimum amount of `tokenOut` to receive
* @param recipient The address to receive the underlying tokens
* @param deadline The timestamp after which this operation is invalid
* @return tokenAmountOut The amount of `tokenOut` received
*/
function removeLiquidityOneToken(
uint256 lpAmountIn,
IERC20 tokenOut,
uint256 minTokenAmountOut,
address recipient,
uint256 deadline
) external returns (uint256 tokenAmountOut);
/**
* @notice Gets the amount received from removing liquidity from the Well as a single underlying token.
* @param lpAmountIn The amount of LP tokens to burn
* @param tokenOut The underlying token to receive
* @return tokenAmountOut The amount of `tokenOut` received
*
*/
function getRemoveLiquidityOneTokenOut(
uint256 lpAmountIn,
IERC20 tokenOut
) external view returns (uint256 tokenAmountOut);
//////////////////// REMOVE LIQUIDITY: IMBALANCED ////////////////////
/**
* @notice Removes liquidity from the Well as multiple underlying tokens in any ratio.
* @param maxLpAmountIn The maximum amount of LP tokens to burn
* @param tokenAmountsOut The amount of each underlying token to receive; MUST match the indexing of {Well.tokens}
* @param recipient The address to receive the underlying tokens
* @return lpAmountIn The amount of LP tokens burned
*/
function removeLiquidityImbalanced(
uint256 maxLpAmountIn,
uint256[] calldata tokenAmountsOut,
address recipient,
uint256 deadline
) external returns (uint256 lpAmountIn);
/**
* @notice Gets the amount of LP tokens to burn from removing liquidity as multiple underlying tokens in any ratio.
* @param tokenAmountsOut The amount of each underlying token to receive; MUST match the indexing of {Well.tokens}
* @return lpAmountIn The amount of LP tokens burned
*/
function getRemoveLiquidityImbalancedIn(
uint256[] calldata tokenAmountsOut
) external view returns (uint256 lpAmountIn);
//////////////////// RESERVES ////////////////////
/**
* @notice Syncs the Well's reserves with the Well's balances of underlying tokens. If the reserves
* increase, mints at least `minLpAmountOut` LP Tokens to `recipient`.
* @param recipient The address to receive the LP tokens
* @param minLpAmountOut The minimum amount of LP tokens to receive
* @return lpAmountOut The amount of LP tokens received
* @dev Can be used in a multicall using a contract like Pipeline to perform gas efficient additions of liquidity.
* No deadline is needed since this function does not use the user's assets. If adding liquidity in a multicall,
* then a deadline check can be added to the multicall.
* If `sync` decreases the Well's reserves, then no LP tokens are minted and `lpAmountOut` must be 0.
*/
function sync(address recipient, uint256 minLpAmountOut) external returns (uint256 lpAmountOut);
/**
* @notice Calculates the amount of LP Tokens received from syncing the Well's reserves with the Well's balances.
* @return lpAmountOut The amount of LP tokens received
*/
function getSyncOut() external view returns (uint256 lpAmountOut);
/**
* @notice Sends excess tokens held by the Well to the `recipient`.
* @param recipient The address to send the tokens
* @return skimAmounts The amount of each token skimmed
* @dev No deadline is needed since this function does not use the user's assets.
*/
function skim(
address recipient
) external returns (uint256[] memory skimAmounts);
/**
* @notice Gets the reserves of each token held by the Well.
*/
function getReserves() external view returns (uint256[] memory reserves);
/**
* @notice Returns whether or not the Well is initialized if it requires initialization.
* If a Well does not require initialization, it should always return `true`.
*/
function isInitialized() external view returns (bool);
}