diff --git a/foundry/src/executors/EkuboExecutor.sol b/foundry/src/executors/EkuboExecutor.sol index fc21e6e..1c0d07c 100644 --- a/foundry/src/executors/EkuboExecutor.sol +++ b/foundry/src/executors/EkuboExecutor.sol @@ -19,6 +19,9 @@ contract EkuboExecutor is IExecutor, ICallback, ILocker, IPayer { ICore immutable core; + bytes4 constant LOCKED_SELECTOR = 0xb45a3c0e; // locked(uint256) + bytes4 constant PAY_CALLBACK_SELECTOR = 0x599d0714; // payCallback(uint256,address) + uint256 constant POOL_DATA_OFFSET = 56; uint256 constant HOP_BYTE_LEN = 52; @@ -34,7 +37,8 @@ contract EkuboExecutor is IExecutor, ICallback, ILocker, IPayer { if (data.length < 92) revert EkuboExecutor__InvalidDataLength(); uint256 tokenOutOffset = data.length - HOP_BYTE_LEN; - address tokenOut = address(bytes20(LibBytes.loadCalldata(data, tokenOutOffset))); + address tokenOut = + address(bytes20(LibBytes.loadCalldata(data, tokenOutOffset))); uint256 tokenOutBalanceBefore = _balanceOf(tokenOut); @@ -60,9 +64,9 @@ contract EkuboExecutor is IExecutor, ICallback, ILocker, IPayer { bytes4 selector = bytes4(raw[:4]); - if (selector == 0xb45a3c0e) { // Selector of locked(uint256) + if (selector == LOCKED_SELECTOR) { _locked(stripped); - } else if (selector == 0x599d0714) { // Selector of payCallback(uint256,address) + } else if (selector == PAY_CALLBACK_SELECTOR) { _payCallback(stripped); } else { revert EkuboExecutor__UnknownCallback(); @@ -84,7 +88,11 @@ contract EkuboExecutor is IExecutor, ICallback, ILocker, IPayer { SafeTransferLib.safeTransfer(token, address(core), amount); } - function _balanceOf(address token) internal view returns (uint256 balance) { + function _balanceOf(address token) + internal + view + returns (uint256 balance) + { balance = token == NATIVE_TOKEN_ADDRESS ? address(this).balance : IERC20(token).balanceOf(address(this)); @@ -128,22 +136,15 @@ contract EkuboExecutor is IExecutor, ICallback, ILocker, IPayer { uint256 offset = POOL_DATA_OFFSET; for (uint256 i = 0; i < hopsLength; i++) { - address nextTokenOut = address(bytes20(LibBytes.loadCalldata(swapData, offset))); - Config poolConfig = Config.wrap(LibBytes.loadCalldata(swapData, offset + 20)); + address nextTokenOut = + address(bytes20(LibBytes.loadCalldata(swapData, offset))); + Config poolConfig = + Config.wrap(LibBytes.loadCalldata(swapData, offset + 20)); - ( - address token0, - address token1, - bool isToken1 - ) = nextTokenIn > nextTokenOut ? ( - nextTokenOut, - nextTokenIn, - true - ) : ( - nextTokenIn, - nextTokenOut, - false - ); + (address token0, address token1, bool isToken1) = nextTokenIn + > nextTokenOut + ? (nextTokenOut, nextTokenIn, true) + : (nextTokenIn, nextTokenOut, false); (int128 delta0, int128 delta1) = core.swap_611415377( PoolKey(token0, token1, poolConfig), @@ -165,11 +166,7 @@ contract EkuboExecutor is IExecutor, ICallback, ILocker, IPayer { _pay(tokenIn, tokenInDebtAmount); - core.withdraw( - nextTokenIn, - receiver, - uint128(nextAmountIn) - ); + core.withdraw(nextTokenIn, receiver, uint128(nextAmountIn)); } function _pay(address token, uint128 amount) internal { diff --git a/foundry/test/executors/EkuboExecutor.t.sol b/foundry/test/executors/EkuboExecutor.t.sol index d870352..0971b40 100644 --- a/foundry/test/executors/EkuboExecutor.t.sol +++ b/foundry/test/executors/EkuboExecutor.t.sol @@ -9,7 +9,8 @@ import {NATIVE_TOKEN_ADDRESS} from "@ekubo/math/constants.sol"; import {ICore} from "@ekubo/interfaces/ICore.sol"; contract EkuboExecutorTest is Test, Constants { - address constant EXECUTOR_ADDRESS = 0xcA4F73Fe97D0B987a0D12B39BBD562c779BAb6f6; // Same address as in swap_encoder.rs tests + address constant EXECUTOR_ADDRESS = + 0xcA4F73Fe97D0B987a0D12B39BBD562c779BAb6f6; // Same address as in swap_encoder.rs tests EkuboExecutor executor; IERC20 USDC = IERC20(USDC_ADDR); @@ -17,7 +18,8 @@ contract EkuboExecutorTest is Test, Constants { address constant CORE_ADDRESS = 0xe0e0e08A6A4b9Dc7bD67BCB7aadE5cF48157d444; - bytes32 constant ORACLE_CONFIG = 0x51d02a5948496a67827242eabc5725531342527c000000000000000000000000; + bytes32 constant ORACLE_CONFIG = + 0x51d02a5948496a67827242eabc5725531342527c000000000000000000000000; function setUp() public { vm.createSelectFork(vm.rpcUrl("mainnet"), 22082754); @@ -57,8 +59,13 @@ contract EkuboExecutorTest is Test, Constants { assertEq(CORE_ADDRESS.balance, ethBalanceBeforeCore + amountIn); assertEq(address(executor).balance, ethBalanceBeforeExecutor - amountIn); - assertEq(USDC.balanceOf(CORE_ADDRESS), usdcBalanceBeforeCore - amountOut); - assertEq(USDC.balanceOf(address(executor)), usdcBalanceBeforeExecutor + amountOut); + assertEq( + USDC.balanceOf(CORE_ADDRESS), usdcBalanceBeforeCore - amountOut + ); + assertEq( + USDC.balanceOf(address(executor)), + usdcBalanceBeforeExecutor + amountOut + ); } function testSingleSwapERC20() public { @@ -86,10 +93,15 @@ contract EkuboExecutorTest is Test, Constants { console.log(amountOut); assertEq(USDC.balanceOf(CORE_ADDRESS), usdcBalanceBeforeCore + amountIn); - assertEq(USDC.balanceOf(address(executor)), usdcBalanceBeforeExecutor - amountIn); + assertEq( + USDC.balanceOf(address(executor)), + usdcBalanceBeforeExecutor - amountIn + ); assertEq(CORE_ADDRESS.balance, ethBalanceBeforeCore - amountOut); - assertEq(address(executor).balance, ethBalanceBeforeExecutor + amountOut); + assertEq( + address(executor).balance, ethBalanceBeforeExecutor + amountOut + ); } // Expects input that encodes the same test case as swap_encoder::tests::ekubo::test_encode_swap_multi @@ -113,8 +125,13 @@ contract EkuboExecutorTest is Test, Constants { assertEq(CORE_ADDRESS.balance, ethBalanceBeforeCore + amountIn); assertEq(address(executor).balance, ethBalanceBeforeExecutor - amountIn); - assertEq(USDT.balanceOf(CORE_ADDRESS), usdtBalanceBeforeCore - amountOut); - assertEq(USDT.balanceOf(address(executor)), usdtBalanceBeforeExecutor + amountOut); + assertEq( + USDT.balanceOf(CORE_ADDRESS), usdtBalanceBeforeCore - amountOut + ); + assertEq( + USDT.balanceOf(address(executor)), + usdtBalanceBeforeExecutor + amountOut + ); } // Same test case as in swap_encoder::tests::ekubo::test_encode_swap_multi @@ -125,7 +142,9 @@ contract EkuboExecutorTest is Test, Constants { USDC_ADDR, // tokenOut of 1st swap ORACLE_CONFIG, // config of 1st swap USDT_ADDR, // tokenOut of 2nd swap - bytes32(0x00000000000000000000000000000000000000000001a36e2eb1c43200000032) // config of 2nd swap (0.0025% fee & 0.005% base pool) + bytes32( + 0x00000000000000000000000000000000000000000001a36e2eb1c43200000032 + ) // config of 2nd swap (0.0025% fee & 0.005% base pool) ); multiHopSwap(data); }