From 9bcb58e5aa4e0d9b8483245da133951b39838e5b Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 15 Apr 2025 12:26:28 +0100 Subject: [PATCH 1/5] feat: Support out transfer straight to the receiver - The out transfer is now a responsibility of the Executors -> remove this from router methods - Also adding a check that the receiver got the full amount out - In encoding, if it is the last swap, pass the receiver as the trade receiver and not the router address (fix encoding tests) - Fixed some solidity tests (after rebasing with a PR that is still open, I will fix them all) TODO: Adapt curve and uniswap v4 to support this --- don't change below this line --- ENG-4315 Took 3 hours 7 minutes Took 20 minutes Took 59 seconds Took 7 minutes --- foundry/src/TychoRouter.sol | 57 ++++++---- foundry/test/TychoRouterSequentialSwap.t.sol | 18 +-- foundry/test/TychoRouterSingleSwap.t.sol | 42 +++---- foundry/test/TychoRouterSplitSwap.t.sol | 23 ++-- .../evm/strategy_encoder/strategy_encoders.rs | 103 +++++++++++++----- 5 files changed, 139 insertions(+), 104 deletions(-) diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 1b693fd..a01fdba 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -58,6 +58,9 @@ import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; error TychoRouter__AddressZero(); error TychoRouter__EmptySwaps(); error TychoRouter__NegativeSlippage(uint256 amount, uint256 minAmount); +error TychoRouter__AmountOutNotFullyReceived( + uint256 amountIn, uint256 amountConsumed +); error TychoRouter__MessageValueMismatch(uint256 value, uint256 amount); error TychoRouter__InvalidDataLength(); error TychoRouter__UndefinedMinAmountOut(); @@ -408,9 +411,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { address receiver, bytes calldata swaps ) internal returns (uint256 amountOut) { - if (receiver == address(0)) { - revert TychoRouter__AddressZero(); - } if (minAmountOut == 0) { revert TychoRouter__UndefinedMinAmountOut(); } @@ -420,6 +420,8 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { _wrapETH(amountIn); tokenIn = address(_weth); } + + uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); amountOut = _splitSwap(amountIn, nTokens, swaps); if (amountOut < minAmountOut) { @@ -428,11 +430,13 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { if (unwrapEth) { _unwrapETH(amountOut); - } - if (tokenOut == address(0)) { Address.sendValue(payable(receiver), amountOut); - } else { - IERC20(tokenOut).safeTransfer(receiver, amountOut); + } + + uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver); + uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut; + if (userAmount != amountOut) { + revert TychoRouter__AmountOutNotFullyReceived(userAmount, amountOut); } } @@ -454,9 +458,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { address receiver, bytes calldata swap_ ) internal returns (uint256 amountOut) { - if (receiver == address(0)) { - revert TychoRouter__AddressZero(); - } if (minAmountOut == 0) { revert TychoRouter__UndefinedMinAmountOut(); } @@ -470,6 +471,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { (address executor, bytes calldata protocolData) = swap_.decodeSingleSwap(); + uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); amountOut = _callExecutor(executor, amountIn, protocolData); if (amountOut < minAmountOut) { @@ -478,11 +480,14 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { if (unwrapEth) { _unwrapETH(amountOut); - } - if (tokenOut == address(0)) { Address.sendValue(payable(receiver), amountOut); - } else { - IERC20(tokenOut).safeTransfer(receiver, amountOut); + } + + uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver); + uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut; + + if (userAmount != amountOut) { + revert TychoRouter__AmountOutNotFullyReceived(userAmount, amountOut); } } @@ -504,9 +509,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { address receiver, bytes calldata swaps ) internal returns (uint256 amountOut) { - if (receiver == address(0)) { - revert TychoRouter__AddressZero(); - } if (minAmountOut == 0) { revert TychoRouter__UndefinedMinAmountOut(); } @@ -517,7 +519,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { tokenIn = address(_weth); } + uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); amountOut = _sequentialSwap(amountIn, swaps); + uint256 currentBalanceTokenIn = _balanceOf(tokenIn, address(this)); if (amountOut < minAmountOut) { revert TychoRouter__NegativeSlippage(amountOut, minAmountOut); @@ -525,11 +529,13 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { if (unwrapEth) { _unwrapETH(amountOut); - } - if (tokenOut == address(0)) { Address.sendValue(payable(receiver), amountOut); - } else { - IERC20(tokenOut).safeTransfer(receiver, amountOut); + } + uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver); + uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut; + + if (userAmount != amountOut) { + revert TychoRouter__AmountOutNotFullyReceived(userAmount, amountOut); } } @@ -764,4 +770,13 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { _handleCallback(data); return ""; } + + function _balanceOf(address token, address owner) + internal + view + returns (uint256) + { + return + token == address(0) ? owner.balance : IERC20(token).balanceOf(owner); + } } diff --git a/foundry/test/TychoRouterSequentialSwap.t.sol b/foundry/test/TychoRouterSequentialSwap.t.sol index 9efd39b..d72d93e 100644 --- a/foundry/test/TychoRouterSequentialSwap.t.sol +++ b/foundry/test/TychoRouterSequentialSwap.t.sol @@ -36,7 +36,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { encodeUniswapV2Swap( DAI_ADDR, DAI_USDC_POOL, - tychoRouterAddr, + ALICE, true, TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL ) @@ -44,22 +44,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { return swaps; } - function testSequentialSwapInternalMethod() public { - // Trade 1 WETH for USDC through DAI - see _getSequentialSwaps for more info - uint256 amountIn = 1 ether; - deal(WETH_ADDR, ALICE, amountIn); - vm.startPrank(ALICE); - IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn); - - bytes[] memory swaps = _getSequentialSwaps(false); - tychoRouter.exposedSequentialSwap(amountIn, pleEncode(swaps)); - vm.stopPrank(); - - uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(tychoRouterAddr); - assertEq(usdcBalance, 2644659787); - assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0); - } - function testSequentialSwapPermit2() public { // Trade 1 WETH for USDC through DAI - see _getSequentialSwaps for more info uint256 amountIn = 1 ether; diff --git a/foundry/test/TychoRouterSingleSwap.t.sol b/foundry/test/TychoRouterSingleSwap.t.sol index 8a8a4d3..aa56efb 100644 --- a/foundry/test/TychoRouterSingleSwap.t.sol +++ b/foundry/test/TychoRouterSingleSwap.t.sol @@ -21,11 +21,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { bytes memory signature ) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn); - bytes memory protocolData = encodeUniswapV2Swap( - WETH_ADDR, + bytes memory protocolData = + encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, - tychoRouterAddr, - false, + ALICE, false, TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL ); @@ -62,11 +61,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { // Approve the tokenIn to be transferred to the router IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes memory protocolData = encodeUniswapV2Swap( - WETH_ADDR, + bytes memory protocolData = + encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, - tychoRouterAddr, - false, + ALICE, false, TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL ); @@ -103,11 +101,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes memory protocolData = encodeUniswapV2Swap( - WETH_ADDR, + bytes memory protocolData = + encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, - tychoRouterAddr, - false, + ALICE, false, TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL ); @@ -129,11 +126,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn - 1); - bytes memory protocolData = encodeUniswapV2Swap( - WETH_ADDR, + bytes memory protocolData = + encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, - tychoRouterAddr, - false, + ALICE, false, TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL ); @@ -164,11 +160,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { // Approve the tokenIn to be transferred to the router IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes memory protocolData = encodeUniswapV2Swap( - WETH_ADDR, + bytes memory protocolData = + encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, - tychoRouterAddr, - false, + ALICE, false, TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL ); @@ -213,11 +208,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { sigDeadline: 0 }); - bytes memory protocolData = encodeUniswapV2Swap( - WETH_ADDR, + bytes memory protocolData = + encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, - tychoRouterAddr, - false, + ALICE, false, TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL ); diff --git a/foundry/test/TychoRouterSplitSwap.t.sol b/foundry/test/TychoRouterSplitSwap.t.sol index 00f8406..255c76b 100644 --- a/foundry/test/TychoRouterSplitSwap.t.sol +++ b/foundry/test/TychoRouterSplitSwap.t.sol @@ -44,11 +44,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint8(2), uint24(0), address(usv2Executor), - encodeUniswapV2Swap( - WBTC_ADDR, - USDC_WBTC_POOL, - tychoRouterAddr, - true, + encodeUniswapV2Swap(WBTC_ADDR, USDC_WBTC_POOL, ALICE, true, TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL ) ); @@ -72,7 +68,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { encodeUniswapV2Swap( DAI_ADDR, DAI_USDC_POOL, - tychoRouterAddr, + ALICE, true, TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL ) @@ -92,7 +88,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouter.exposedSplitSwap(amountIn, 4, pleEncode(swaps)); vm.stopPrank(); - uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(tychoRouterAddr); + uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(ALICE); assertEq(usdcBalance, 2615491639); assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0); } @@ -136,7 +132,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { deal(WETH_ADDR, ALICE, amountIn); vm.startPrank(ALICE); - IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); + IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn); bytes[] memory swaps = _getSplitSwaps(false); @@ -154,7 +150,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(ALICE); assertEq(usdcBalance, 2615491639); - assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0); + assertEq(IERC20(WETH_ADDR).balanceOf(ALICE), 0); } function testSplitSwapUndefinedMinAmount() public { @@ -265,11 +261,10 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { spender: address(0), sigDeadline: 0 }); - bytes memory protocolData = encodeUniswapV2Swap( - WETH_ADDR, + bytes memory protocolData = + encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, - tychoRouterAddr, - false, + ALICE, false, TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL ); @@ -367,7 +362,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { bytes memory protocolData = encodeUniswapV3Swap( WETH_ADDR, DAI_ADDR, - tychoRouterAddr, + ALICE, DAI_WETH_USV3, zeroForOne, TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 2536812..4a34850 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -111,16 +111,19 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { NativeAction::Unwrap => unwrap = true, } } - + let protocol = grouped_swap.protocol_system.clone(); let swap_encoder = self - .get_swap_encoder(&grouped_swap.protocol_system) + .get_swap_encoder(&protocol) .ok_or_else(|| { EncodingError::InvalidInput(format!( "Swap encoder not found for protocol: {}", - grouped_swap.protocol_system + protocol )) })?; + let receiver = + if !unwrap { solution.receiver.clone() } else { self.router_address.clone() }; + let mut grouped_protocol_data: Vec = vec![]; for swap in grouped_swap.swaps.iter() { let transfer_type = self.get_transfer_type( @@ -133,7 +136,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { ); let encoding_context = EncodingContext { - receiver: self.router_address.clone(), + receiver: receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.input_token.clone(), @@ -286,16 +289,23 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { } let mut swaps = vec![]; - for grouped_swap in grouped_swaps.iter() { + for (i, grouped_swap) in grouped_swaps.iter().enumerate() { + let protocol = grouped_swap.protocol_system.clone(); let swap_encoder = self - .get_swap_encoder(&grouped_swap.protocol_system) + .get_swap_encoder(&protocol) .ok_or_else(|| { EncodingError::InvalidInput(format!( "Swap encoder not found for protocol: {}", - grouped_swap.protocol_system + protocol )) })?; + let receiver = if i == grouped_swaps.len() - 1 && !unwrap { + solution.receiver.clone() + } else { + self.router_address.clone() + }; + let mut grouped_protocol_data: Vec = vec![]; for swap in grouped_swap.swaps.iter() { let transfer_type = self.get_transfer_type( @@ -308,7 +318,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { ); let encoding_context = EncodingContext { - receiver: self.router_address.clone(), + receiver: receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.input_token.clone(), @@ -516,15 +526,22 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { let mut swaps = vec![]; for grouped_swap in grouped_swaps.iter() { + let protocol = grouped_swap.protocol_system.clone(); let swap_encoder = self - .get_swap_encoder(&grouped_swap.protocol_system) + .get_swap_encoder(&protocol) .ok_or_else(|| { EncodingError::InvalidInput(format!( "Swap encoder not found for protocol: {}", - grouped_swap.protocol_system + protocol )) })?; + let receiver = if !wrap && grouped_swap.output_token == solution.checked_token { + solution.receiver.clone() + } else { + self.router_address.clone() + }; + let mut grouped_protocol_data: Vec = vec![]; for swap in grouped_swap.swaps.iter() { let transfer_type = self.get_transfer_type( @@ -537,7 +554,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { ); let encoding_context = EncodingContext { - receiver: self.router_address.clone(), + receiver: receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.input_token.clone(), @@ -766,7 +783,7 @@ mod tests { "5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id - "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one "02", // transfer type "00000000000000", // padding @@ -869,7 +886,7 @@ mod tests { "5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id - "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one "02", // transfer type "0000000000000000000000000000", // padding @@ -1197,9 +1214,6 @@ mod tests { #[test] fn test_sequential_swap_strategy_encoder_no_permit2() { - // Note: This test does not assert anything. It is only used to obtain integration test - // data for our router solidity test. - // // Performs a split swap from WETH to USDC though WBTC and DAI using USV2 pools // // WETH ───(USV2)──> WBTC ───(USV2)──> USDC @@ -1253,8 +1267,41 @@ mod tests { .encode_strategy(solution) .unwrap(); - let _hex_calldata = encode(&calldata); - println!("{}", _hex_calldata); + let hex_calldata = encode(&calldata); + println!("{}", hex_calldata); + + let expected = String::from(concat!( + "e8a980d7", /* function selector */ + "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in + "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in + "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token ou + "00000000000000000000000000000000000000000000000000000000018f61ec", // min amount out + "0000000000000000000000000000000000000000000000000000000000000000", // wrap + "0000000000000000000000000000000000000000000000000000000000000000", // unwrap + "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver + "0000000000000000000000000000000000000000000000000000000000000100", /* length ple + * encode */ + "00000000000000000000000000000000000000000000000000000000000000a8", + // swap 1 + "0052", // swap length + "5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address + "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in + "bb2b8038a1640196fbe3e38816f3e67cba72d940", // component id + "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver (router) + "00", // zero to one + "00", // transfer type + // swap 2 + "0052", // swap length + "5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address + "2260fac5e5542a773aa44fbcfedf7c193bc2c599", // token in + "004375dff511095cc5a197a54140a24efef3a416", // component id + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver (final user) + "01", // zero to one + "00", // transfer type + "000000000000000000000000000000000000000000000000", // padding + )); + + assert_eq!(hex_calldata, expected); } #[test] @@ -1529,7 +1576,7 @@ mod tests { "5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id - "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one "01", // transfer type "0000000000000000000000000000", // padding @@ -1612,7 +1659,7 @@ mod tests { "5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id - "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one "01", // transfer type "00000000000000", // padding @@ -1863,7 +1910,7 @@ mod tests { "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token out "0001f4", // pool fee - "3ede3eca2a72b3aecc820e955b36f38437d01395", // router address + "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id "01", // zero2one "02", // transfer type @@ -1874,7 +1921,7 @@ mod tests { "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token out "000bb8", // pool fee - "3ede3eca2a72b3aecc820e955b36f38437d01395", // router address + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id "00", // zero2one "00", // transfer type @@ -2017,7 +2064,7 @@ mod tests { "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token out "0001f4", // pool fee - "3ede3eca2a72b3aecc820e955b36f38437d01395", // router address + "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id "01", // zero2one "02", // transfer type @@ -2029,7 +2076,7 @@ mod tests { "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token out "000bb8", // pool fee - "3ede3eca2a72b3aecc820e955b36f38437d01395", // router address + "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id "01", // zero2one "02", // transfer type @@ -2040,7 +2087,7 @@ mod tests { "5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address, "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id, - "3ede3eca2a72b3aecc820e955b36f38437d01395", // router address + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one "00", // transfer type "00000000000000" // padding @@ -2178,7 +2225,7 @@ mod tests { "5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in "b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id - "3ede3eca2a72b3aecc820e955b36f38437d01395", // router address + "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "01", // zero2one "02", // transfer type "006e", // ple encoded swaps @@ -2189,7 +2236,7 @@ mod tests { "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token out "0001f4", // pool fee - "3ede3eca2a72b3aecc820e955b36f38437d01395", // router address + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id "00", // zero2one "00", // transfer type @@ -2201,7 +2248,7 @@ mod tests { "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token out "000bb8", // pool fee - "3ede3eca2a72b3aecc820e955b36f38437d01395", // router address + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id "00", // zero2one "00", // transfer type From 328a281a44e033a72e7bb8991f689c736718f098 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 15 Apr 2025 13:03:25 +0100 Subject: [PATCH 2/5] feat: Add transfer out for Curve Add transfer in Executor and pass receiver address in encoding Remove integration test with StETH pool because we don't support it at simulation level and there is something weird with the amounts (that it is not worth it to investigate now) --- don't change below this line --- ENG-4315 Took 34 minutes Took 2 minutes --- foundry/src/executors/CurveExecutor.sol | 18 ++- foundry/test/TychoRouterIntegration.t.sol | 15 --- foundry/test/executors/CurveExecutor.t.sol | 113 +++++++----------- .../evm/swap_encoder/swap_encoders.rs | 7 ++ 4 files changed, 67 insertions(+), 86 deletions(-) diff --git a/foundry/src/executors/CurveExecutor.sol b/foundry/src/executors/CurveExecutor.sol index 933077e..8f893a0 100644 --- a/foundry/src/executors/CurveExecutor.sol +++ b/foundry/src/executors/CurveExecutor.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.26; import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./TokenTransfer.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; error CurveExecutor__AddressZero(); error CurveExecutor__InvalidDataLength(); @@ -64,7 +65,8 @@ contract CurveExecutor is IExecutor, TokenTransfer { int128 i, int128 j, bool tokenApprovalNeeded, - TransferType transferType + TransferType transferType, + address receiver ) = _decodeData(data); _transfer( @@ -109,7 +111,16 @@ contract CurveExecutor is IExecutor, TokenTransfer { } uint256 balanceAfter = _balanceOf(tokenOut); - return balanceAfter - balanceBefore; + uint256 amountOut = balanceAfter - balanceBefore; + + if (receiver != address(this)) { + if (tokenOut == nativeToken) { + Address.sendValue(payable(receiver), amountOut); + } else { + IERC20(tokenOut).safeTransfer(receiver, amountOut); + } + } + return amountOut; } function _decodeData(bytes calldata data) @@ -123,7 +134,7 @@ contract CurveExecutor is IExecutor, TokenTransfer { int128 i, int128 j, bool tokenApprovalNeeded, - TransferType transferType + address receiver ) { tokenIn = address(bytes20(data[0:20])); @@ -134,6 +145,7 @@ contract CurveExecutor is IExecutor, TokenTransfer { j = int128(uint128(uint8(data[62]))); tokenApprovalNeeded = data[63] != 0; transferType = TransferType(uint8(data[64])); + receiver = address(bytes20(data[65:85])); } receive() external payable { diff --git a/foundry/test/TychoRouterIntegration.t.sol b/foundry/test/TychoRouterIntegration.t.sol index 053c780..df57ab0 100644 --- a/foundry/test/TychoRouterIntegration.t.sol +++ b/foundry/test/TychoRouterIntegration.t.sol @@ -312,19 +312,4 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { vm.stopPrank(); } - - function testSplitCurveIntegrationStETH() public { - deal(ALICE, 1 ether); - - vm.startPrank(ALICE); - // Encoded solution generated using `test_split_encoding_strategy_curve_st_eth` - (bool success,) = tychoRouterAddr.call{value: 1 ether}( - hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe840000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000005c005a00010000001d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f67022010001000500000000" - ); - - assertTrue(success, "Call Failed"); - assertEq(IERC20(STETH_ADDR).balanceOf(ALICE), 1000754689941529590); - - vm.stopPrank(); - } } diff --git a/foundry/test/executors/CurveExecutor.t.sol b/foundry/test/executors/CurveExecutor.t.sol index a49a2dc..278413c 100644 --- a/foundry/test/executors/CurveExecutor.t.sol +++ b/foundry/test/executors/CurveExecutor.t.sol @@ -37,7 +37,8 @@ contract CurveExecutorExposed is CurveExecutor { int128 i, int128 j, bool tokenApprovalNeeded, - TokenTransfer.TransferType transferType + TokenTransfer.TransferType transferType, + address receiver ) { return _decodeData(data); @@ -67,7 +68,8 @@ contract CurveExecutorTest is Test, Constants { uint8(2), uint8(0), true, - TokenTransfer.TransferType.NONE + TokenTransfer.TransferType.NONE, + ALICE ); ( @@ -78,7 +80,8 @@ contract CurveExecutorTest is Test, Constants { int128 i, int128 j, bool tokenApprovalNeeded, - TokenTransfer.TransferType transferType + TokenTransfer.TransferType transferType, + address receiver ) = curveExecutorExposed.decodeData(data); assertEq(tokenIn, WETH_ADDR); @@ -89,6 +92,7 @@ contract CurveExecutorTest is Test, Constants { assertEq(j, 0); assertEq(tokenApprovalNeeded, true); assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE)); + assertEq(receiver, ALICE); } function testTriPool() public { @@ -96,15 +100,12 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(DAI_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = _getData(DAI_ADDR, USDC_ADDR, TRIPOOL, 1); + bytes memory data = _getData(DAI_ADDR, USDC_ADDR, TRIPOOL, 1, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 999797); - assertEq( - IERC20(USDC_ADDR).balanceOf(address(curveExecutorExposed)), - amountOut - ); + assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), amountOut); } function testStEthPool() public { @@ -113,14 +114,14 @@ contract CurveExecutorTest is Test, Constants { deal(address(curveExecutorExposed), amountIn); bytes memory data = - _getData(ETH_ADDR_FOR_CURVE, STETH_ADDR, STETH_POOL, 1); + _getData(ETH_ADDR_FOR_CURVE, STETH_ADDR, STETH_POOL, 1, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 1001072414418410897); assertEq( - IERC20(STETH_ADDR).balanceOf(address(curveExecutorExposed)), - amountOut + IERC20(STETH_ADDR).balanceOf(ALICE), + amountOut - 1 // there is something weird in this pool, but won't investigate for now because we don't currently support it in the simulation ); } @@ -129,15 +130,13 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(WETH_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = _getData(WETH_ADDR, WBTC_ADDR, TRICRYPTO2_POOL, 3); + bytes memory data = + _getData(WETH_ADDR, WBTC_ADDR, TRICRYPTO2_POOL, 3, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 2279618); - assertEq( - IERC20(WBTC_ADDR).balanceOf(address(curveExecutorExposed)), - amountOut - ); + assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), amountOut); } function testSUSDPool() public { @@ -145,15 +144,12 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 100 * 10 ** 6; deal(USDC_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = _getData(USDC_ADDR, SUSD_ADDR, SUSD_POOL, 1); + bytes memory data = _getData(USDC_ADDR, SUSD_ADDR, SUSD_POOL, 1, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 100488101605550214590); - assertEq( - IERC20(SUSD_ADDR).balanceOf(address(curveExecutorExposed)), - amountOut - ); + assertEq(IERC20(SUSD_ADDR).balanceOf(ALICE), amountOut); } function testFraxUsdcPool() public { @@ -161,15 +157,13 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(FRAX_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = _getData(FRAX_ADDR, USDC_ADDR, FRAX_USDC_POOL, 1); + bytes memory data = + _getData(FRAX_ADDR, USDC_ADDR, FRAX_USDC_POOL, 1, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 998097); - assertEq( - IERC20(USDC_ADDR).balanceOf(address(curveExecutorExposed)), - amountOut - ); + assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), amountOut); } function testUsdeUsdcPool() public { @@ -177,15 +171,13 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 100 * 10 ** 6; deal(USDC_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = _getData(USDC_ADDR, USDE_ADDR, USDE_USDC_POOL, 1); + bytes memory data = + _getData(USDC_ADDR, USDE_ADDR, USDE_USDC_POOL, 1, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 100064812138999986170); - assertEq( - IERC20(USDE_ADDR).balanceOf(address(curveExecutorExposed)), - amountOut - ); + assertEq(IERC20(USDE_ADDR).balanceOf(ALICE), amountOut); } function testDolaFraxPyusdPool() public { @@ -194,32 +186,27 @@ contract CurveExecutorTest is Test, Constants { deal(DOLA_ADDR, address(curveExecutorExposed), amountIn); bytes memory data = - _getData(DOLA_ADDR, FRAXPYUSD_POOL, DOLA_FRAXPYUSD_POOL, 1); + _getData(DOLA_ADDR, FRAXPYUSD_POOL, DOLA_FRAXPYUSD_POOL, 1, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 99688992); - assertEq( - IERC20(FRAXPYUSD_POOL).balanceOf(address(curveExecutorExposed)), - amountOut - ); + assertEq(IERC20(FRAXPYUSD_POOL).balanceOf(ALICE), amountOut); } function testCryptoPoolWithETH() public { // Swapping XYO -> ETH on a CryptoPool, deployed by factory 0xF18056Bbd320E96A48e3Fbf8bC061322531aac99 uint256 amountIn = 1 ether; - uint256 initialBalance = address(curveExecutorExposed).balance; // this address already has some ETH assigned to it + uint256 initialBalance = address(ALICE).balance; // this address already has some ETH assigned to it deal(XYO_ADDR, address(curveExecutorExposed), amountIn); bytes memory data = - _getData(XYO_ADDR, ETH_ADDR_FOR_CURVE, ETH_XYO_POOL, 2); + _getData(XYO_ADDR, ETH_ADDR_FOR_CURVE, ETH_XYO_POOL, 2, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 6081816039338); - assertEq( - address(curveExecutorExposed).balance, initialBalance + amountOut - ); + assertEq(ALICE.balance, initialBalance + amountOut); } function testCryptoPool() public { @@ -227,15 +214,13 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1000 ether; deal(BSGG_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = _getData(BSGG_ADDR, USDT_ADDR, BSGG_USDT_POOL, 2); + bytes memory data = + _getData(BSGG_ADDR, USDT_ADDR, BSGG_USDT_POOL, 2, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 23429); - assertEq( - IERC20(USDT_ADDR).balanceOf(address(curveExecutorExposed)), - amountOut - ); + assertEq(IERC20(USDT_ADDR).balanceOf(ALICE), amountOut); } function testTricryptoPool() public { @@ -243,15 +228,13 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(WETH_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = _getData(WETH_ADDR, USDC_ADDR, TRICRYPTO_POOL, 2); + bytes memory data = + _getData(WETH_ADDR, USDC_ADDR, TRICRYPTO_POOL, 2, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 1861130974); - assertEq( - IERC20(USDC_ADDR).balanceOf(address(curveExecutorExposed)), - amountOut - ); + assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), amountOut); } function testTwoCryptoPool() public { @@ -259,15 +242,13 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(UWU_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = _getData(UWU_ADDR, WETH_ADDR, UWU_WETH_POOL, 2); + bytes memory data = + _getData(UWU_ADDR, WETH_ADDR, UWU_WETH_POOL, 2, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 2873786684675); - assertEq( - IERC20(WETH_ADDR).balanceOf(address(curveExecutorExposed)), - amountOut - ); + assertEq(IERC20(WETH_ADDR).balanceOf(ALICE), amountOut); } function testStableSwapPool() public { @@ -276,15 +257,12 @@ contract CurveExecutorTest is Test, Constants { deal(CRVUSD_ADDR, address(curveExecutorExposed), amountIn); bytes memory data = - _getData(CRVUSD_ADDR, USDT_ADDR, CRVUSD_USDT_POOL, 1); + _getData(CRVUSD_ADDR, USDT_ADDR, CRVUSD_USDT_POOL, 1, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 999910); - assertEq( - IERC20(USDT_ADDR).balanceOf(address(curveExecutorExposed)), - amountOut - ); + assertEq(IERC20(USDT_ADDR).balanceOf(ALICE), amountOut); } function testMetaPool() public { @@ -293,22 +271,20 @@ contract CurveExecutorTest is Test, Constants { deal(WTAO_ADDR, address(curveExecutorExposed), amountIn); bytes memory data = - _getData(WTAO_ADDR, WSTTAO_ADDR, WSTTAO_WTAO_POOL, 1); + _getData(WTAO_ADDR, WSTTAO_ADDR, WSTTAO_WTAO_POOL, 1, ALICE); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); assertEq(amountOut, 32797923610); - assertEq( - IERC20(WSTTAO_ADDR).balanceOf(address(curveExecutorExposed)), - amountOut - ); + assertEq(IERC20(WSTTAO_ADDR).balanceOf(ALICE), amountOut); } function _getData( address tokenIn, address tokenOut, address pool, - uint8 poolType + uint8 poolType, + address receiver ) internal view returns (bytes memory data) { (int128 i, int128 j) = _getIndexes(tokenIn, tokenOut, pool); data = abi.encodePacked( @@ -319,7 +295,8 @@ contract CurveExecutorTest is Test, Constants { uint8(uint256(uint128(i))), uint8(uint256(uint128(j))), true, - TokenTransfer.TransferType.NONE + TokenTransfer.TransferType.NONE, + receiver ); } diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index 5581cc0..a538e5d 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -548,6 +548,7 @@ impl SwapEncoder for CurveSwapEncoder { j.to_be_bytes::<1>(), approval_needed, (encoding_context.transfer_type as u8).to_be_bytes(), + bytes_to_address(&encoding_context.receiver)?, ); Ok(args.abi_encode_packed()) @@ -1276,6 +1277,8 @@ mod tests { "01", // transfer type "05", + // receiver, + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" )) ); } @@ -1344,6 +1347,8 @@ mod tests { "01", // transfer type "05", + // receiver + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" )) ); } @@ -1422,6 +1427,8 @@ mod tests { "01", // transfer type "05", + // receiver + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" )) ); } From ec87969aa6e938a4e0d5bdfa0d6aaae1c49b56fd Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 15 Apr 2025 16:21:23 +0100 Subject: [PATCH 3/5] feat: Add transfer out for Uniswap V4 Add transfer in Executor and pass receiver address in encoding This is done by using the TAKE action instead of TAKE_ALL --- don't change below this line --- ENG-4315 Took 1 hour 36 minutes Took 2 minutes --- foundry/src/executors/UniswapV4Executor.sol | 25 +++++++++++-------- foundry/test/TychoRouterSplitSwap.t.sol | 5 ++-- .../test/executors/UniswapV4Executor.t.sol | 19 ++++++++------ foundry/test/executors/UniswapV4Utils.sol | 3 ++- .../evm/strategy_encoder/strategy_encoders.rs | 1 + .../evm/swap_encoder/swap_encoders.rs | 15 +++++++---- src/encoding/evm/tycho_encoders.rs | 2 ++ 7 files changed, 43 insertions(+), 27 deletions(-) diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index aafbd7d..6f32012 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -46,6 +46,7 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer { address tokenOut, bool zeroForOne, TransferType transferType, + address receiver, UniswapV4Executor.UniswapV4Pool[] memory pools ) = _decodeData(data); @@ -72,7 +73,7 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer { bytes memory actions = abi.encodePacked( uint8(Actions.SWAP_EXACT_IN_SINGLE), uint8(Actions.SETTLE_ALL), - uint8(Actions.TAKE_ALL) + uint8(Actions.TAKE) ); bytes[] memory params = new bytes[](3); @@ -87,7 +88,7 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer { }) ); params[1] = abi.encode(tokenIn, amountIn); // currency to settle - params[2] = abi.encode(tokenOut, uint256(0)); // currency to take + params[2] = abi.encode(tokenOut, receiver, uint256(0)); // currency to take. 0 means to take the full amount swapData = abi.encode(actions, params); } else { PathKey[] memory path = new PathKey[](pools.length); @@ -104,7 +105,7 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer { bytes memory actions = abi.encodePacked( uint8(Actions.SWAP_EXACT_IN), uint8(Actions.SETTLE_ALL), - uint8(Actions.TAKE_ALL) + uint8(Actions.TAKE) ); bytes[] memory params = new bytes[](3); @@ -119,22 +120,22 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer { }) ); params[1] = abi.encode(currencyIn, amountIn); - params[2] = abi.encode(Currency.wrap(tokenOut), uint256(0)); + params[2] = abi.encode(Currency.wrap(tokenOut), receiver, uint256(0)); swapData = abi.encode(actions, params); } uint256 tokenOutBalanceBefore; tokenOutBalanceBefore = tokenOut == address(0) - ? address(this).balance - : IERC20(tokenOut).balanceOf(address(this)); + ? receiver.balance + : IERC20(tokenOut).balanceOf(receiver); executeActions(swapData); uint256 tokenOutBalanceAfter; tokenOutBalanceAfter = tokenOut == address(0) - ? address(this).balance - : IERC20(tokenOut).balanceOf(address(this)); + ? receiver.balance + : IERC20(tokenOut).balanceOf(receiver); calculatedAmount = tokenOutBalanceAfter - tokenOutBalanceBefore; @@ -155,10 +156,11 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer { address tokenOut, bool zeroForOne, TransferType transferType, + address receiver, UniswapV4Pool[] memory pools ) { - if (data.length < 67) { + if (data.length < 88) { revert UniswapV4Executor__InvalidDataLength(); } @@ -166,10 +168,11 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer { tokenOut = address(bytes20(data[20:40])); zeroForOne = (data[40] != 0); transferType = TransferType(uint8(data[41])); + receiver = address(bytes20(data[42:62])); - uint256 poolsLength = (data.length - 42) / 26; // 26 bytes per pool object + uint256 poolsLength = (data.length - 62) / 26; // 26 bytes per pool object pools = new UniswapV4Pool[](poolsLength); - bytes memory poolsData = data[42:]; + bytes memory poolsData = data[62:]; uint256 offset = 0; for (uint256 i = 0; i < poolsLength; i++) { address intermediaryToken; diff --git a/foundry/test/TychoRouterSplitSwap.t.sol b/foundry/test/TychoRouterSplitSwap.t.sol index 255c76b..97083d7 100644 --- a/foundry/test/TychoRouterSplitSwap.t.sol +++ b/foundry/test/TychoRouterSplitSwap.t.sol @@ -423,6 +423,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { USDT_ADDR, true, TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_ROUTER, + ALICE, pools ); @@ -471,7 +472,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { }); bytes memory protocolData = UniswapV4Utils.encodeExactInput( - USDE_ADDR, WBTC_ADDR, true, TokenTransfer.TransferType.NONE, pools + USDE_ADDR, WBTC_ADDR, true, TokenTransfer.TransferType.NONE, ALICE, pools ); bytes memory swap = encodeSplitSwap( @@ -483,7 +484,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouter.exposedSplitSwap(amountIn, 2, pleEncode(swaps)); - assertEq(IERC20(WBTC_ADDR).balanceOf(tychoRouterAddr), 102718); + assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), 102718); } function testSplitInputCyclicSwapInternalMethod() public { diff --git a/foundry/test/executors/UniswapV4Executor.t.sol b/foundry/test/executors/UniswapV4Executor.t.sol index 62f61c9..2518774 100644 --- a/foundry/test/executors/UniswapV4Executor.t.sol +++ b/foundry/test/executors/UniswapV4Executor.t.sol @@ -22,6 +22,7 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor { address tokenOut, bool zeroForOne, TokenTransfer.TransferType transferType, + address receiver, UniswapV4Pool[] memory pools ) { @@ -68,7 +69,7 @@ contract UniswapV4ExecutorTest is Test, Constants { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, USDT_ADDR, zeroForOne, transferType, pools + USDE_ADDR, USDT_ADDR, zeroForOne, transferType, ALICE, pools ); ( @@ -76,6 +77,7 @@ contract UniswapV4ExecutorTest is Test, Constants { address tokenOut, bool zeroForOneDecoded, TokenTransfer.TransferType transferTypeDecoded, + address receiver, UniswapV4Executor.UniswapV4Pool[] memory decodedPools ) = uniswapV4Exposed.decodeData(data); @@ -83,6 +85,7 @@ contract UniswapV4ExecutorTest is Test, Constants { assertEq(tokenOut, USDT_ADDR); assertEq(zeroForOneDecoded, zeroForOne); assertEq(uint8(transferTypeDecoded), uint8(transferType)); + assertEq(receiver, ALICE); assertEq(decodedPools.length, 2); assertEq(decodedPools[0].intermediaryToken, USDT_ADDR); assertEq(decodedPools[0].fee, pool1Fee); @@ -108,7 +111,7 @@ contract UniswapV4ExecutorTest is Test, Constants { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, USDT_ADDR, true, TokenTransfer.TransferType.NONE, pools + USDE_ADDR, USDT_ADDR, true, TokenTransfer.TransferType.NONE, ALICE, pools ); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); @@ -117,7 +120,7 @@ contract UniswapV4ExecutorTest is Test, Constants { USDE.balanceOf(address(uniswapV4Exposed)), usdeBalanceBeforeSwapExecutor - amountIn ); - assertTrue(USDT.balanceOf(address(uniswapV4Exposed)) == amountOut); + assertTrue(USDT.balanceOf(ALICE) == amountOut); } function testSingleSwapIntegration() public { @@ -134,10 +137,10 @@ contract UniswapV4ExecutorTest is Test, Constants { uint256 amountOut = uniswapV4Exposed.swap(amountIn, protocolData); assertEq(USDE.balanceOf(poolManager), usdeBalanceBeforePool + amountIn); assertEq( - USDE.balanceOf(address(uniswapV4Exposed)), + USDE.balanceOf(ALICE), usdeBalanceBeforeSwapExecutor - amountIn ); - assertTrue(USDT.balanceOf(address(uniswapV4Exposed)) == amountOut); + assertTrue(USDT.balanceOf(ALICE) == amountOut); } function testMultipleSwap() public { @@ -162,7 +165,7 @@ contract UniswapV4ExecutorTest is Test, Constants { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, WBTC_ADDR, true, TokenTransfer.TransferType.NONE, pools + USDE_ADDR, WBTC_ADDR, true, TokenTransfer.TransferType.NONE, ALICE, pools ); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); @@ -172,7 +175,7 @@ contract UniswapV4ExecutorTest is Test, Constants { usdeBalanceBeforeSwapExecutor - amountIn ); assertTrue( - IERC20(WBTC_ADDR).balanceOf(address(uniswapV4Exposed)) == amountOut + IERC20(WBTC_ADDR).balanceOf(ALICE) == amountOut ); } @@ -196,7 +199,7 @@ contract UniswapV4ExecutorTest is Test, Constants { usdeBalanceBeforeSwapExecutor - amountIn ); assertTrue( - IERC20(WBTC_ADDR).balanceOf(address(uniswapV4Exposed)) == amountOut + IERC20(WBTC_ADDR).balanceOf(ALICE) == amountOut ); } } diff --git a/foundry/test/executors/UniswapV4Utils.sol b/foundry/test/executors/UniswapV4Utils.sol index 1ccc29c..c96465c 100644 --- a/foundry/test/executors/UniswapV4Utils.sol +++ b/foundry/test/executors/UniswapV4Utils.sol @@ -9,6 +9,7 @@ library UniswapV4Utils { address tokenOut, bool zeroForOne, UniswapV4Executor.TransferType transferType, + address receiver, UniswapV4Executor.UniswapV4Pool[] memory pools ) public pure returns (bytes memory) { bytes memory encodedPools; @@ -23,7 +24,7 @@ library UniswapV4Utils { } return abi.encodePacked( - tokenIn, tokenOut, zeroForOne, transferType, encodedPools + tokenIn, tokenOut, zeroForOne, transferType, receiver, encodedPools ); } } diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 4a34850..29f085c 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -1433,6 +1433,7 @@ mod tests { "6982508145454ce325ddbe47a25d4ec3d2311933", // group token in "00", // zero2one "04", // transfer type (transfer to router) + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver // First pool params "0000000000000000000000000000000000000000", // intermediary token (ETH) "000bb8", // fee diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index a538e5d..decaeab 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -207,6 +207,7 @@ impl SwapEncoder for UniswapV4SwapEncoder { group_token_out_address, zero_to_one, (encoding_context.transfer_type as u8).to_be_bytes(), + bytes_to_address(&encoding_context.receiver)?, pool_params, ); @@ -766,9 +767,8 @@ mod tests { split: 0f64, }; let encoding_context = EncodingContext { - // The receiver address was taken from `address(uniswapV4Exposed)` in the - // UniswapV4Executor.t.sol - receiver: Bytes::from("0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f"), + // The receiver is ALICE to match the solidity tests + receiver: Bytes::from("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2"), exact_out: false, // Same as the executor address router_address: Some(Bytes::from("0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f")), @@ -800,6 +800,8 @@ mod tests { "01", // transfer type "00", + // receiver + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // pool params: // - intermediary token "dac17f958d2ee523a2206206994597c13d831ec7", @@ -878,11 +880,11 @@ mod tests { let usdt_address = Bytes::from("0xdAC17F958D2ee523a2206206994597C13D831ec7"); let wbtc_address = Bytes::from("0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"); let router_address = Bytes::from("0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f"); - let receiver_address = router_address.clone(); // The context is the same for both swaps, since the group token in and out are the same let context = EncodingContext { - receiver: receiver_address.clone(), + // The receiver is ALICE to match the solidity tests + receiver: Bytes::from("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2"), exact_out: false, router_address: Some(router_address.clone()), group_token_in: usde_address.clone(), @@ -968,6 +970,8 @@ mod tests { "01", // transfer type "00", + // receiver + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // pool params: // - intermediary token USDT "dac17f958d2ee523a2206206994597c13d831ec7", @@ -983,6 +987,7 @@ mod tests { "00003c" )) ); + println!("{}", combined_hex) } mod ekubo { diff --git a/src/encoding/evm/tycho_encoders.rs b/src/encoding/evm/tycho_encoders.rs index 1ecf41f..5d285e0 100644 --- a/src/encoding/evm/tycho_encoders.rs +++ b/src/encoding/evm/tycho_encoders.rs @@ -1050,6 +1050,8 @@ mod tests { "00", // transfer type "00", + // receiver + "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // first pool intermediary token (ETH) "0000000000000000000000000000000000000000", // fee From 8145f416b7a12c52e27a1b3b6399d52625d992e5 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Tue, 15 Apr 2025 18:27:19 +0100 Subject: [PATCH 4/5] fix: After rebase fixes - In Tycho Router - Fix integration tests - If the trade is cyclical, we can't do the balance check for the correctness of the amountOut transfers - In encoding, - if it is a wrap trade, the transfer should be just a normal Transfer (not TransferFrom nor a Permit2Transfer) - add test names to println! statements --- don't change below this line --- ENG-4315 Took 1 hour 0 minutes Took 30 seconds Took 21 seconds Took 16 seconds Took 17 seconds --- foundry/src/TychoRouter.sol | 37 +++++++++------ foundry/src/executors/CurveExecutor.sol | 3 +- foundry/src/executors/UniswapV4Executor.sol | 3 +- foundry/test/TychoRouterIntegration.t.sol | 32 ++++++------- foundry/test/TychoRouterSequentialSwap.t.sol | 2 +- foundry/test/TychoRouterSingleSwap.t.sol | 46 +++++++++++-------- foundry/test/TychoRouterSplitSwap.t.sol | 20 ++++++-- .../test/executors/UniswapV4Executor.t.sol | 29 +++++++----- .../evm/strategy_encoder/strategy_encoders.rs | 46 +++++++++---------- .../transfer_optimizations.rs | 7 +-- .../evm/swap_encoder/swap_encoders.rs | 4 +- 11 files changed, 132 insertions(+), 97 deletions(-) diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index a01fdba..3c28a11 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -433,10 +433,14 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { Address.sendValue(payable(receiver), amountOut); } - uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver); - uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut; - if (userAmount != amountOut) { - revert TychoRouter__AmountOutNotFullyReceived(userAmount, amountOut); + if (tokenIn != tokenOut) { + uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver); + uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut; + if (userAmount != amountOut) { + revert TychoRouter__AmountOutNotFullyReceived( + userAmount, amountOut + ); + } } } @@ -483,11 +487,14 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { Address.sendValue(payable(receiver), amountOut); } - uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver); - uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut; - - if (userAmount != amountOut) { - revert TychoRouter__AmountOutNotFullyReceived(userAmount, amountOut); + if (tokenIn != tokenOut) { + uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver); + uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut; + if (userAmount != amountOut) { + revert TychoRouter__AmountOutNotFullyReceived( + userAmount, amountOut + ); + } } } @@ -531,11 +538,15 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { _unwrapETH(amountOut); Address.sendValue(payable(receiver), amountOut); } - uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver); - uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut; - if (userAmount != amountOut) { - revert TychoRouter__AmountOutNotFullyReceived(userAmount, amountOut); + if (tokenIn != tokenOut) { + uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver); + uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut; + if (userAmount != amountOut) { + revert TychoRouter__AmountOutNotFullyReceived( + userAmount, amountOut + ); + } } } diff --git a/foundry/src/executors/CurveExecutor.sol b/foundry/src/executors/CurveExecutor.sol index 8f893a0..8c9995c 100644 --- a/foundry/src/executors/CurveExecutor.sol +++ b/foundry/src/executors/CurveExecutor.sol @@ -55,7 +55,7 @@ contract CurveExecutor is IExecutor, TokenTransfer { payable returns (uint256) { - if (data.length != 65) revert CurveExecutor__InvalidDataLength(); + if (data.length != 85) revert CurveExecutor__InvalidDataLength(); ( address tokenIn, @@ -134,6 +134,7 @@ contract CurveExecutor is IExecutor, TokenTransfer { int128 i, int128 j, bool tokenApprovalNeeded, + TransferType transferType, address receiver ) { diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index 6f32012..9191f98 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -120,7 +120,8 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer { }) ); params[1] = abi.encode(currencyIn, amountIn); - params[2] = abi.encode(Currency.wrap(tokenOut), receiver, uint256(0)); + params[2] = + abi.encode(Currency.wrap(tokenOut), receiver, uint256(0)); swapData = abi.encode(actions, params); } uint256 tokenOutBalanceBefore; diff --git a/foundry/test/TychoRouterIntegration.t.sol b/foundry/test/TychoRouterIntegration.t.sol index df57ab0..f168175 100644 --- a/foundry/test/TychoRouterIntegration.t.sol +++ b/foundry/test/TychoRouterIntegration.t.sol @@ -12,7 +12,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { uint256 balancerBefore = IERC20(DAI_ADDR).balanceOf(ALICE); // Encoded solution generated using `test_split_swap_strategy_encoder_no_permit2` (bool success,) = tychoRouterAddr.call( - hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae37400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000059005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000100000000000000" + hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae37400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000059005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000" ); vm.stopPrank(); @@ -37,7 +37,7 @@ contract TychoRouterTestIntegration 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"7c553846000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006824c2ae00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fd3cb6000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041850e1add80e90f19d7b1ac70721b5dec8a6bdcb57999ea957f831ea57c4ce1a116bec18d2cae2559421ead48186b6985176fee7f8d2e3452c1518dc2635224b41c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007900770001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d231193300040000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000" + hex"7c553846000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006826193a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe9342000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c96ca498573c3c283e270700101c963405003b631ce90988c3690248b5cab66a70a1cb074afa6acf671300c917b8d6ac0149ae538c95a67a844175bfa9ae7d811b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008d008b0001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330004cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000" ); vm.stopPrank(); @@ -60,7 +60,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { // Encoded solution generated using `test_split_encoding_strategy_usv4_eth_in` (bool success,) = tychoRouterAddr.call{value: 1 ether}( - hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000c87c939ae635f92dc2379c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006824c2cb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fd3cd3000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041a97e156e8c7a48a968efe2f057700ce8458ecfbfb53e0319fc9223b2364aba20227d2ee00226b42e2f28aeb002a242576d75152b270d73a8926f595190828f3d1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f005d0001000000f62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d231193301056982508145454ce325ddbe47a25d4ec3d23119330061a80001f400" + hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000c87c939ae635f92dc2379c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006826193a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe934200000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004197c8f24177a14b631dd3a9226c08a0a376fcaf7894364b5131db4415890fc2c57a48bb5497d36a57a4aa359fd6781788c697f6a85500d7bee3e7a1597f0900b81b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330105cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000" ); vm.stopPrank(); @@ -87,7 +87,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { // Encoded solution generated using `test_split_encoding_strategy_usv4_eth_out` (bool success,) = tychoRouterAddr.call( - hex"7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006824c2da00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fd3ce20000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416b224d97fe1a35f2698380969c22854cf7ed92881ea484df7adb438f8d8e78e66c8617131f6712c5f3b4fa07725725081b2ebe27cd44acd11332a4a72bded96c1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f005d0001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000040000000000000000000000000000000000000000000bb800003c00" + hex"7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006826193a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe9342000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041dbb84c68a4293bcf6303ca45327614667c54226086ddcfa2daa9289c1657da9a57268f4d8ceea3c831d43e5a96b1dc54766bc3fda8845d5c7e266981b9d84c651b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000004cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000" ); vm.stopPrank(); @@ -109,7 +109,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { vm.startPrank(ALICE); // Encoded solution generated using `test_split_swap_strategy_encoder_wrap` (bool success,) = tychoRouterAddr.call{value: 1 ether}( - hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006821640400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9de0c000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041b34e1f3d4e78942b2429b776073a5dfab1420f763de7d7e2a2296ca8abf684f923f7ae7945e824d8a084b9610d33ed49246a36e8e0efbce8ae210b0474f9fe3a1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059005700020000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000" + hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068261ff900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe9a01000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041eaba97110bc7c3586bf8fa3d3d2c24a3863e84d2e1688689e325e750f860802d745309e3dc818fe029f439c14a52d9a3f48f2873733259c342eb01bdf8ac896b1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059005700020000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000" ); vm.stopPrank(); @@ -131,7 +131,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { IERC20(DAI_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max); // Encoded solution generated using `test_split_swap_strategy_encoder_unwrap` (bool success,) = tychoRouterAddr.call( - hex"7c5538460000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be00000000000000000000000000000000000000000000000000000000000006821641200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9de1a00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004181d23336d0cacd47a4d228590a825a1d92a48378cd481ff308b6d235e14b925c584f31e420682879bea58363ca4aa44a3b79557b15a9f73078a4696e00f55f911b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395010200000000000000" + hex"7c5538460000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be00000000000000000000000000000000000000000000000000000000000006826193a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe93420000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000413c401d4a22c3e0b693b4f9d0807f6107ab6b6d6b716a45978ba175af6e717ae617d4c13b8603db25ee6902b807ee049588ce27030bf3f60833bf26e9561f560c1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395010200000000000000" ); vm.stopPrank(); @@ -159,7 +159,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { vm.startPrank(ALICE); // Encoded solution generated using `test_split_encoding_strategy_ekubo` (bool success,) = address(tychoRouter).call{value: 1 ether}( - hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000078007600010000003d7ebc40af7092e3f1c81f2e996cba5cae2090d705a4ad4f68d0b91cfd19687c881e50f3a00242828c0000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c0000000000000000000000000000000000000000" + hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000078007600010000003d7ebc40af7092e3f1c81f2e996cba5cae2090d705cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c0000000000000000000000000000000000000000" ); uint256 balancerAfter = IERC20(USDC_ADDR).balanceOf(ALICE); @@ -181,9 +181,9 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { // Approve permit2 vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max); - // Encoded solution generated using `test_split_swap_strategy_encoder_complex` + // Encoded solution generated using `test_split_swap_strategy_encoder_complex_route` (bool success,) = tychoRouterAddr.call( - hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006821643700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9de3f00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004112f41a590796702b322fa5a9ee1602daef9b22d732e4fd8f122f072b65dda325271f630759db500db8a42bd4f41ddc18ddda63650deaf36228dca702e28eefd31b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950002005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950002005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d53ede3eca2a72b3aecc820e955b36f38437d013950100005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d01395010000000000000000000000000000000000000000000000000000000000" + hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006826193a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe9342000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041d137d0776bc16ff9c49bfd3e96103ceb6926654f314489cafcf5a64ab7a9c4f2061ed5ffdef67c33c3c5b78036d28d9eb73da156a0e68d8740235be50e88a3481b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950002005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950002005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010000000000000000000000000000000000000000000000000000000000" ); vm.stopPrank(); @@ -210,7 +210,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { IERC20(WETH_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max); // Encoded solution generated using `test_sequential_swap_strategy_encoder_complex_route` (bool success,) = tychoRouterAddr.call( - hex"51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006821644a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9de5200000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041530bdcde0c687eacb51a339f30c7b3eff7c078a3bbd4bc852519568dcdf271bb4c6ac05583f32c4a8d1a99be3a2817fe86c15ad2a06c5cf938bde9c22bc80f301c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d01395000200525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d013950100000000000000000000000000000000000000000000000000" + hex"51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006826193a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe934200000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041d137d0776bc16ff9c49bfd3e96103ceb6926654f314489cafcf5a64ab7a9c4f2061ed5ffdef67c33c3c5b78036d28d9eb73da156a0e68d8740235be50e88a3481b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d01395000200525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000" ); vm.stopPrank(); @@ -234,7 +234,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max); // Encoded solution generated using `test_sequential_swap_strategy_encoder_no_permit2` (bool success,) = tychoRouterAddr.call( - hex"e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d01395000100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d013950100000000000000000000000000000000000000000000000000" + hex"e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d01395000100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000" ); vm.stopPrank(); @@ -252,9 +252,9 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { // Approve permit2 vm.startPrank(ALICE); IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max); - // Encoded solution generated using `test_cyclic_sequential_swap` + // Encoded solution generated using `test_cyclic_sequential_swap_split_strategy` (bool success,) = tychoRouterAddr.call( - hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f4308e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006821647000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9de780000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000413c8b048dc7b7614106a5aa1fa13e48c02a6a9714dfa07d2c424f68b81a5f828c39ace62f2dd57d7bfad10910ae44f77d68aec5c079fce456028b1bd7f72053151c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400102006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80000" + hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f4308e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006826193a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe934200000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004194fc497ac440b520981d23b4713425da21dc1c801e657d218a917b5c51339a660b9a5fe0a346cb0aacc0d67ebf03f8fa3ec9fade437ef1b08ea837b2442931b61b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400102006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000" ); assertTrue(success, "Call Failed"); @@ -271,7 +271,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max); // Encoded solution generated using `test_split_input_cyclic_swap` (bool success,) = tychoRouterAddr.call( - hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006821659d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9dfa5000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041dd84c5cdc51719e377598eccd8eac0aae036e7e0745a7c65b5d44cc817071a7460ccc73934363f33cc7af71dc07545aeff1d92f8c2f0b2973e1fc37e7b2de3551c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400102006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80102005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000" + hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006826193a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe934200000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004194fc497ac440b520981d23b4713425da21dc1c801e657d218a917b5c51339a660b9a5fe0a346cb0aacc0d67ebf03f8fa3ec9fade437ef1b08ea837b2442931b61b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400102006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80102005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000" ); assertTrue(success, "Call Failed"); @@ -288,7 +288,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max); // Encoded solution generated using `test_split_output_cyclic_swap` (bool success,) = tychoRouterAddr.call( - hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005eea514000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000682165ac00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9dfb400000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004107f2b0f9c2e4e308ab43b288d69de30d84b10c8075e4dd9a2cf66594f97a52fb34de2534b89bf1887da74c92fd03464f45baff700dd32e213e3add1a3f351e891b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950102006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400000006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8000000000000000000" + hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005eea514000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006826193a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe934200000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004194fc497ac440b520981d23b4713425da21dc1c801e657d218a917b5c51339a660b9a5fe0a346cb0aacc0d67ebf03f8fa3ec9fade437ef1b08ea837b2442931b61b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950102006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400000006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000000000000000000" ); assertTrue(success, "Call Failed"); @@ -304,7 +304,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup { IERC20(UWU_ADDR).approve(tychoRouterAddr, type(uint256).max); // Encoded solution generated using `test_split_encoding_strategy_curve` (bool success,) = tychoRouterAddr.call( - hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000005c005a00010000001d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e71020100010300000000" + hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000070006e00010000001d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000103cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000" ); assertTrue(success, "Call Failed"); diff --git a/foundry/test/TychoRouterSequentialSwap.t.sol b/foundry/test/TychoRouterSequentialSwap.t.sol index d72d93e..9e35c6f 100644 --- a/foundry/test/TychoRouterSequentialSwap.t.sol +++ b/foundry/test/TychoRouterSequentialSwap.t.sol @@ -216,7 +216,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { encodeUniswapV2Swap( DAI_ADDR, DAI_USDC_POOL, - tychoRouterAddr, + ALICE, true, TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL ) diff --git a/foundry/test/TychoRouterSingleSwap.t.sol b/foundry/test/TychoRouterSingleSwap.t.sol index aa56efb..f2fba1b 100644 --- a/foundry/test/TychoRouterSingleSwap.t.sol +++ b/foundry/test/TychoRouterSingleSwap.t.sol @@ -21,10 +21,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { bytes memory signature ) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, WETH_DAI_POOL, - ALICE, false, + ALICE, + false, TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL ); @@ -61,10 +62,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { // Approve the tokenIn to be transferred to the router IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, WETH_DAI_POOL, - ALICE, false, + ALICE, + false, TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL ); @@ -101,10 +103,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, WETH_DAI_POOL, - ALICE, false, + ALICE, + false, TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL ); @@ -126,10 +129,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn - 1); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, WETH_DAI_POOL, - ALICE, false, + ALICE, + false, TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL ); @@ -160,10 +164,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { // Approve the tokenIn to be transferred to the router IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, WETH_DAI_POOL, - ALICE, false, + ALICE, + false, TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL ); @@ -208,10 +213,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { sigDeadline: 0 }); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, WETH_DAI_POOL, - ALICE, false, + ALICE, + false, TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL ); @@ -290,7 +296,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max); // Encoded solution generated using `test_single_swap_strategy_encoder_no_permit2` (bool success,) = tychoRouterAddr.call( - hex"20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae3740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500010000000000000000000000000000" + hex"20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae3740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000" ); vm.stopPrank(); @@ -309,7 +315,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { IERC20(WETH_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max); // Encoded solution generated using `test_single_swap_strategy_encoder` (bool success,) = tychoRouterAddr.call( - hex"30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000682169c100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9e3c900000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000412d3f0fee3fc61987512f024f20b1448eb934f82105a91653dd169179c693aaf95d09ef666ce1d38be70b8156fa6e4ea3e8717204e02fe7ba99a1fc4e5a26e6e11b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500020000000000000000000000000000" + hex"30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006826193a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe934200000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041d137d0776bc16ff9c49bfd3e96103ceb6926654f314489cafcf5a64ab7a9c4f2061ed5ffdef67c33c3c5b78036d28d9eb73da156a0e68d8740235be50e88a3481b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200020000000000000000000000000000" ); vm.stopPrank(); diff --git a/foundry/test/TychoRouterSplitSwap.t.sol b/foundry/test/TychoRouterSplitSwap.t.sol index 97083d7..46817c4 100644 --- a/foundry/test/TychoRouterSplitSwap.t.sol +++ b/foundry/test/TychoRouterSplitSwap.t.sol @@ -44,7 +44,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint8(2), uint24(0), address(usv2Executor), - encodeUniswapV2Swap(WBTC_ADDR, USDC_WBTC_POOL, ALICE, true, + encodeUniswapV2Swap( + WBTC_ADDR, + USDC_WBTC_POOL, + ALICE, + true, TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL ) ); @@ -261,10 +265,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { spender: address(0), sigDeadline: 0 }); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, WETH_DAI_POOL, - ALICE, false, + ALICE, + false, TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL ); @@ -472,7 +477,12 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { }); bytes memory protocolData = UniswapV4Utils.encodeExactInput( - USDE_ADDR, WBTC_ADDR, true, TokenTransfer.TransferType.NONE, ALICE, pools + USDE_ADDR, + WBTC_ADDR, + true, + TokenTransfer.TransferType.NONE, + ALICE, + pools ); bytes memory swap = encodeSplitSwap( diff --git a/foundry/test/executors/UniswapV4Executor.t.sol b/foundry/test/executors/UniswapV4Executor.t.sol index 2518774..9ff7f72 100644 --- a/foundry/test/executors/UniswapV4Executor.t.sol +++ b/foundry/test/executors/UniswapV4Executor.t.sol @@ -111,7 +111,12 @@ contract UniswapV4ExecutorTest is Test, Constants { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, USDT_ADDR, true, TokenTransfer.TransferType.NONE, ALICE, pools + USDE_ADDR, + USDT_ADDR, + true, + TokenTransfer.TransferType.NONE, + ALICE, + pools ); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); @@ -127,7 +132,7 @@ contract UniswapV4ExecutorTest is Test, Constants { // USDE -> USDT // Generated by the Tycho swap encoder - test_encode_uniswap_v4_simple_swap bytes memory protocolData = - hex"4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec70100dac17f958d2ee523a2206206994597c13d831ec7000064000001"; + hex"4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec70100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001"; uint256 amountIn = 100 ether; deal(USDE_ADDR, address(uniswapV4Exposed), amountIn); uint256 usdeBalanceBeforePool = USDE.balanceOf(poolManager); @@ -137,8 +142,7 @@ contract UniswapV4ExecutorTest is Test, Constants { uint256 amountOut = uniswapV4Exposed.swap(amountIn, protocolData); assertEq(USDE.balanceOf(poolManager), usdeBalanceBeforePool + amountIn); assertEq( - USDE.balanceOf(ALICE), - usdeBalanceBeforeSwapExecutor - amountIn + USDE.balanceOf(ALICE), usdeBalanceBeforeSwapExecutor - amountIn ); assertTrue(USDT.balanceOf(ALICE) == amountOut); } @@ -165,7 +169,12 @@ contract UniswapV4ExecutorTest is Test, Constants { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, WBTC_ADDR, true, TokenTransfer.TransferType.NONE, ALICE, pools + USDE_ADDR, + WBTC_ADDR, + true, + TokenTransfer.TransferType.NONE, + ALICE, + pools ); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); @@ -174,9 +183,7 @@ contract UniswapV4ExecutorTest is Test, Constants { USDE.balanceOf(address(uniswapV4Exposed)), usdeBalanceBeforeSwapExecutor - amountIn ); - assertTrue( - IERC20(WBTC_ADDR).balanceOf(ALICE) == amountOut - ); + assertTrue(IERC20(WBTC_ADDR).balanceOf(ALICE) == amountOut); } function testMultipleSwapIntegration() public { @@ -184,7 +191,7 @@ contract UniswapV4ExecutorTest is Test, Constants { // Generated by the Tycho swap encoder - test_encode_uniswap_v4_sequential_swap bytes memory protocolData = - hex"4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990100dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c"; + hex"4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c"; uint256 amountIn = 100 ether; deal(USDE_ADDR, address(uniswapV4Exposed), amountIn); @@ -198,8 +205,6 @@ contract UniswapV4ExecutorTest is Test, Constants { USDE.balanceOf(address(uniswapV4Exposed)), usdeBalanceBeforeSwapExecutor - amountIn ); - assertTrue( - IERC20(WBTC_ADDR).balanceOf(ALICE) == amountOut - ); + assertTrue(IERC20(WBTC_ADDR).balanceOf(ALICE) == amountOut); } } diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 29f085c..be6316b 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -536,7 +536,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { )) })?; - let receiver = if !wrap && grouped_swap.output_token == solution.checked_token { + let receiver = if !unwrap && grouped_swap.output_token == solution.checked_token { solution.receiver.clone() } else { self.router_address.clone() @@ -892,7 +892,7 @@ mod tests { "0000000000000000000000000000", // padding )); let hex_calldata = encode(&calldata); - println!("{}", hex_calldata); + println!("test_single_swap_strategy_encoder: {}", hex_calldata); assert_eq!(hex_calldata[..456], expected_input); assert_eq!(hex_calldata[1224..], expected_swap); @@ -947,7 +947,7 @@ mod tests { .unwrap(); let hex_calldata = encode(&calldata); - println!("{}", hex_calldata); + println!("test_single_swap_strategy_encoder_wrap: {}", hex_calldata); } #[test] @@ -999,7 +999,7 @@ mod tests { .unwrap(); let hex_calldata = encode(&calldata); - println!("{}", hex_calldata); + println!("test_split_swap_strategy_encoder_wrap: {}", hex_calldata); } #[test] @@ -1051,7 +1051,7 @@ mod tests { .unwrap(); let hex_calldata = encode(&calldata); - println!("{}", hex_calldata); + println!("test_split_swap_strategy_encoder_unwrap: {}", hex_calldata); } #[test] @@ -1143,7 +1143,7 @@ mod tests { .unwrap(); let _hex_calldata = encode(&calldata); - println!("{}", _hex_calldata); + println!("test_split_swap_strategy_encoder_complex_route: {}", _hex_calldata); } #[test] @@ -1209,7 +1209,7 @@ mod tests { .unwrap(); let _hex_calldata = encode(&calldata); - println!("{}", _hex_calldata); + println!("test_sequential_swap_strategy_encoder_complex_route: {}", _hex_calldata); } #[test] @@ -1268,7 +1268,7 @@ mod tests { .unwrap(); let hex_calldata = encode(&calldata); - println!("{}", hex_calldata); + println!("test_sequential_swap_strategy_encoder_no_permit2: {}", hex_calldata); let expected = String::from(concat!( "e8a980d7", /* function selector */ @@ -1289,7 +1289,7 @@ mod tests { "bb2b8038a1640196fbe3e38816f3e67cba72d940", // component id "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver (router) "00", // zero to one - "00", // transfer type + "01", // transfer type // swap 2 "0052", // swap length "5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address @@ -1420,9 +1420,9 @@ mod tests { let expected_swaps = String::from(concat!( // length of ple encoded swaps without padding - "0000000000000000000000000000000000000000000000000000000000000079", + "000000000000000000000000000000000000000000000000000000000000008d", // ple encoded swaps - "0077", // Swap length + "008b", // Swap length "00", // token in index "01", // token out index "000000", // split @@ -1442,14 +1442,14 @@ mod tests { "6982508145454ce325ddbe47a25d4ec3d2311933", // intermediary token (PEPE) "0061a8", // fee "0001f4", // tick spacing - "00000000000000" // padding + "00000000000000000000000000000000000000" // padding )); let hex_calldata = encode(&calldata); assert_eq!(hex_calldata[..520], expected_input); assert_eq!(hex_calldata[1288..], expected_swaps); - println!("{}", hex_calldata); + println!("test_split_encoding_strategy_usv4: {}", hex_calldata); } #[test] @@ -1509,7 +1509,7 @@ mod tests { .unwrap(); let hex_calldata = encode(&calldata); - println!("{}", hex_calldata); + println!("test_split_encoding_strategy_ekubo: {}", hex_calldata); } #[test] @@ -1587,7 +1587,7 @@ mod tests { let hex_calldata = encode(&calldata); assert_eq!(hex_calldata, expected_input); - println!("{}", hex_calldata); + println!("test_single_swap_strategy_encoder_no_permit2: {}", hex_calldata); } #[test] @@ -1670,7 +1670,7 @@ mod tests { let hex_calldata = encode(&calldata); assert_eq!(hex_calldata, expected_input); - println!("{}", hex_calldata); + println!("test_split_swap_strategy_encoder_no_permit2: {}", hex_calldata); } #[test] @@ -1734,7 +1734,7 @@ mod tests { .unwrap(); let hex_calldata = encode(&calldata); - println!("{}", hex_calldata); + println!("test_split_encoding_strategy_usv4_eth_in: {}", hex_calldata); } #[test] fn test_split_encoding_strategy_usv4_eth_out() { @@ -1801,7 +1801,7 @@ mod tests { .unwrap(); let hex_calldata = encode(&calldata); - println!("{}", hex_calldata); + println!("test_split_encoding_strategy_usv4_eth_out: {}", hex_calldata); } #[test] @@ -1931,7 +1931,7 @@ mod tests { assert_eq!(hex_calldata[..520], expected_input); assert_eq!(hex_calldata[1288..], expected_swaps); - println!("{}", hex_calldata); + println!("test_cyclic_sequential_swap_split_strategy: {}", hex_calldata); } #[test] @@ -2096,7 +2096,7 @@ mod tests { .join(""); assert_eq!(hex_calldata[..520], expected_input); assert_eq!(hex_calldata[1288..], expected_swaps); - println!("{}", hex_calldata); + println!("test_split_input_cyclic_swap: {}", hex_calldata); } #[test] @@ -2259,7 +2259,7 @@ mod tests { assert_eq!(hex_calldata[..520], expected_input); assert_eq!(hex_calldata[1288..], expected_swaps); - println!("{}", hex_calldata); + println!("test_split_output_cyclic_swap: {}", hex_calldata); } #[test] @@ -2321,7 +2321,7 @@ mod tests { .unwrap(); let hex_calldata = encode(&calldata); - println!("{}", hex_calldata); + println!("test_split_encoding_strategy_curve: {}", hex_calldata); } #[test] @@ -2383,6 +2383,6 @@ mod tests { .unwrap(); let hex_calldata = encode(&calldata); - println!("{}", hex_calldata); + println!("test_split_encoding_strategy_curve_st_eth: {}", hex_calldata); } } diff --git a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs index 5188986..08ac181 100644 --- a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs +++ b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs @@ -24,12 +24,13 @@ pub trait TransferOptimization { // In the case of wrapping, check if the swap's token in is the wrapped token to // determine if it's the first swap. Otherwise, compare to the given token. - let is_first_swap = - (swap.token_in == given_token) || ((swap.token_in == wrapped_token) && wrap); + let is_first_swap = swap.token_in == given_token; if swap.token_in == native_token { // Funds are already in router. All protocols currently take care of native transfers. TransferType::None + } else if (swap.token_in == wrapped_token) && wrap { + TransferType::TransferToProtocol } else if is_first_swap && send_funds_to_pool { if permit2 { // Transfer from swapper to pool using permit2. @@ -149,7 +150,7 @@ mod tests { let strategy = MockStrategy {}; let transfer_method = strategy.get_transfer_type(swap.clone(), eth(), eth(), weth(), false, true); - assert_eq!(transfer_method, TransferType::TransferFromToProtocol); + assert_eq!(transfer_method, TransferType::TransferToProtocol); } #[test] diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index decaeab..c2e803a 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -787,7 +787,7 @@ mod tests { .encode_swap(swap, encoding_context) .unwrap(); let hex_swap = encode(&encoded_swap); - println!("{}", hex_swap); + println!("test_encode_uniswap_v4_simple_swap: {}", hex_swap); assert_eq!( hex_swap, @@ -958,7 +958,7 @@ mod tests { let combined_hex = format!("{}{}", encode(&initial_encoded_swap), encode(&second_encoded_swap)); - println!("{}", combined_hex); + println!("test_encode_uniswap_v4_sequential_swap: {}", combined_hex); assert_eq!( combined_hex, String::from(concat!( From d447551e20c42cecd47c3005b430924f6d8aff5f Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Wed, 16 Apr 2025 14:57:02 +0100 Subject: [PATCH 5/5] fix: Bring back receiver address zero check Add small docs and rename variables --- don't change below this line --- ENG-4314 Took 1 hour 39 minutes --- foundry/src/TychoRouter.sol | 9 +++++++++ .../evm/strategy_encoder/strategy_encoders.rs | 14 ++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 3c28a11..f9597a1 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -411,6 +411,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { address receiver, bytes calldata swaps ) internal returns (uint256 amountOut) { + if (receiver == address(0)) { + revert TychoRouter__AddressZero(); + } if (minAmountOut == 0) { revert TychoRouter__UndefinedMinAmountOut(); } @@ -462,6 +465,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { address receiver, bytes calldata swap_ ) internal returns (uint256 amountOut) { + if (receiver == address(0)) { + revert TychoRouter__AddressZero(); + } if (minAmountOut == 0) { revert TychoRouter__UndefinedMinAmountOut(); } @@ -516,6 +522,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { address receiver, bytes calldata swaps ) internal returns (uint256 amountOut) { + if (receiver == address(0)) { + revert TychoRouter__AddressZero(); + } if (minAmountOut == 0) { revert TychoRouter__UndefinedMinAmountOut(); } diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index be6316b..45a83d8 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -121,7 +121,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { )) })?; - let receiver = + let swap_receiver = if !unwrap { solution.receiver.clone() } else { self.router_address.clone() }; let mut grouped_protocol_data: Vec = vec![]; @@ -136,7 +136,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { ); let encoding_context = EncodingContext { - receiver: receiver.clone(), + receiver: swap_receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.input_token.clone(), @@ -300,7 +300,9 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { )) })?; - let receiver = if i == grouped_swaps.len() - 1 && !unwrap { + // if it is the last swap and there isn't an unwrap at the end, we can set the receiver + // to the final user + let swap_receiver = if i == grouped_swaps.len() - 1 && !unwrap { solution.receiver.clone() } else { self.router_address.clone() @@ -318,7 +320,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { ); let encoding_context = EncodingContext { - receiver: receiver.clone(), + receiver: swap_receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.input_token.clone(), @@ -536,7 +538,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { )) })?; - let receiver = if !unwrap && grouped_swap.output_token == solution.checked_token { + let swap_receiver = if !unwrap && grouped_swap.output_token == solution.checked_token { solution.receiver.clone() } else { self.router_address.clone() @@ -554,7 +556,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { ); let encoding_context = EncodingContext { - receiver: receiver.clone(), + receiver: swap_receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.input_token.clone(),