@@ -26,18 +26,16 @@ import { ICurveAddressProvider } from "../interfaces/external/ICurveAddressProvi
26
26
import { ICurvePoolRegistry } from "../interfaces/external/ICurvePoolRegistry.sol " ;
27
27
import { ICurvePool } from "../interfaces/external/ICurvePool.sol " ;
28
28
import { ISwapRouter} from "../interfaces/external/ISwapRouter.sol " ;
29
+ import { IQuoter } from "../interfaces/IQuoter.sol " ;
29
30
import { IWETH } from "../interfaces/IWETH.sol " ;
30
31
import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol " ;
31
32
32
33
33
-
34
-
35
34
/**
36
35
* @title DEXAdapter
37
36
* @author Index Coop
38
37
*
39
38
* Adapter to execute swaps on different DEXes
40
- *
41
39
*/
42
40
library DEXAdapter {
43
41
using SafeERC20 for IERC20 ;
@@ -60,6 +58,7 @@ library DEXAdapter {
60
58
address quickRouter;
61
59
address sushiRouter;
62
60
address uniV3Router;
61
+ address uniV3Quoter;
63
62
address curveAddressProvider;
64
63
address curveCalculator;
65
64
// Wrapped native token (WMATIC on polygon)
@@ -73,7 +72,6 @@ library DEXAdapter {
73
72
Exchange exchange;
74
73
}
75
74
76
-
77
75
struct CurvePoolData {
78
76
int128 nCoins;
79
77
uint256 [8 ] balances;
@@ -83,11 +81,6 @@ library DEXAdapter {
83
81
uint256 [8 ] decimals;
84
82
}
85
83
86
- /* ============ State Variables ============ */
87
-
88
-
89
-
90
- /* ============ Internal Methods ============ */
91
84
/**
92
85
* Swap exact tokens for another token on a given DEX.
93
86
*
@@ -133,7 +126,7 @@ library DEXAdapter {
133
126
_swapData.path,
134
127
_amountIn,
135
128
_minAmountOut,
136
- IUniswapV2Router02 (( _swapData.exchange == Exchange.Quickswap) ? _addresses.quickRouter : _addresses.sushiRouter )
129
+ _getRouter ( _swapData.exchange, _addresses)
137
130
);
138
131
}
139
132
}
@@ -161,6 +154,7 @@ library DEXAdapter {
161
154
if (_swapData.path[0 ] == _swapData.path[_swapData.path.length - 1 ]) {
162
155
return _amountOut;
163
156
}
157
+
164
158
if (_swapData.exchange == Exchange.Curve){
165
159
return _swapTokensForExactTokensCurve (
166
160
_swapData.path,
@@ -183,7 +177,87 @@ library DEXAdapter {
183
177
_swapData.path,
184
178
_amountOut,
185
179
_maxAmountIn,
186
- IUniswapV2Router02 ((_swapData.exchange == Exchange.Quickswap) ? _addresses.quickRouter : _addresses.sushiRouter)
180
+ _getRouter (_swapData.exchange, _addresses)
181
+ );
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Gets the output amount of a token swap.
187
+ *
188
+ * @param _swapData the swap parameters
189
+ * @param _addresses Struct containing relevant smart contract addresses.
190
+ * @param _amountIn the input amount of the trade
191
+ *
192
+ * @return the output amount of the swap
193
+ */
194
+ function getAmountOut (
195
+ Addresses memory _addresses ,
196
+ SwapData memory _swapData ,
197
+ uint256 _amountIn
198
+ )
199
+ external
200
+ returns (uint256 )
201
+ {
202
+ if (_swapData.path.length == 0 || _swapData.path[0 ] == _swapData.path[_swapData.path.length -1 ]) {
203
+ return _amountIn;
204
+ }
205
+
206
+ if (_swapData.exchange == Exchange.UniV3) {
207
+ return _getAmountOutUniV3 (_swapData, _addresses.uniV3Quoter, _amountIn);
208
+ } else if (_swapData.exchange == Exchange.Curve) {
209
+ (int128 i , int128 j ) = _getCoinIndices (
210
+ _swapData.pool,
211
+ _swapData.path[0 ],
212
+ _swapData.path[1 ],
213
+ ICurveAddressProvider (_addresses.curveAddressProvider)
214
+ );
215
+ return _getAmountOutCurve (_swapData.pool, i, j, _amountIn, _addresses);
216
+ } else {
217
+ return _getAmountOutUniV2 (
218
+ _swapData,
219
+ _getRouter (_swapData.exchange, _addresses),
220
+ _amountIn
221
+ );
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Gets the input amount of a fixed output swap.
227
+ *
228
+ * @param _swapData the swap parameters
229
+ * @param _addresses Struct containing relevant smart contract addresses.
230
+ * @param _amountOut the output amount of the swap
231
+ *
232
+ * @return the input amount of the swap
233
+ */
234
+ function getAmountIn (
235
+ Addresses memory _addresses ,
236
+ SwapData memory _swapData ,
237
+ uint256 _amountOut
238
+ )
239
+ external
240
+ returns (uint256 )
241
+ {
242
+ if (_swapData.path.length == 0 || _swapData.path[0 ] == _swapData.path[_swapData.path.length -1 ]) {
243
+ return _amountOut;
244
+ }
245
+
246
+ if (_swapData.exchange == Exchange.UniV3) {
247
+ return _getAmountInUniV3 (_swapData, _addresses.uniV3Quoter, _amountOut);
248
+ } else if (_swapData.exchange == Exchange.Curve) {
249
+ (int128 i , int128 j ) = _getCoinIndices (
250
+ _swapData.pool,
251
+ _swapData.path[0 ],
252
+ _swapData.path[1 ],
253
+ ICurveAddressProvider (_addresses.curveAddressProvider)
254
+ );
255
+ return _getAmountInCurve (_swapData.pool, i, j, _amountOut, _addresses);
256
+ } else {
257
+ return _getAmountInUniV2 (
258
+ _swapData,
259
+ _getRouter (_swapData.exchange, _addresses),
260
+ _amountOut
187
261
);
188
262
}
189
263
}
@@ -237,8 +311,10 @@ library DEXAdapter {
237
311
/**
238
312
* Execute exact output swap via UniswapV3
239
313
*
240
- * @param _path List of token address to swap via. (In the order as expected by uniV2, the first element being the input toen)
241
- * @param _fees List of fee levels identifying the pools to swap via. (_fees[0] refers to pool between _path[0] and _path[1])
314
+ * @param _path List of token address to swap via. (In the order as
315
+ * expected by uniV2, the first element being the input toen)
316
+ * @param _fees List of fee levels identifying the pools to swap via.
317
+ * (_fees[0] refers to pool between _path[0] and _path[1])
242
318
* @param _amountOut The amount of output token required
243
319
* @param _maxAmountIn Maximum amount of input token to be spent
244
320
* @param _uniV3Router Address of the uniswapV3 router
@@ -338,7 +414,7 @@ library DEXAdapter {
338
414
uint256 _maxAmountIn ,
339
415
Addresses memory _addresses
340
416
)
341
- public
417
+ private
342
418
returns (uint256 )
343
419
{
344
420
require (_path.length == 2 , "ExchangeIssuance: CURVE_WRONG_PATH_LENGTH " );
@@ -364,7 +440,6 @@ library DEXAdapter {
364
440
IWETH (_addresses.weth).deposit { value: returnedAmountOut }();
365
441
}
366
442
367
-
368
443
return amountIn;
369
444
}
370
445
@@ -399,8 +474,6 @@ library DEXAdapter {
399
474
}
400
475
}
401
476
402
-
403
-
404
477
/**
405
478
* Calculate required input amount to get a given output amount via Curve swap
406
479
*
@@ -419,7 +492,7 @@ library DEXAdapter {
419
492
uint256 _amountOut ,
420
493
Addresses memory _addresses
421
494
)
422
- public
495
+ private
423
496
view
424
497
returns (uint256 )
425
498
{
@@ -439,6 +512,31 @@ library DEXAdapter {
439
512
) + ROUNDING_ERROR_MARGIN;
440
513
}
441
514
515
+ /**
516
+ * Calculate output amount of a Curve swap
517
+ *
518
+ * @param _i Index of input token as per the ordering of the pools tokens
519
+ * @param _j Index of output token as per the ordering of the pools tokens
520
+ * @param _pool Address of curve pool to use
521
+ * @param _amountIn The amount of output token to be received
522
+ * @param _addresses Struct containing relevant smart contract addresses.
523
+ *
524
+ * @return amountOut The amount of output token obtained
525
+ */
526
+ function _getAmountOutCurve (
527
+ address _pool ,
528
+ int128 _i ,
529
+ int128 _j ,
530
+ uint256 _amountIn ,
531
+ Addresses memory _addresses
532
+ )
533
+ private
534
+ view
535
+ returns (uint256 )
536
+ {
537
+ return ICurvePool (_pool).get_dy (_i, _j, _amountIn);
538
+ }
539
+
442
540
/**
443
541
* Get metadata on curve pool required to calculate input amount from output amount
444
542
*
@@ -482,7 +580,9 @@ library DEXAdapter {
482
580
address _to ,
483
581
ICurveAddressProvider _curveAddressProvider
484
582
)
485
- public view returns (int128 i , int128 j )
583
+ private
584
+ view
585
+ returns (int128 i , int128 j )
486
586
{
487
587
ICurvePoolRegistry registry = ICurvePoolRegistry (_curveAddressProvider.get_registry ());
488
588
@@ -510,13 +610,12 @@ library DEXAdapter {
510
610
return (i, j);
511
611
}
512
612
513
-
514
-
515
613
/**
516
614
* Execute exact input swap via UniswapV3
517
615
*
518
616
* @param _path List of token address to swap via.
519
- * @param _fees List of fee levels identifying the pools to swap via. (_fees[0] refers to pool between _path[0] and _path[1])
617
+ * @param _fees List of fee levels identifying the pools to swap via.
618
+ * (_fees[0] refers to pool between _path[0] and _path[1])
520
619
* @param _amountIn The amount of input token to be spent
521
620
* @param _minAmountOut Minimum amount of output token to receive
522
621
* @param _uniV3Router Address of the uniswapV3 router
@@ -586,13 +685,99 @@ library DEXAdapter {
586
685
return _router.swapExactTokensForTokens (_amountIn, _minAmountOut, _path, address (this ), block .timestamp )[1 ];
587
686
}
588
687
688
+ /**
689
+ * Gets the output amount of a token swap on Uniswap V2
690
+ *
691
+ * @param _swapData the swap parameters
692
+ * @param _router the uniswap v2 router address
693
+ * @param _amountIn the input amount of the trade
694
+ *
695
+ * @return the output amount of the swap
696
+ */
697
+ function _getAmountOutUniV2 (
698
+ SwapData memory _swapData ,
699
+ IUniswapV2Router02 _router ,
700
+ uint256 _amountIn
701
+ )
702
+ private
703
+ view
704
+ returns (uint256 )
705
+ {
706
+ return _router.getAmountsOut (_amountIn, _swapData.path)[_swapData.path.length -1 ];
707
+ }
708
+
709
+ /**
710
+ * Gets the input amount of a fixed output swap on Uniswap V2.
711
+ *
712
+ * @param _swapData the swap parameters
713
+ * @param _router the uniswap v2 router address
714
+ * @param _amountOut the output amount of the swap
715
+ *
716
+ * @return the input amount of the swap
717
+ */
718
+ function _getAmountInUniV2 (
719
+ SwapData memory _swapData ,
720
+ IUniswapV2Router02 _router ,
721
+ uint256 _amountOut
722
+ )
723
+ private
724
+ view
725
+ returns (uint256 )
726
+ {
727
+ return _router.getAmountsIn (_amountOut, _swapData.path)[0 ];
728
+ }
729
+
730
+ /**
731
+ * Gets the output amount of a token swap on Uniswap V3.
732
+ *
733
+ * @param _swapData the swap parameters
734
+ * @param _quoter the uniswap v3 quoter
735
+ * @param _amountIn the input amount of the trade
736
+ *
737
+ * @return the output amount of the swap
738
+ */
739
+
740
+ function _getAmountOutUniV3 (
741
+ SwapData memory _swapData ,
742
+ address _quoter ,
743
+ uint256 _amountIn
744
+ )
745
+ private
746
+ returns (uint256 )
747
+ {
748
+ bytes memory path = _encodePathV3 (_swapData.path, _swapData.fees, false );
749
+ return IQuoter (_quoter).quoteExactInput (path, _amountIn);
750
+ }
751
+
752
+ /**
753
+ * Gets the input amount of a fixed output swap on Uniswap V3.
754
+ *
755
+ * @param _swapData the swap parameters
756
+ * @param _quoter uniswap v3 quoter
757
+ * @param _amountOut the output amount of the swap
758
+ *
759
+ * @return the input amount of the swap
760
+ */
761
+ function _getAmountInUniV3 (
762
+ SwapData memory _swapData ,
763
+ address _quoter ,
764
+ uint256 _amountOut
765
+ )
766
+ private
767
+ returns (uint256 )
768
+ {
769
+ bytes memory path = _encodePathV3 (_swapData.path, _swapData.fees, true );
770
+ return IQuoter (_quoter).quoteExactOutput (path, _amountOut);
771
+ }
589
772
590
773
/**
591
774
* Encode path / fees to bytes in the format expected by UniV3 router
592
775
*
593
776
* @param _path List of token address to swap via (starting with input token)
594
- * @param _fees List of fee levels identifying the pools to swap via. (_fees[0] refers to pool between _path[0] and _path[1])
595
- * @param _reverseOrder Boolean indicating if path needs to be reversed to start with output token. (which is the case for exact output swap)
777
+ * @param _fees List of fee levels identifying the pools to swap via.
778
+ * (_fees[0] refers to pool between _path[0] and _path[1])
779
+ * @param _reverseOrder Boolean indicating if path needs to be reversed to start with output token.
780
+ * (which is the case for exact output swap)
596
781
*
597
782
* @return encodedPath Encoded path to be forwared to uniV3 router
598
783
*/
@@ -619,4 +804,16 @@ library DEXAdapter {
619
804
}
620
805
}
621
806
807
+ function _getRouter (
808
+ Exchange _exchange ,
809
+ Addresses memory _addresses
810
+ )
811
+ private
812
+ pure
813
+ returns (IUniswapV2Router02)
814
+ {
815
+ return IUniswapV2Router02 (
816
+ (_exchange == Exchange.Quickswap) ? _addresses.quickRouter : _addresses.sushiRouter
817
+ );
818
+ }
622
819
}
0 commit comments