refactor: move swap params from interface to executor, add needsApproval

This commit is contained in:
royvardhan
2025-03-17 19:32:53 +05:30
committed by Diana Carvalho
parent 3054ca042b
commit 826eca4a80
3 changed files with 69 additions and 72 deletions

View File

@@ -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

View File

@@ -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));
} }
} }

View File

@@ -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);