refactor: move swap params from interface to executor, add needsApproval
This commit is contained in:
committed by
Diana Carvalho
parent
3054ca042b
commit
826eca4a80
@@ -7,31 +7,6 @@ pragma solidity ^0.8.26;
|
|||||||
* @dev This interface allows for executing swaps through Curve's router, which can handle different pool types
|
* @dev This interface allows for executing swaps through Curve's router, which can handle different pool types
|
||||||
*/
|
*/
|
||||||
interface ICurveRouter {
|
interface ICurveRouter {
|
||||||
|
|
||||||
/**
|
|
||||||
* @notice Parameters for executing a swap through the Curve router
|
|
||||||
* @dev This struct encapsulates all necessary parameters for a Curve swap
|
|
||||||
* @param route Array of addresses representing the swap path (tokens and pools)
|
|
||||||
* @param swapParams 2D array containing swap parameters for each hop:
|
|
||||||
* [0]: tokenIn index in the pool
|
|
||||||
* [1]: tokenOut index in the pool
|
|
||||||
* [2]: swap type (1 for regular swap)
|
|
||||||
* [3]: pool type (1-4 depending on the Curve pool implementation)
|
|
||||||
* [4]: number of coins in the pool
|
|
||||||
* @param amountIn Amount of input token to swap
|
|
||||||
* @param minAmountOut Minimum amount of output token to receive
|
|
||||||
* @param pools Array of pool addresses involved in the swap
|
|
||||||
* @param receiver Address to receive the output tokens
|
|
||||||
*/
|
|
||||||
struct CurveRouterParams {
|
|
||||||
address[11] route;
|
|
||||||
uint256[5][5] swapParams;
|
|
||||||
uint256 amountIn;
|
|
||||||
uint256 minAmountOut;
|
|
||||||
address[5] pools;
|
|
||||||
address receiver;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice Executes a token swap through Curve pools
|
* @notice Executes a token swap through Curve pools
|
||||||
* @dev This function handles the routing of tokens through one or more Curve pools
|
* @dev This function handles the routing of tokens through one or more Curve pools
|
||||||
|
|||||||
@@ -11,14 +11,24 @@ contract CurveExecutor is IExecutor {
|
|||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
ICurveRouter public immutable curveRouter;
|
ICurveRouter public immutable curveRouter;
|
||||||
address public immutable nativeTokens;
|
address public immutable nativeToken;
|
||||||
|
|
||||||
constructor(address _curveRouter, address _nativeTokens) {
|
struct SwapParams {
|
||||||
if (_curveRouter == address(0) || _nativeTokens == address(0)) {
|
address[11] route;
|
||||||
|
uint256[5][5] swapParams;
|
||||||
|
uint256 amountIn;
|
||||||
|
uint256 minAmountOut;
|
||||||
|
address[5] pools;
|
||||||
|
address receiver;
|
||||||
|
bool needsApproval;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(address _curveRouter, address _nativeToken) {
|
||||||
|
if (_curveRouter == address(0) || _nativeToken == address(0)) {
|
||||||
revert CurveExecutor__InvalidAddresses();
|
revert CurveExecutor__InvalidAddresses();
|
||||||
}
|
}
|
||||||
curveRouter = ICurveRouter(_curveRouter);
|
curveRouter = ICurveRouter(_curveRouter);
|
||||||
nativeTokens = _nativeTokens;
|
nativeToken = _nativeToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
// slither-disable-next-line locked-ether
|
// slither-disable-next-line locked-ether
|
||||||
@@ -27,36 +37,30 @@ contract CurveExecutor is IExecutor {
|
|||||||
payable
|
payable
|
||||||
returns (uint256)
|
returns (uint256)
|
||||||
{
|
{
|
||||||
ICurveRouter.CurveRouterParams memory params = _decodeData(data);
|
SwapParams memory params = _decodeData(data);
|
||||||
if (params.route[0] != nativeTokens) {
|
|
||||||
// slither-disable-next-line unused-return
|
|
||||||
IERC20(params.route[0]).approve(address(curveRouter), amountIn);
|
|
||||||
|
|
||||||
return curveRouter.exchange(
|
if (params.needsApproval) {
|
||||||
params.route,
|
// slither-disable-next-line unused-return
|
||||||
params.swapParams,
|
IERC20(params.route[0]).approve(
|
||||||
amountIn,
|
address(curveRouter), type(uint256).max
|
||||||
params.minAmountOut,
|
|
||||||
params.pools,
|
|
||||||
params.receiver
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return curveRouter.exchange{value: amountIn}(
|
|
||||||
params.route,
|
|
||||||
params.swapParams,
|
|
||||||
amountIn,
|
|
||||||
params.minAmountOut,
|
|
||||||
params.pools,
|
|
||||||
params.receiver
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Only add the value parameter when the first token is the native token
|
||||||
|
return curveRouter.exchange{value: params.route[0] == nativeToken ? amountIn : 0}(
|
||||||
|
params.route,
|
||||||
|
params.swapParams,
|
||||||
|
amountIn,
|
||||||
|
params.minAmountOut,
|
||||||
|
params.pools,
|
||||||
|
params.receiver
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _decodeData(bytes calldata data)
|
function _decodeData(bytes calldata data)
|
||||||
internal
|
internal
|
||||||
pure
|
pure
|
||||||
returns (ICurveRouter.CurveRouterParams memory params)
|
returns (SwapParams memory params)
|
||||||
{
|
{
|
||||||
return abi.decode(data, (ICurveRouter.CurveRouterParams));
|
return abi.decode(data, (SwapParams));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ contract CurveExecutorExposed is CurveExecutor {
|
|||||||
function decodeParams(bytes calldata data)
|
function decodeParams(bytes calldata data)
|
||||||
external
|
external
|
||||||
pure
|
pure
|
||||||
returns (ICurveRouter.CurveRouterParams memory params)
|
returns (SwapParams memory params)
|
||||||
{
|
{
|
||||||
return _decodeData(data);
|
return _decodeData(data);
|
||||||
}
|
}
|
||||||
@@ -79,10 +79,10 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
address[5] memory pools;
|
address[5] memory pools;
|
||||||
|
|
||||||
bytes memory data = abi.encode(
|
bytes memory data = abi.encode(
|
||||||
route, swapParams, amountIn, minAmountOut, pools, address(this)
|
route, swapParams, amountIn, minAmountOut, pools, address(this), true
|
||||||
);
|
);
|
||||||
|
|
||||||
ICurveRouter.CurveRouterParams memory params =
|
CurveExecutor.SwapParams memory params =
|
||||||
curveExecutorExposed.decodeParams(data);
|
curveExecutorExposed.decodeParams(data);
|
||||||
|
|
||||||
assertEq(params.route[0], WETH_ADDR);
|
assertEq(params.route[0], WETH_ADDR);
|
||||||
@@ -92,6 +92,11 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
assertEq(params.swapParams[0][1], 0);
|
assertEq(params.swapParams[0][1], 0);
|
||||||
assertEq(params.swapParams[0][2], 1);
|
assertEq(params.swapParams[0][2], 1);
|
||||||
assertEq(params.swapParams[0][3], 3);
|
assertEq(params.swapParams[0][3], 3);
|
||||||
|
assertEq(params.swapParams[0][4], 3);
|
||||||
|
assertEq(params.amountIn, amountIn);
|
||||||
|
assertEq(params.minAmountOut, minAmountOut);
|
||||||
|
assertEq(params.receiver, address(this));
|
||||||
|
assertEq(params.needsApproval, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following pools are unique and do not have a factory
|
// The following pools are unique and do not have a factory
|
||||||
@@ -107,7 +112,7 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
|
|
||||||
deal(DAI_ADDR, address(curveExecutorExposed), amountIn);
|
deal(DAI_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
bytes memory data = abi.encode(
|
bytes memory data = abi.encode(
|
||||||
route, swapParams, amountIn, minAmountOut, pools, address(this)
|
route, swapParams, amountIn, minAmountOut, pools, address(this), true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -127,13 +132,13 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
|
|
||||||
deal(address(curveExecutorExposed), amountIn);
|
deal(address(curveExecutorExposed), amountIn);
|
||||||
bytes memory data = abi.encode(
|
bytes memory data = abi.encode(
|
||||||
route, swapParams, amountIn, minAmountOut, pools, address(this)
|
route, swapParams, amountIn, minAmountOut, pools, address(this), false
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
assertTrue(amountOut == 1 ether - 1); //// Gets 1 wei less than amountOut
|
assertTrue(amountOut == 1001072414418410898);
|
||||||
assertEq(IERC20(STETH_ADDR).balanceOf(address(this)), amountOut - 1);
|
assertEq(IERC20(STETH_ADDR).balanceOf(address(this)), amountOut - 1); //// Gets 1 wei less than amountOut
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSwapTricrypto2Pool() public {
|
function testSwapTricrypto2Pool() public {
|
||||||
@@ -153,7 +158,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -181,7 +187,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -210,7 +217,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -241,7 +249,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -272,7 +281,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -301,7 +311,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -326,7 +337,7 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
|
|
||||||
deal(WETH_ADDR, address(curveExecutorExposed), amountIn);
|
deal(WETH_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
bytes memory data = abi.encode(
|
bytes memory data = abi.encode(
|
||||||
route, swapParams, amountIn, minAmountOut, pools, address(this)
|
route, swapParams, amountIn, minAmountOut, pools, address(this), true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -352,7 +363,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -383,7 +395,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -411,7 +424,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -439,7 +453,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -467,7 +482,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -495,7 +511,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
@@ -529,7 +546,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
amountIn,
|
amountIn,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
pools,
|
pools,
|
||||||
address(curveExecutorExposed)
|
address(curveExecutorExposed),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|||||||
Reference in New Issue
Block a user