Skip to content

Commit 7de4d9a

Browse files
authored
feat: leverage token exchange issuance quote functions (#101)
* add issue quote function * add redemption quote function * add uniswap V3 support * add code comments * fix tests * fix comments * refactor * move tests to new interface * better tests * fix tests * fix integration tests * add curve support * remove console log * fix function visibility * cleanup * add integration test for curve quotes * fix integration tests
1 parent 04ce6ff commit 7de4d9a

File tree

10 files changed

+603
-53
lines changed

10 files changed

+603
-53
lines changed

contracts/exchangeIssuance/DEXAdapter.sol

Lines changed: 221 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,16 @@ import { ICurveAddressProvider } from "../interfaces/external/ICurveAddressProvi
2626
import { ICurvePoolRegistry } from "../interfaces/external/ICurvePoolRegistry.sol";
2727
import { ICurvePool } from "../interfaces/external/ICurvePool.sol";
2828
import { ISwapRouter} from "../interfaces/external/ISwapRouter.sol";
29+
import { IQuoter } from "../interfaces/IQuoter.sol";
2930
import { IWETH } from "../interfaces/IWETH.sol";
3031
import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol";
3132

3233

33-
34-
3534
/**
3635
* @title DEXAdapter
3736
* @author Index Coop
3837
*
3938
* Adapter to execute swaps on different DEXes
40-
*
4139
*/
4240
library DEXAdapter {
4341
using SafeERC20 for IERC20;
@@ -60,6 +58,7 @@ library DEXAdapter {
6058
address quickRouter;
6159
address sushiRouter;
6260
address uniV3Router;
61+
address uniV3Quoter;
6362
address curveAddressProvider;
6463
address curveCalculator;
6564
// Wrapped native token (WMATIC on polygon)
@@ -73,7 +72,6 @@ library DEXAdapter {
7372
Exchange exchange;
7473
}
7574

76-
7775
struct CurvePoolData {
7876
int128 nCoins;
7977
uint256[8] balances;
@@ -83,11 +81,6 @@ library DEXAdapter {
8381
uint256[8] decimals;
8482
}
8583

86-
/* ============ State Variables ============ */
87-
88-
89-
90-
/* ============ Internal Methods ============ */
9184
/**
9285
* Swap exact tokens for another token on a given DEX.
9386
*
@@ -133,7 +126,7 @@ library DEXAdapter {
133126
_swapData.path,
134127
_amountIn,
135128
_minAmountOut,
136-
IUniswapV2Router02((_swapData.exchange == Exchange.Quickswap) ? _addresses.quickRouter : _addresses.sushiRouter)
129+
_getRouter(_swapData.exchange, _addresses)
137130
);
138131
}
139132
}
@@ -161,6 +154,7 @@ library DEXAdapter {
161154
if (_swapData.path[0] == _swapData.path[_swapData.path.length -1]) {
162155
return _amountOut;
163156
}
157+
164158
if(_swapData.exchange == Exchange.Curve){
165159
return _swapTokensForExactTokensCurve(
166160
_swapData.path,
@@ -183,7 +177,87 @@ library DEXAdapter {
183177
_swapData.path,
184178
_amountOut,
185179
_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
187261
);
188262
}
189263
}
@@ -237,8 +311,10 @@ library DEXAdapter {
237311
/**
238312
* Execute exact output swap via UniswapV3
239313
*
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])
242318
* @param _amountOut The amount of output token required
243319
* @param _maxAmountIn Maximum amount of input token to be spent
244320
* @param _uniV3Router Address of the uniswapV3 router
@@ -338,7 +414,7 @@ library DEXAdapter {
338414
uint256 _maxAmountIn,
339415
Addresses memory _addresses
340416
)
341-
public
417+
private
342418
returns (uint256)
343419
{
344420
require(_path.length == 2, "ExchangeIssuance: CURVE_WRONG_PATH_LENGTH");
@@ -364,7 +440,6 @@ library DEXAdapter {
364440
IWETH(_addresses.weth).deposit{ value: returnedAmountOut }();
365441
}
366442

367-
368443
return amountIn;
369444
}
370445

@@ -399,8 +474,6 @@ library DEXAdapter {
399474
}
400475
}
401476

402-
403-
404477
/**
405478
* Calculate required input amount to get a given output amount via Curve swap
406479
*
@@ -419,7 +492,7 @@ library DEXAdapter {
419492
uint256 _amountOut,
420493
Addresses memory _addresses
421494
)
422-
public
495+
private
423496
view
424497
returns (uint256)
425498
{
@@ -439,6 +512,31 @@ library DEXAdapter {
439512
) + ROUNDING_ERROR_MARGIN;
440513
}
441514

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+
442540
/**
443541
* Get metadata on curve pool required to calculate input amount from output amount
444542
*
@@ -482,7 +580,9 @@ library DEXAdapter {
482580
address _to,
483581
ICurveAddressProvider _curveAddressProvider
484582
)
485-
public view returns (int128 i, int128 j)
583+
private
584+
view
585+
returns (int128 i, int128 j)
486586
{
487587
ICurvePoolRegistry registry = ICurvePoolRegistry(_curveAddressProvider.get_registry());
488588

@@ -510,13 +610,12 @@ library DEXAdapter {
510610
return (i, j);
511611
}
512612

513-
514-
515613
/**
516614
* Execute exact input swap via UniswapV3
517615
*
518616
* @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])
520619
* @param _amountIn The amount of input token to be spent
521620
* @param _minAmountOut Minimum amount of output token to receive
522621
* @param _uniV3Router Address of the uniswapV3 router
@@ -586,13 +685,99 @@ library DEXAdapter {
586685
return _router.swapExactTokensForTokens(_amountIn, _minAmountOut, _path, address(this), block.timestamp)[1];
587686
}
588687

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+
}
589772

590773
/**
591774
* Encode path / fees to bytes in the format expected by UniV3 router
592775
*
593776
* @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)
596781
*
597782
* @return encodedPath Encoded path to be forwared to uniV3 router
598783
*/
@@ -619,4 +804,16 @@ library DEXAdapter {
619804
}
620805
}
621806

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+
}
622819
}

0 commit comments

Comments
 (0)