From d65d575003f67347110c70e2dabe6a9cc83fd712 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Thu, 20 Feb 2025 12:15:40 -0500 Subject: [PATCH] feat: Don't encode min amount for USV4 We aren't checking min amount for any other executor. This would be overkill (since we are already checking in the main router) and also inconsistent. --- foundry/src/executors/UniswapV4Executor.sol | 23 ++++++++----------- foundry/test/TychoRouter.t.sol | 4 +--- .../test/executors/UniswapV4Executor.t.sol | 11 ++------- foundry/test/executors/UniswapV4Utils.sol | 2 -- .../evm/strategy_encoder/strategy_encoders.rs | 5 ++-- .../evm/swap_encoder/swap_encoders.rs | 9 ++------ 6 files changed, 17 insertions(+), 37 deletions(-) diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index 57fe796..be069e6 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -39,7 +39,6 @@ contract UniswapV4Executor is IExecutor, V4Router { ( address tokenIn, address tokenOut, - uint256 amountOutMin, bool zeroForOne, address callbackExecutor, bytes4 callbackSelector, @@ -68,12 +67,12 @@ contract UniswapV4Executor is IExecutor, V4Router { poolKey: key, zeroForOne: zeroForOne, amountIn: uint128(amountIn), - amountOutMinimum: uint128(amountOutMin), + amountOutMinimum: uint128(0), hookData: bytes("") }) ); params[1] = abi.encode(key.currency0, amountIn); - params[2] = abi.encode(key.currency1, amountOutMin); + params[2] = abi.encode(key.currency1, uint256(0)); swapData = abi.encode(actions, params); } else { PathKey[] memory path = new PathKey[](pools.length); @@ -101,11 +100,11 @@ contract UniswapV4Executor is IExecutor, V4Router { currencyIn: currencyIn, path: path, amountIn: uint128(amountIn), - amountOutMinimum: uint128(amountOutMin) + amountOutMinimum: uint128(0) }) ); params[1] = abi.encode(currencyIn, amountIn); - params[2] = abi.encode(Currency.wrap(tokenOut), amountOutMin); + params[2] = abi.encode(Currency.wrap(tokenOut), uint256(0)); swapData = abi.encode(actions, params); } bytes memory fullData = @@ -141,27 +140,25 @@ contract UniswapV4Executor is IExecutor, V4Router { returns ( address tokenIn, address tokenOut, - uint256 amountOutMin, bool zeroForOne, address callbackExecutor, bytes4 callbackSelector, UniswapV4Pool[] memory pools ) { - if (data.length < 123) { + if (data.length < 91) { revert UniswapV4Executor__InvalidDataLength(); } tokenIn = address(bytes20(data[0:20])); tokenOut = address(bytes20(data[20:40])); - amountOutMin = uint256(bytes32(data[40:72])); - zeroForOne = (data[72] != 0); - callbackExecutor = address(bytes20(data[73:93])); - callbackSelector = bytes4(data[93:97]); + zeroForOne = (data[40] != 0); + callbackExecutor = address(bytes20(data[41:61])); + callbackSelector = bytes4(data[61:65]); - uint256 poolsLength = (data.length - 97) / 26; // 26 bytes per pool object + uint256 poolsLength = (data.length - 65) / 26; // 26 bytes per pool object pools = new UniswapV4Pool[](poolsLength); - bytes memory poolsData = data[97:]; + bytes memory poolsData = data[65:]; 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 75417a2..e31f082 100644 --- a/foundry/test/TychoRouter.t.sol +++ b/foundry/test/TychoRouter.t.sol @@ -753,7 +753,7 @@ contract TychoRouterTest is TychoRouterTestSetup { // `5c2f5a71f67c01775180adc06909288b4c329308` with the one in this test // `f62849f9a0b5bf2913b396098f7c7019b51a820a` (bool success,) = tychoRouterAddr.call( - hex"d499aa88000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000067ddee9e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067b668a6000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041bdf91011918dcb5f59ab3588212a035c770a2839fe2c19060491370fa89685b8469def9e83c7b9cf8f0ef5088a3179556a6ba1096cefbe83c09a1182981c93e41c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b400b20001000000f62849f9a0b5bf2913b396098f7c7019b51a820abd0625aba0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a91dd73460000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f4000000000000000000000000" + hex"d499aa88000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000067ddee9e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067b668a6000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041bdf91011918dcb5f59ab3588212a035c770a2839fe2c19060491370fa89685b8469def9e83c7b9cf8f0ef5088a3179556a6ba1096cefbe83c09a1182981c93e41c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009400920001000000f62849f9a0b5bf2913b396098f7c7019b51a820abd0625aba0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d231193300f62849f9a0b5bf2913b396098f7c7019b51a820a91dd73460000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f4000000000000000000000000" ); vm.stopPrank(); @@ -924,7 +924,6 @@ contract TychoRouterTest is TychoRouterTestSetup { bytes memory protocolData = UniswapV4Utils.encodeExactInput( USDE_ADDR, USDT_ADDR, - uint256(1), true, address(usv4Executor), SafeCallback.unlockCallback.selector, @@ -970,7 +969,6 @@ contract TychoRouterTest is TychoRouterTestSetup { bytes memory protocolData = UniswapV4Utils.encodeExactInput( USDE_ADDR, WBTC_ADDR, - uint256(1), true, address(usv4Executor), SafeCallback.unlockCallback.selector, diff --git a/foundry/test/executors/UniswapV4Executor.t.sol b/foundry/test/executors/UniswapV4Executor.t.sol index c4b1845..c4d0787 100644 --- a/foundry/test/executors/UniswapV4Executor.t.sol +++ b/foundry/test/executors/UniswapV4Executor.t.sol @@ -17,7 +17,6 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor { returns ( address tokenIn, address tokenOut, - uint256 amountOutMin, bool zeroForOne, address callbackExecutor, bytes4 callbackSelector, @@ -44,7 +43,6 @@ contract UniswapV4ExecutorTest is Test, Constants { } function testDecodeParams() public view { - uint256 minAmountOut = 100; bool zeroForOne = true; uint24 pool1Fee = 500; int24 tickSpacing1 = 60; @@ -67,7 +65,6 @@ contract UniswapV4ExecutorTest is Test, Constants { bytes memory data = UniswapV4Utils.encodeExactInput( USDE_ADDR, USDT_ADDR, - minAmountOut, zeroForOne, address(uniswapV4Exposed), SafeCallback.unlockCallback.selector, @@ -77,7 +74,6 @@ contract UniswapV4ExecutorTest is Test, Constants { ( address tokenIn, address tokenOut, - uint256 amountOutMin, bool zeroForOneDecoded, address callbackExecutor, bytes4 callbackSelector, @@ -86,7 +82,6 @@ contract UniswapV4ExecutorTest is Test, Constants { assertEq(tokenIn, USDE_ADDR); assertEq(tokenOut, USDT_ADDR); - assertEq(amountOutMin, minAmountOut); assertEq(zeroForOneDecoded, zeroForOne); assertEq(callbackExecutor, address(uniswapV4Exposed)); assertEq(callbackSelector, SafeCallback.unlockCallback.selector); @@ -117,7 +112,6 @@ contract UniswapV4ExecutorTest is Test, Constants { bytes memory data = UniswapV4Utils.encodeExactInput( USDE_ADDR, USDT_ADDR, - uint256(1), true, address(uniswapV4Exposed), SafeCallback.unlockCallback.selector, @@ -137,7 +131,7 @@ contract UniswapV4ExecutorTest is Test, Constants { // USDE -> USDT // Generated by the Tycho swap encoder - test_encode_uniswap_v4_simple_swap bytes memory protocolData = - hex"4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000000000001015615deb798bb3e4dfa0139dfa1b3d433cc23b72f91dd7346dac17f958d2ee523a2206206994597c13d831ec7000064000001"; + hex"4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec701f62849f9a0b5bf2913b396098f7c7019b51a820a91dd7346dac17f958d2ee523a2206206994597c13d831ec7000064000001"; uint256 amountIn = 100 ether; deal(USDE_ADDR, address(uniswapV4Exposed), amountIn); @@ -178,7 +172,6 @@ contract UniswapV4ExecutorTest is Test, Constants { bytes memory data = UniswapV4Utils.encodeExactInput( USDE_ADDR, WBTC_ADDR, - uint256(1), true, address(uniswapV4Exposed), SafeCallback.unlockCallback.selector, @@ -200,7 +193,7 @@ contract UniswapV4ExecutorTest is Test, Constants { // USDE -> USDT -> WBTC // Generated by the Tycho swap encoder - test_encode_uniswap_v4_sequential_swap bytes memory protocolData = - hex"4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990000000000000000000000000000000000000000000000000000000000000001015615deb798bb3e4dfa0139dfa1b3d433cc23b72f91dd7346dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c"; + hex"4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c59901f62849f9a0b5bf2913b396098f7c7019b51a820a91dd7346dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c"; 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 ffa0b21..272d319 100644 --- a/foundry/test/executors/UniswapV4Utils.sol +++ b/foundry/test/executors/UniswapV4Utils.sol @@ -7,7 +7,6 @@ library UniswapV4Utils { function encodeExactInput( address tokenIn, address tokenOut, - uint256 amountOutMin, bool zeroForOne, address callbackExecutor, bytes4 callbackSelector, @@ -27,7 +26,6 @@ library UniswapV4Utils { return abi.encodePacked( tokenIn, tokenOut, - amountOutMin, zeroForOne, callbackExecutor, bytes4(callbackSelector), diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 71f5029..f5d4e9a 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -981,9 +981,9 @@ mod tests { let expected_swaps = String::from(concat!( // length of ple encoded swaps without padding - "00000000000000000000000000000000000000000000000000000000000000b4", + "0000000000000000000000000000000000000000000000000000000000000094", // ple encoded swaps - "00b2", // Swap length + "0092", // Swap length "00", // token in index "01", // token out index "000000", // split @@ -993,7 +993,6 @@ mod tests { // Protocol data "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // group token in "6982508145454ce325ddbe47a25d4ec3d2311933", // group token in - "0000000000000000000000000000000000000000000000000000000000000000", // amount out min "00", // zero2one "f62849f9a0b5bf2913b396098f7c7019b51a820a", // executor address "91dd7346", // callback selector diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index fb4b6e6..0d7678e 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use alloy_primitives::{Address, Bytes as AlloyBytes, U256}; +use alloy_primitives::{Address, Bytes as AlloyBytes}; use alloy_sol_types::SolValue; use tycho_core::Bytes; @@ -192,7 +192,6 @@ impl SwapEncoder for UniswapV4SwapEncoder { let group_token_in_address = bytes_to_address(&encoding_context.group_token_in)?; let group_token_out_address = bytes_to_address(&encoding_context.group_token_out)?; - let amount_out_min = U256::from(0); 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(|_| { @@ -205,7 +204,6 @@ impl SwapEncoder for UniswapV4SwapEncoder { let args = ( group_token_in_address, group_token_out_address, - amount_out_min, zero_to_one, callback_executor, encode_function_selector(&self.callback_selector), @@ -481,6 +479,7 @@ mod tests { .unwrap(); let hex_swap = encode(&encoded_swap); + println!("{}", hex_swap); assert_eq!( hex_swap, String::from(concat!( @@ -488,8 +487,6 @@ mod tests { "4c9edd5852cd905f086c759e8383e09bff1e68b3", // group token out "dac17f958d2ee523a2206206994597c13d831ec7", - // amount out min - "0000000000000000000000000000000000000000000000000000000000000000", // zero for one "01", // executor address @@ -649,8 +646,6 @@ mod tests { "4c9edd5852cd905f086c759e8383e09bff1e68b3", // group_token out "2260fac5e5542a773aa44fbcfedf7c193bc2c599", - // amount out min - "0000000000000000000000000000000000000000000000000000000000000000", // zero for one "01", // executor address