From af449562b0c4038cf666194a52eea582855495fc Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Mon, 31 Mar 2025 18:07:59 +0100 Subject: [PATCH] feat: Refactor callback to use transient storage With this, we don't need the univ3 specific method in the router contract. This should be flexible enough for most protocols that integrate TODO: is this safe enough?? --- don't change below this line --- ENG-4411 Took 1 hour 52 minutes Took 4 minutes Took 5 minutes --- foundry/src/Dispatcher.sol | 12 ++++++++-- foundry/src/TychoRouter.sol | 20 ---------------- foundry/src/executors/UniswapV3Executor.sol | 11 +++++---- foundry/src/executors/UniswapV4Executor.sol | 12 ++++------ foundry/test/TychoRouter.t.sol | 24 +++++++++---------- .../test/executors/UniswapV3Executor.t.sol | 19 +-------------- .../test/executors/UniswapV4Executor.t.sol | 19 ++++++--------- foundry/test/executors/UniswapV4Utils.sol | 5 +--- .../evm/strategy_encoder/strategy_encoders.rs | 9 +++---- .../evm/swap_encoder/swap_encoders.rs | 16 +------------ 10 files changed, 45 insertions(+), 102 deletions(-) diff --git a/foundry/src/Dispatcher.sol b/foundry/src/Dispatcher.sol index 828d0b1..ae8deba 100644 --- a/foundry/src/Dispatcher.sol +++ b/foundry/src/Dispatcher.sol @@ -52,7 +52,7 @@ contract Dispatcher { * @dev Calls an executor, assumes swap.protocolData contains * protocol-specific data required by the executor. */ - // slither-disable-next-line delegatecall-loop + // slither-disable-next-line delegatecall-loop,assembly function _callExecutor( address executor, uint256 amount, @@ -62,6 +62,10 @@ contract Dispatcher { revert Dispatcher__UnapprovedExecutor(); } + assembly { + tstore(0, executor) + } + // slither-disable-next-line controlled-delegatecall,low-level-calls (bool success, bytes memory result) = executor.delegatecall( abi.encodeWithSelector(IExecutor.swap.selector, amount, data) @@ -80,8 +84,12 @@ contract Dispatcher { calculatedAmount = abi.decode(result, (uint256)); } + // slither-disable-next-line assembly function _handleCallback(bytes calldata data) internal { - address executor = address(uint160(bytes20(data[data.length - 20:]))); + address executor; + assembly { + executor := tload(0) + } if (!executors[executor]) { revert Dispatcher__UnapprovedExecutor(); diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 3a549cd..13391b9 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -502,26 +502,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { require(msg.sender.code.length != 0); } - /** - * @dev Called by UniswapV3 pool when swapping on it. - * See in IUniswapV3SwapCallback for documentation. - */ - function uniswapV3SwapCallback( - int256, /* amount0Delta */ - int256, /* amount1Delta */ - bytes calldata data - ) external { - if (data.length < 24) revert TychoRouter__InvalidDataLength(); - // We are taking advantage of the fact that the data we need is already encoded in the correct format inside msg.data - // This way we preserve the bytes calldata (and don't need to convert it to bytes memory) - uint256 dataOffset = 4 + 32 + 32 + 32; // Skip selector + 2 ints + data_offset - uint256 dataLength = - uint256(bytes32(msg.data[dataOffset:dataOffset + 32])); - - bytes calldata fullData = msg.data[4:dataOffset + 32 + dataLength]; - _handleCallback(fullData); - } - /** * @dev Called by PancakeV3 pool when swapping on it. */ diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index 1d46c08..7b6383f 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -80,6 +80,7 @@ contract UniswapV3Executor is IExecutor, ICallback { returns (bytes memory result) { // The data has the following layout: + // - selector (4 bytes) // - amount0Delta (32 bytes) // - amount1Delta (32 bytes) // - dataOffset (32 bytes) @@ -87,11 +88,11 @@ contract UniswapV3Executor is IExecutor, ICallback { // - protocolData (variable length) (int256 amount0Delta, int256 amount1Delta) = - abi.decode(msgData[:64], (int256, int256)); + abi.decode(msgData[4:68], (int256, int256)); - address tokenIn = address(bytes20(msgData[128:148])); + address tokenIn = address(bytes20(msgData[132:152])); - verifyCallback(msgData[128:]); + verifyCallback(msgData[132:]); uint256 amountOwed = amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta); @@ -147,10 +148,10 @@ contract UniswapV3Executor is IExecutor, ICallback { function _makeV3CallbackData(address tokenIn, address tokenOut, uint24 fee) internal - view + pure returns (bytes memory) { - return abi.encodePacked(tokenIn, tokenOut, fee, self); + return abi.encodePacked(tokenIn, tokenOut, fee); } function _verifyPairAddress( diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index a487ef1..694937f 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -41,7 +41,6 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback { address tokenIn, address tokenOut, bool zeroForOne, - address callbackExecutor, UniswapV4Executor.UniswapV4Pool[] memory pools ) = _decodeData(data); @@ -107,14 +106,13 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback { params[2] = abi.encode(Currency.wrap(tokenOut), uint256(0)); swapData = abi.encode(actions, params); } - bytes memory fullData = abi.encodePacked(swapData, callbackExecutor); uint256 tokenOutBalanceBefore; tokenOutBalanceBefore = tokenOut == address(0) ? address(this).balance : IERC20(tokenOut).balanceOf(address(this)); - executeActions(fullData); + executeActions(swapData); uint256 tokenOutBalanceAfter; @@ -140,22 +138,20 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback { address tokenIn, address tokenOut, bool zeroForOne, - address callbackExecutor, UniswapV4Pool[] memory pools ) { - if (data.length < 87) { + if (data.length < 67) { revert UniswapV4Executor__InvalidDataLength(); } tokenIn = address(bytes20(data[0:20])); tokenOut = address(bytes20(data[20:40])); zeroForOne = (data[40] != 0); - callbackExecutor = address(bytes20(data[41:61])); - uint256 poolsLength = (data.length - 61) / 26; // 26 bytes per pool object + uint256 poolsLength = (data.length - 41) / 26; // 26 bytes per pool object pools = new UniswapV4Pool[](poolsLength); - bytes memory poolsData = data[61:]; + bytes memory poolsData = data[41:]; uint256 offset = 0; for (uint256 i = 0; i < poolsLength; i++) { address intermediaryToken; diff --git a/foundry/test/TychoRouter.t.sol b/foundry/test/TychoRouter.t.sol index 49fde90..3db7b04 100644 --- a/foundry/test/TychoRouter.t.sol +++ b/foundry/test/TychoRouter.t.sol @@ -897,7 +897,7 @@ contract TychoRouterTest is TychoRouterTestSetup { IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max); // Encoded solution generated using `test_split_encoding_strategy_usv4` (bool success,) = tychoRouterAddr.call( - hex"d499aa88000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006814875700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ed015f0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000413a7c6367c69ac46fc2b633fd53e583b74b20ec9b3ea83b069fe564765560a4cb335af200fd90ddb5f56d11e469c11a97420499f1b3ee0c1db13149a74daa90db1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008c008a0001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d231193300f62849f9a0b5bf2913b396098f7c7019b51a820a0000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000" + hex"d499aa88000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000681256a200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ead0aa0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000413803331cb4aae060a37526a6dce2440366c9bc77a4e03b751c0f691fc1fb890b2fcf855c7362c3ec08185fca4b8379a42c08880528f2e30bd823dadd405660d01c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007800760001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000" ); vm.stopPrank(); @@ -920,7 +920,7 @@ contract TychoRouterTest is TychoRouterTestSetup { // Encoded solution generated using `test_split_encoding_strategy_usv4_eth_in` (bool success,) = tychoRouterAddr.call{value: 1 ether}( - hex"d499aa880000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000c87c939ae635f92dc2379c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006814877000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ed017800000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004193acc98d79044e8ec1bc3ced832dc679e38ac8c6fe9b5befd1e5e44cb44edb0e365f1c5d6e3ca6590ed1a053f1841aede29e5b573f046387aff794520a0f22581b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007200700001000000f62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d231193301f62849f9a0b5bf2913b396098f7c7019b51a820a6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000" + hex"d499aa880000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000c87c939ae635f92dc2379c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000681256e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ead0ec0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000418b5f23ec914f030acb2c8d1ebf4a29e2939503c5b77890f17ae7615fa70a0a1d13cd43b88008246daa88c2eae9d317ca0f42aabdf234f7fea93a6b99daf018781b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e005c0001000000f62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933016982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000" ); vm.stopPrank(); @@ -947,7 +947,7 @@ contract TychoRouterTest is TychoRouterTestSetup { // Encoded solution generated using `test_split_encoding_strategy_usv4_eth_out` (bool success,) = tychoRouterAddr.call( - hex"d499aa8800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006814878000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ed018800000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004190134d2d142caff6dbea417292a15685119bd676b2b73bad35fe39f720f7c3163f16d057327499019506b6f690a3916fd3375c579c9cb814113b1516187380531b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007200700001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a0000000000000000000000000000000000000000000bb800003c0000000000000000000000000000" + hex"d499aa8800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000681256ff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ead107000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041b922cb2ddd143d935da7e22171b298fb2dc5dcb28f300f002069fbe36594478a1a18dc7b66ee2f8143247d4af15a26a3ac69f364a902fca1a6983b68a4e7ef881c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e005c0001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000000000000000000000000000bb800003c0000" ); vm.stopPrank(); @@ -1140,9 +1140,8 @@ contract TychoRouterTest is TychoRouterTestSetup { tickSpacing: int24(1) }); - bytes memory protocolData = UniswapV4Utils.encodeExactInput( - USDE_ADDR, USDT_ADDR, true, address(usv4Executor), pools - ); + bytes memory protocolData = + UniswapV4Utils.encodeExactInput(USDE_ADDR, USDT_ADDR, true, pools); bytes memory swap = encodeSwap( uint8(0), uint8(1), uint24(0), address(usv4Executor), protocolData @@ -1173,9 +1172,8 @@ contract TychoRouterTest is TychoRouterTestSetup { tickSpacing: int24(1) }); - bytes memory protocolData = UniswapV4Utils.encodeExactInput( - USDE_ADDR, USDT_ADDR, true, address(usv4Executor), pools - ); + bytes memory protocolData = + UniswapV4Utils.encodeExactInput(USDE_ADDR, USDT_ADDR, true, pools); bytes memory swap = encodeSwap( uint8(0), uint8(1), uint24(0), address(usv4Executor), protocolData @@ -1221,9 +1219,8 @@ contract TychoRouterTest is TychoRouterTestSetup { tickSpacing: int24(60) }); - bytes memory protocolData = UniswapV4Utils.encodeExactInput( - USDE_ADDR, WBTC_ADDR, true, address(usv4Executor), pools - ); + bytes memory protocolData = + UniswapV4Utils.encodeExactInput(USDE_ADDR, WBTC_ADDR, true, pools); bytes memory swap = encodeSwap( uint8(0), uint8(1), uint24(0), address(usv4Executor), protocolData @@ -1388,6 +1385,7 @@ contract TychoRouterTest is TychoRouterTestSetup { hex"d499aa880000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f4308e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000681363d200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ebddda0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000418d58a54a3b8afc5d2e228ce6c5a1ab6b342cb5bfd9a00d57b869a4703ca2bb084d10d21f6842be9652a9ff2392673fbdcb961439ccc962de09f6bc64e5e665fe1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de006d00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564001006d01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8000000" ); + assertTrue(success, "Call Failed"); assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99889294); vm.stopPrank(); @@ -1404,6 +1402,7 @@ contract TychoRouterTest is TychoRouterTestSetup { hex"d499aa880000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000681363ee00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ebddf6000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041358738c580b15c5aeb2cd79615e7405569255d599e45d2d537805c4d403a8ce4198cdde7c328a881afeb2f5dc721c5d13dfae03ded6e8e958a96e303e7fa07e91b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000136006d00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564001006d00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d801005601000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000" ); + assertTrue(success, "Call Failed"); assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99574171); vm.stopPrank(); @@ -1420,6 +1419,7 @@ contract TychoRouterTest is TychoRouterTestSetup { hex"d499aa880000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005eea514000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006813641000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ebde18000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041261a267c7d90a230d7f6d0917652953ef5cdaaabc80234a0c3d39ca20687f5af0b56421d0b0bec01d5ba66dd435d7cd63e95abcea114aa9fef6fe9d77589c12e1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000136005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d0139501006d01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564000006d01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80000000000000000000000" ); + assertTrue(success, "Call Failed"); assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99525908); vm.stopPrank(); diff --git a/foundry/test/executors/UniswapV3Executor.t.sol b/foundry/test/executors/UniswapV3Executor.t.sol index 01f5d1c..59b03ba 100644 --- a/foundry/test/executors/UniswapV3Executor.t.sol +++ b/foundry/test/executors/UniswapV3Executor.t.sol @@ -111,6 +111,7 @@ contract UniswapV3ExecutorTest is Test, Constants { uint256 dataLength = protocolData.length; bytes memory callbackData = abi.encodePacked( + bytes4(0xfa461e33), int256(amountOwed), // amount0Delta int256(0), // amount1Delta dataOffset, @@ -124,24 +125,6 @@ contract UniswapV3ExecutorTest is Test, Constants { assertEq(finalPoolReserve - initialPoolReserve, amountOwed); } - function testSwapIntegration() public { - uint256 amountIn = 10 ** 18; - deal(WETH_ADDR, address(uniswapV3Exposed), amountIn); - - uint256 expAmountOut = 1205_128428842122129186; //Swap 1 WETH for 1205.12 DAI - bool zeroForOne = false; - - bytes memory data = encodeUniswapV3Swap( - WETH_ADDR, DAI_ADDR, address(this), DAI_WETH_USV3, zeroForOne - ); - - uint256 amountOut = uniswapV3Exposed.swap(amountIn, data); - - assertGe(amountOut, expAmountOut); - assertEq(IERC20(WETH_ADDR).balanceOf(address(uniswapV3Exposed)), 0); - assertGe(IERC20(DAI_ADDR).balanceOf(address(this)), expAmountOut); - } - function testSwapFailureInvalidTarget() public { uint256 amountIn = 10 ** 18; deal(WETH_ADDR, address(uniswapV3Exposed), amountIn); diff --git a/foundry/test/executors/UniswapV4Executor.t.sol b/foundry/test/executors/UniswapV4Executor.t.sol index e3b3cb6..487e251 100644 --- a/foundry/test/executors/UniswapV4Executor.t.sol +++ b/foundry/test/executors/UniswapV4Executor.t.sol @@ -18,7 +18,6 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor { address tokenIn, address tokenOut, bool zeroForOne, - address callbackExecutor, UniswapV4Pool[] memory pools ) { @@ -62,21 +61,19 @@ contract UniswapV4ExecutorTest is Test, Constants { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, USDT_ADDR, zeroForOne, address(uniswapV4Exposed), pools + USDE_ADDR, USDT_ADDR, zeroForOne, pools ); ( address tokenIn, address tokenOut, bool zeroForOneDecoded, - address callbackExecutor, UniswapV4Executor.UniswapV4Pool[] memory decodedPools ) = uniswapV4Exposed.decodeData(data); assertEq(tokenIn, USDE_ADDR); assertEq(tokenOut, USDT_ADDR); assertEq(zeroForOneDecoded, zeroForOne); - assertEq(callbackExecutor, address(uniswapV4Exposed)); assertEq(decodedPools.length, 2); assertEq(decodedPools[0].intermediaryToken, USDT_ADDR); assertEq(decodedPools[0].fee, pool1Fee); @@ -101,9 +98,8 @@ contract UniswapV4ExecutorTest is Test, Constants { tickSpacing: int24(1) }); - bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, USDT_ADDR, true, address(uniswapV4Exposed), pools - ); + bytes memory data = + UniswapV4Utils.encodeExactInput(USDE_ADDR, USDT_ADDR, true, pools); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); assertEq(USDE.balanceOf(poolManager), usdeBalanceBeforePool + amountIn); @@ -118,7 +114,7 @@ contract UniswapV4ExecutorTest is Test, Constants { // USDE -> USDT // Generated by the Tycho swap encoder - test_encode_uniswap_v4_simple_swap bytes memory protocolData = - hex"4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec701f62849f9a0b5bf2913b396098f7c7019b51a820adac17f958d2ee523a2206206994597c13d831ec7000064000001"; + hex"4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec701dac17f958d2ee523a2206206994597c13d831ec7000064000001"; uint256 amountIn = 100 ether; deal(USDE_ADDR, address(uniswapV4Exposed), amountIn); uint256 usdeBalanceBeforePool = USDE.balanceOf(poolManager); @@ -155,9 +151,8 @@ contract UniswapV4ExecutorTest is Test, Constants { tickSpacing: int24(60) }); - bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, WBTC_ADDR, true, address(uniswapV4Exposed), pools - ); + bytes memory data = + UniswapV4Utils.encodeExactInput(USDE_ADDR, WBTC_ADDR, true, pools); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); assertEq(USDE.balanceOf(poolManager), usdeBalanceBeforePool + amountIn); @@ -175,7 +170,7 @@ contract UniswapV4ExecutorTest is Test, Constants { // Generated by the Tycho swap encoder - test_encode_uniswap_v4_sequential_swap bytes memory protocolData = - hex"4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c59901f62849f9a0b5bf2913b396098f7c7019b51a820adac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c"; + hex"4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c59901dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c"; uint256 amountIn = 100 ether; deal(USDE_ADDR, address(uniswapV4Exposed), amountIn); diff --git a/foundry/test/executors/UniswapV4Utils.sol b/foundry/test/executors/UniswapV4Utils.sol index b84bb69..67c7c7f 100644 --- a/foundry/test/executors/UniswapV4Utils.sol +++ b/foundry/test/executors/UniswapV4Utils.sol @@ -8,7 +8,6 @@ library UniswapV4Utils { address tokenIn, address tokenOut, bool zeroForOne, - address callbackExecutor, UniswapV4Executor.UniswapV4Pool[] memory pools ) public pure returns (bytes memory) { bytes memory encodedPools; @@ -22,8 +21,6 @@ library UniswapV4Utils { ); } - return abi.encodePacked( - tokenIn, tokenOut, zeroForOne, callbackExecutor, encodedPools - ); + return abi.encodePacked(tokenIn, tokenOut, zeroForOne, encodedPools); } } diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 0a4dcfc..4dc67b5 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -563,8 +563,6 @@ mod tests { "6982508145454ce325ddbe47a25d4ec3d2311933", // zero for one "00", - // executor address - "f62849f9a0b5bf2913b396098f7c7019b51a820a", // first pool intermediary token (ETH) "0000000000000000000000000000000000000000", // fee @@ -1019,9 +1017,9 @@ mod tests { let expected_swaps = String::from(concat!( // length of ple encoded swaps without padding - "000000000000000000000000000000000000000000000000000000000000008c", + "0000000000000000000000000000000000000000000000000000000000000078", // ple encoded swaps - "008a", // Swap length + "0076", // Swap length "00", // token in index "01", // token out index "000000", // split @@ -1031,7 +1029,6 @@ mod tests { "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // group token in "6982508145454ce325ddbe47a25d4ec3d2311933", // group token in "00", // zero2one - "f62849f9a0b5bf2913b396098f7c7019b51a820a", // executor address // First pool params "0000000000000000000000000000000000000000", // intermediary token (ETH) "000bb8", // fee @@ -1040,7 +1037,7 @@ mod tests { "6982508145454ce325ddbe47a25d4ec3d2311933", // intermediary token (PEPE) "0061a8", // fee "0001f4", // tick spacing - "0000000000000000000000000000000000000000" // padding + "0000000000000000" // padding )); let hex_calldata = encode(&calldata); diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index cf41e88..a4414b1 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -196,21 +196,11 @@ impl SwapEncoder for UniswapV4SwapEncoder { let group_token_out_address = bytes_to_address(&encoding_context.group_token_out)?; let zero_to_one = Self::get_zero_to_one(token_in_address, token_out_address); - let callback_executor = - bytes_to_address(&Bytes::from_str(&self.executor_address).map_err(|_| { - EncodingError::FatalError("Invalid UniswapV4 executor address".into()) - })?)?; let pool_params = (token_out_address, pool_fee_u24, pool_tick_spacing_u24).abi_encode_packed(); - let args = ( - group_token_in_address, - group_token_out_address, - zero_to_one, - callback_executor, - pool_params, - ); + let args = (group_token_in_address, group_token_out_address, zero_to_one, pool_params); Ok(args.abi_encode_packed()) } @@ -785,8 +775,6 @@ mod tests { "dac17f958d2ee523a2206206994597c13d831ec7", // zero for one "01", - // executor address - "f62849f9a0b5bf2913b396098f7c7019b51a820a", // pool params: // - intermediary token "dac17f958d2ee523a2206206994597c13d831ec7", @@ -950,8 +938,6 @@ mod tests { "2260fac5e5542a773aa44fbcfedf7c193bc2c599", // zero for one "01", - // executor address - "f62849f9a0b5bf2913b396098f7c7019b51a820a", // pool params: // - intermediary token USDT "dac17f958d2ee523a2206206994597c13d831ec7",