feat: allow executor to do native swaps, add diff pool type tests

Took 4 seconds
This commit is contained in:
royvardhan
2025-03-13 22:56:29 +05:30
committed by Diana Carvalho
parent 7cde5130d6
commit 93bdc86dc6
3 changed files with 307 additions and 17 deletions

View File

@@ -30,6 +30,7 @@ contract Constants is Test, BaseConstants {
address UNPAUSER = makeAddr("unpauser");
// Assets
address ETH_ADDR = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
address WETH_ADDR = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
address DAI_ADDR = address(0x6B175474E89094C44Da98b954EedeAC495271d0F);
address BAL_ADDR = address(0xba100000625a3754423978a60c9317c58a424e3D);
@@ -39,6 +40,12 @@ contract Constants is Test, BaseConstants {
address USDE_ADDR = address(0x4c9EDD5852cd905f086C759E8383e09bff1E68B3);
address USDT_ADDR = address(0xdAC17F958D2ee523a2206206994597C13D831ec7);
address PEPE_ADDR = address(0x6982508145454Ce325dDbE47a25d4ec3d2311933);
address STETH_ADDR = address(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84);
address LUSD_ADDR = address(0x5f98805A4E8be255a32880FDeC7F6728C6568bA0);
address LDO_ADDR = address(0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32);
address CRV_ADDR = address(0xD533a949740bb3306d119CC777fa900bA034cd52);
address ADAI_ADDR = address(0x028171bCA77440897B824Ca71D1c56caC55b68A3);
address AUSDC_ADDR = address(0xBcca60bB61934080951369a648Fb03DF4F96263C);
// Uniswap v2
address WETH_DAI_POOL = 0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11;
@@ -77,8 +84,23 @@ contract Constants is Test, BaseConstants {
0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9;
// Curve
// 3pool - Pool type 1
address TRIPOOL_USDT_USDC_DAI = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7;
// Tricrypto - Pool type 3
address TRICRYPTO_USDC_WBTC_WETH =
0x7F86Bf177Dd4F3494b841a37e810A34dD56c829B;
// stEth - Pool type 4
address STETH_POOL = 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022;
// LUSD - Pool type 5
address LUSD_POOL = 0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA;
// Compound - Pool type 6
address CPOOL = 0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56;
// LDO - Pool type 7
address LDO_POOL = 0x9409280DC1e6D33AB7A8C6EC03e5763FB61772B5;
// CRV - Pool type 8
address CRV_POOL = 0x8301AE4fc9c624d1D396cbDAa1ed877821D7C511;
// AAVE - Pool type 0
address AAVE_POOL = 0xDeBF20617708857ebe4F679508E7b7863a8A8EeE;
// Uniswap universal router
address UNIVERSAL_ROUTER = 0x66a9893cC07D91D95644AEDD05D03f95e1dBA8Af;

View File

@@ -5,8 +5,26 @@ import "@src/executors/CurveExecutor.sol";
import {Test} from "../../lib/forge-std/src/Test.sol";
import {Constants} from "../Constants.sol";
interface ICurvePool {
function coins(uint256 i) external view returns (address);
}
interface ILendingPool {
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
function withdraw(address asset, uint256 amount, address to)
external
returns (uint256);
}
contract CurveExecutorExposed is CurveExecutor {
constructor(address _curveRouter) CurveExecutor(_curveRouter) {}
constructor(address _curveRouter, address _ethAddress) CurveExecutor(_curveRouter, _ethAddress) {}
function decodeParams(bytes calldata data)
external
@@ -25,7 +43,7 @@ contract CurveExecutorTest is Test, Constants {
function setUp() public {
uint256 forkBlock = 22031795;
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
curveExecutorExposed = new CurveExecutorExposed(CURVE_ROUTER);
curveExecutorExposed = new CurveExecutorExposed(CURVE_ROUTER, ETH_ADDR);
}
function testDecodeParams() public view {
@@ -61,18 +79,52 @@ contract CurveExecutorTest is Test, Constants {
assertEq(params.swapParams[0][3], 3);
}
function testSwapCurve() public {
address[11] memory route;
route[0] = WETH_ADDR;
route[1] = TRICRYPTO_USDC_WBTC_WETH;
route[2] = USDC_ADDR;
uint256[5][5] memory swapParams;
swapParams[0][0] = 2; // tokenIn Index
swapParams[0][1] = 0; // tokenOut Index
swapParams[0][2] = 1; // swap type
swapParams[0][3] = 3; // pool type
swapParams[0][4] = 3; // n_coins
function testCurveSwapPoolType0() public {
address[11] memory route = _getRoute(ADAI_ADDR, AUSDC_ADDR, AAVE_POOL);
uint256[5][5] memory swapParams = _getSwapParams(AAVE_POOL, ADAI_ADDR, AUSDC_ADDR, 1, 1);
uint256 amountIn = 1 ether;
uint256 minAmountOut = 0;
address[5] memory pools;
dealAaveDai();
bytes memory data = abi.encode(
route, swapParams, amountIn, minAmountOut, pools, address(curveExecutorExposed)
);
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
assertEq(amountOut, 999734);
assertEq(IERC20(AUSDC_ADDR).balanceOf(address(curveExecutorExposed)), amountOut);
}
function testCurveSwapPoolType1() public {
address[11] memory route =
_getRoute(DAI_ADDR, USDC_ADDR, TRIPOOL_USDT_USDC_DAI);
uint256[5][5] memory swapParams =
_getSwapParams(TRIPOOL_USDT_USDC_DAI, DAI_ADDR, USDC_ADDR, 1, 1);
uint256 amountIn = 1 ether;
uint256 minAmountOut = 0;
address[5] memory pools;
deal(DAI_ADDR, address(curveExecutorExposed), amountIn);
bytes memory data = abi.encode(
route, swapParams, amountIn, minAmountOut, pools, address(this)
);
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
assertEq(amountOut, 999796);
assertEq(IERC20(USDC_ADDR).balanceOf(address(this)), amountOut);
}
function testCurveSwapPoolType3() public {
address[11] memory route =
_getRoute(WETH_ADDR, USDC_ADDR, TRICRYPTO_USDC_WBTC_WETH);
uint256[5][5] memory swapParams =
_getSwapParams(TRICRYPTO_USDC_WBTC_WETH, WETH_ADDR, USDC_ADDR, 1, 3);
uint256 amountIn = 1 ether;
uint256 minAmountOut = 0;
@@ -88,4 +140,203 @@ contract CurveExecutorTest is Test, Constants {
assertEq(amountOut, 1861130973);
assertEq(IERC20(USDC_ADDR).balanceOf(address(this)), amountOut);
}
function testCurveSwapPoolType4() public {
address[11] memory route =
_getRoute(ETH_ADDR, STETH_ADDR, STETH_POOL);
uint256[5][5] memory swapParams =
_getSwapParams(STETH_POOL, ETH_ADDR, STETH_ADDR, 1, 1);
uint256 amountIn = 1 ether;
uint256 minAmountOut = 0;
address[5] memory pools;
deal(address(curveExecutorExposed), amountIn);
bytes memory data = abi.encode(
route, swapParams, amountIn, minAmountOut, pools, address(curveExecutorExposed)
);
uint256 amountOut = curveExecutorExposed.swap(
amountIn, data
);
assertTrue(amountOut >= 1 ether);
assertEq(IERC20(STETH_ADDR).balanceOf(address(curveExecutorExposed)), amountOut - 1); // Gets 1 wei less than amountOut
// Now reverse the swap
amountIn = amountOut - 1;
route =
_getRoute(STETH_ADDR, ETH_ADDR, STETH_POOL);
swapParams =
_getSwapParams(STETH_POOL, STETH_ADDR, ETH_ADDR, 1, 1);
data = abi.encode(
route, swapParams, amountIn, minAmountOut, pools, address(curveExecutorExposed)
);
amountOut = curveExecutorExposed.swap(
amountIn, data
);
assertEq(address(curveExecutorExposed).balance, 999800010006950374);
}
function testCurveSwapPoolType5() public {
address[11] memory route =
_getRoute(LUSD_ADDR, USDT_ADDR, LUSD_POOL);
uint256[5][5] memory swapParams =
_getSwapParams(LUSD_POOL, LUSD_ADDR, USDT_ADDR, 2, 1);
// pool.coins(index) reverts, defaulting tokenOut index to 0
swapParams[0][1] = 3;
uint256 amountIn = 1 ether;
uint256 minAmountOut = 0;
address[5] memory pools;
deal(LUSD_ADDR, address(curveExecutorExposed), amountIn);
bytes memory data = abi.encode(
route, swapParams, amountIn, minAmountOut, pools, address(curveExecutorExposed)
);
uint256 amountOut = curveExecutorExposed.swap(
amountIn, data
);
assertEq(amountOut, 1001785);
assertEq(IERC20(USDT_ADDR).balanceOf(address(curveExecutorExposed)), amountOut);
}
function testCurveSwapPoolType6() public {
address[11] memory route =
_getRoute(DAI_ADDR, USDC_ADDR, CPOOL);
uint256[5][5] memory swapParams =
_getSwapParams(CPOOL, DAI_ADDR, USDC_ADDR, 2, 1);
// pool.coins(index) reverts, defaulting tokenOut index to 0
swapParams[0][1] = 1;
uint256 amountIn = 1 ether;
uint256 minAmountOut = 0;
address[5] memory pools;
deal(DAI_ADDR, address(curveExecutorExposed), amountIn);
bytes memory data = abi.encode(
route, swapParams, amountIn, minAmountOut, pools, address(curveExecutorExposed)
);
uint256 amountOut = curveExecutorExposed.swap(
amountIn, data);
assertEq(amountOut, 999549);
assertEq(IERC20(USDC_ADDR).balanceOf(address(curveExecutorExposed)), amountOut);
}
function testCurveSwapPoolType7() public {
address[11] memory route = _getRoute(WETH_ADDR, LDO_ADDR, LDO_POOL);
uint256[5][5] memory swapParams = _getSwapParams(LDO_POOL, WETH_ADDR, LDO_ADDR, 1, 4);
// pool.coins(index) reverts, defaulting tokenOut index to 0
swapParams[0][1] = 1;
uint256 amountIn = 1 ether;
uint256 minAmountOut = 0;
address[5] memory pools;
deal(WETH_ADDR, address(curveExecutorExposed), amountIn);
bytes memory data = abi.encode(
route, swapParams, amountIn, minAmountOut, pools, address(curveExecutorExposed)
);
uint256 amountOut = curveExecutorExposed.swap(
amountIn, data);
assertEq(amountOut, 2075236672516568049094);
assertEq(IERC20(LDO_ADDR).balanceOf(address(curveExecutorExposed)), amountOut);
}
function testCurveSwapPoolType8() public {
address[11] memory route = _getRoute(CRV_ADDR, WETH_ADDR, CRV_POOL);
uint256[5][5] memory swapParams = _getSwapParams(CRV_POOL, CRV_ADDR, WETH_ADDR, 1, 4);
uint256 amountIn = 1 ether;
uint256 minAmountOut = 0;
address[5] memory pools;
deal(CRV_ADDR, address(curveExecutorExposed), amountIn);
bytes memory data = abi.encode(
route, swapParams, amountIn, minAmountOut, pools, address(curveExecutorExposed)
);
uint256 amountOut = curveExecutorExposed.swap(
amountIn, data);
assertEq(amountOut, 21806692849);
assertEq(IERC20(WETH_ADDR).balanceOf(address(curveExecutorExposed)), amountOut);
}
function _getRoute(address tokenIn, address tokenOut, address pool)
internal
pure
returns (address[11] memory route)
{
route[0] = tokenIn;
route[2] = tokenOut;
route[1] = pool;
}
function _getSwapParams(
address pool,
address tokenIn,
address tokenOut,
uint256 swapType,
uint256 poolType
) internal view returns (uint256[5][5] memory swapParams) {
// Get number of coins in pool and their indices
uint256 coinInIndex;
uint256 coinOutIndex;
uint256 nCoins;
address lastCoinAddress = address(1);
while (lastCoinAddress != address(0)) {
try ICurvePool(pool).coins(nCoins) returns (address coin) {
lastCoinAddress = coin;
nCoins++;
if (coin == tokenIn) {
coinInIndex = nCoins - 1;
}
if (coin == tokenOut) {
coinOutIndex = nCoins - 1;
}
} catch {
lastCoinAddress = address(0);
}
}
swapParams[0][0] = coinInIndex;
swapParams[0][1] = coinOutIndex;
swapParams[0][2] = swapType;
swapParams[0][3] = poolType;
swapParams[0][4] = nCoins;
}
function dealAaveDai() internal {
deal(DAI_ADDR, address(curveExecutorExposed), 100_000 * 10 ** 18);
ILendingPool aave =
ILendingPool(0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9);
vm.startPrank(address(curveExecutorExposed));
IERC20(DAI_ADDR).approve(address(aave), type(uint256).max);
aave.deposit(DAI_ADDR, 100_000 * 10 ** 18, address(curveExecutorExposed), 0);
vm.stopPrank();
}
}