From 9401ce26206b53740898aa05fff63042d1939d65 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Wed, 14 May 2025 11:22:54 +0100 Subject: [PATCH 01/22] feat: Sketch for OneTransferFromOnly.sol Took 49 seconds --- foundry/src/OneTransferFromOnly.sol | 77 +++++++++++++++++++++ foundry/src/TychoRouter.sol | 24 ++++++- foundry/src/executors/UniswapV2Executor.sol | 25 ++++--- foundry/src/executors/UniswapV3Executor.sol | 52 +++++++++----- 4 files changed, 148 insertions(+), 30 deletions(-) create mode 100644 foundry/src/OneTransferFromOnly.sol diff --git a/foundry/src/OneTransferFromOnly.sol b/foundry/src/OneTransferFromOnly.sol new file mode 100644 index 0000000..4cc26f0 --- /dev/null +++ b/foundry/src/OneTransferFromOnly.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.26; + +import "@interfaces/IExecutor.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@permit2/src/interfaces/IAllowanceTransfer.sol"; + +error TokenTransfer__AddressZero(); + +contract OneTransferFromOnly { + using SafeERC20 for IERC20; + + // this is a stupid name but the compiler was complaining that we already had a permit2 variable in TychoRouter + IAllowanceTransfer public immutable permit2lal; + uint256 private constant _TOKEN_IN_SLOT = 123; + uint256 private constant _AMOUNT_IN_SLOT = 124; + uint256 private constant _IS_PERMIT2_SLOT = 125; + uint256 private constant _SENDER_SLOT = 126; + uint256 private constant _IS_TRANSFER_EXECUTED_SLOT = 127; + + constructor(address _permit2) { + if (_permit2 == address(0)) { + revert TokenTransfer__AddressZero(); + } + permit2lal = IAllowanceTransfer(_permit2); + } + + function tstoreTransferFromInfo( + address tokenIn, + address amountIn, + bool isPermit2, + address sender + ) internal { + assembly { + tstore(_TOKEN_IN_SLOT, tokenIn) + tstore(_AMOUNT_IN_SLOT, amountIn) + tstore(_IS_PERMIT2_SLOT, isPermit2) + tstore(_SENDER_SLOT, sender) + tstore(_IS_TRANSFER_EXECUTED_SLOT, false) + } + } + + function _transfer(address receiver) + // we could pass the amount and address too and compare to what is in the slots? + internal + { + address tokenIn; + uint256 amount; + bool isPermit2; + address sender; + bool isTransferExecuted; + assembly { + tokenIn := tload(_TOKEN_IN_SLOT) + amount := tload(_AMOUNT_IN_SLOT) + isPermit2 := tload(_IS_PERMIT2_SLOT) + sender := tload(_SENDER_SLOT) + isTransferExecuted := tload(_IS_TRANSFER_EXECUTED_SLOT) + } + if (isTransferExecuted) { + return; // or revert? + } + + if (isPermit2) { + // Permit2.permit is already called from the TychoRouter + permit2lal.transferFrom(sender, receiver, uint160(amount), tokenIn); + assembly { + tstore(_IS_TRANSFER_EXECUTED_SLOT, true) + } + } else { + // slither-disable-next-line arbitrary-send-erc20 + IERC20(tokenIn).safeTransferFrom(sender, receiver, amount); + assembly { + tstore(_IS_TRANSFER_EXECUTED_SLOT, true) + } + } + } +} diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index c237d64..2d193d6 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -14,6 +14,7 @@ import "@permit2/src/interfaces/IAllowanceTransfer.sol"; import "./Dispatcher.sol"; import {LibSwap} from "../lib/LibSwap.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; +import {OneTransferFromOnly} from "./OneTransferFromOnly.sol"; // ✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷ // ✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷ @@ -65,7 +66,13 @@ error TychoRouter__MessageValueMismatch(uint256 value, uint256 amount); error TychoRouter__InvalidDataLength(); error TychoRouter__UndefinedMinAmountOut(); -contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { +contract TychoRouter is + AccessControl, + Dispatcher, + Pausable, + ReentrancyGuard, + OneTransferFromOnly +{ IAllowanceTransfer public immutable permit2; IWETH private immutable _weth; @@ -87,7 +94,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { address indexed token, uint256 amount, address indexed receiver ); - constructor(address _permit2, address weth) { + constructor(address _permit2, address weth) OneTransferFromOnly(_permit2) { if (_permit2 == address(0) || weth == address(0)) { revert TychoRouter__AddressZero(); } @@ -130,6 +137,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { address receiver, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { + tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); return _splitSwapChecked( amountIn, tokenIn, @@ -187,6 +195,8 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { permit2.permit(msg.sender, permitSingle, signature); } + tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); + return _splitSwapChecked( amountIn, tokenIn, @@ -232,6 +242,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { address receiver, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { + tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); return _sequentialSwapChecked( amountIn, tokenIn, @@ -285,6 +296,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { permit2.permit(msg.sender, permitSingle, signature); } + tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); return _sequentialSwapChecked( amountIn, tokenIn, @@ -325,8 +337,14 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { bool wrapEth, bool unwrapEth, address receiver, + bool inTransferNeeded, + address fundsReceiver, bytes calldata swapData ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { + tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); + if (inTransferNeeded) { + _transfer(fundsReceiver); + } return _singleSwap( amountIn, tokenIn, @@ -379,7 +397,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard { if (tokenIn != address(0)) { permit2.permit(msg.sender, permitSingle, signature); } - + tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); return _singleSwap( amountIn, tokenIn, diff --git a/foundry/src/executors/UniswapV2Executor.sol b/foundry/src/executors/UniswapV2Executor.sol index dd04dd1..31b6db7 100644 --- a/foundry/src/executors/UniswapV2Executor.sol +++ b/foundry/src/executors/UniswapV2Executor.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.26; import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@uniswap-v2/contracts/interfaces/IUniswapV2Pair.sol"; -import "./TokenTransfer.sol"; error UniswapV2Executor__InvalidDataLength(); error UniswapV2Executor__InvalidTarget(); @@ -12,7 +11,7 @@ error UniswapV2Executor__InvalidFactory(); error UniswapV2Executor__InvalidInitCode(); error UniswapV2Executor__InvalidFee(); -contract UniswapV2Executor is IExecutor, TokenTransfer { +contract UniswapV2Executor is IExecutor { using SafeERC20 for IERC20; address public immutable factory; @@ -25,7 +24,7 @@ contract UniswapV2Executor is IExecutor, TokenTransfer { bytes32 _initCode, address _permit2, uint256 _feeBps - ) TokenTransfer(_permit2) { + ) { if (_factory == address(0)) { revert UniswapV2Executor__InvalidFactory(); } @@ -51,17 +50,23 @@ contract UniswapV2Executor is IExecutor, TokenTransfer { address target; address receiver; bool zeroForOne; - TransferType transferType; + bool transferNeeded; - (tokenIn, target, receiver, zeroForOne, transferType) = + (tokenIn, target, receiver, zeroForOne, transferNeeded) = _decodeData(data); _verifyPairAddress(target); calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne); - _transfer( - address(tokenIn), msg.sender, target, givenAmount, transferType - ); + + if (transferNeeded){ + if (tokenIn == address(0)) { + payable(target).transfer(givenAmount); + } else { + // slither-disable-next-line arbitrary-send-erc20 + tokenIn.safeTransferFrom(msg.sender, target, givenAmount); + } + } IUniswapV2Pair pool = IUniswapV2Pair(target); if (zeroForOne) { @@ -79,7 +84,7 @@ contract UniswapV2Executor is IExecutor, TokenTransfer { address target, address receiver, bool zeroForOne, - TransferType transferType + bool transferNeeded ) { if (data.length != 62) { @@ -89,7 +94,7 @@ contract UniswapV2Executor is IExecutor, TokenTransfer { target = address(bytes20(data[20:40])); receiver = address(bytes20(data[40:60])); zeroForOne = uint8(data[60]) > 0; - transferType = TransferType(uint8(data[61])); + transferNeeded = bool(data[61]); } function _getAmountOut(address target, uint256 amountIn, bool zeroForOne) diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index c1d570d..7585384 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -6,14 +6,14 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; import "@interfaces/ICallback.sol"; import {TokenTransfer} from "./TokenTransfer.sol"; +import {OneTransferFromOnly} from "../OneTransferFromOnly.sol"; error UniswapV3Executor__InvalidDataLength(); error UniswapV3Executor__InvalidFactory(); error UniswapV3Executor__InvalidTarget(); error UniswapV3Executor__InvalidInitCode(); -error UniswapV3Executor__InvalidTransferType(uint8 transferType); -contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer { +contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { using SafeERC20 for IERC20; uint160 private constant MIN_SQRT_RATIO = 4295128739; @@ -25,7 +25,7 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer { address private immutable self; constructor(address _factory, bytes32 _initCode, address _permit2) - TokenTransfer(_permit2) + OneTransferFromOnly(_permit2) { if (_factory == address(0)) { revert UniswapV3Executor__InvalidFactory(); @@ -51,7 +51,8 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer { address receiver, address target, bool zeroForOne, - TransferType transferType + bool inTransferNeeded, + bool inBetweenSwapsTransferNeeded ) = _decodeData(data); _verifyPairAddress(tokenIn, tokenOut, fee, target); @@ -60,8 +61,13 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer { int256 amount1; IUniswapV3Pool pool = IUniswapV3Pool(target); - bytes memory callbackData = - _makeV3CallbackData(tokenIn, tokenOut, fee, transferType); + bytes memory callbackData = _makeV3CallbackData( + tokenIn, + tokenOut, + fee, + inTransferNeeded, + inBetweenSwapsTransferNeeded + ); { (amount0, amount1) = pool.swap( @@ -98,12 +104,8 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer { address tokenIn = address(bytes20(msgData[132:152])); - // Transfer type does not exist - if (uint8(msgData[175]) > uint8(TransferType.NONE)) { - revert UniswapV3Executor__InvalidTransferType(uint8(msgData[175])); - } - - TransferType transferType = TransferType(uint8(msgData[175])); + bool inTransferNeeded = bool(msgData[175]); + bool inBetweenSwapsTransferNeeded = bool(msgData[176]); address sender = address(bytes20(msgData[176:196])); verifyCallback(msgData[132:]); @@ -111,7 +113,15 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer { uint256 amountOwed = amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta); - _transfer(tokenIn, sender, msg.sender, amountOwed, transferType); + if (inTransferNeeded) { + _transfer(msg.sender); + } else if (inBetweenSwapsTransferNeeded) { + if (tokenIn == address(0)) { + payable(msg.sender).transfer(amountOwed); + } else { + IERC20(tokenIn).safeTransfer(msg.sender, amountOwed); + } + } return abi.encode(amountOwed, tokenIn); } @@ -142,7 +152,8 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer { address receiver, address target, bool zeroForOne, - TransferType transferType + bool inTransferNeeded, + bool inBetweenSwapsTransferNeeded ) { if (data.length != 85) { @@ -154,17 +165,24 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer { receiver = address(bytes20(data[43:63])); target = address(bytes20(data[63:83])); zeroForOne = uint8(data[83]) > 0; - transferType = TransferType(uint8(data[84])); + inTransferNeeded = bool(data[84]); + inBetweenSwapsTransferNeeded = bool(data[85]); } function _makeV3CallbackData( address tokenIn, address tokenOut, uint24 fee, - TransferType transferType + bool inTransferNeeded, + bool inBetweenSwapsTransferNeeded ) internal view returns (bytes memory) { return abi.encodePacked( - tokenIn, tokenOut, fee, uint8(transferType), msg.sender + tokenIn, + tokenOut, + fee, + inTransferNeeded, + inBetweenSwapsTransferNeeded, + msg.sender ); } From 0f9af658468f0ae29d7e075bd68f8a07f88970b4 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Wed, 14 May 2025 18:00:19 +0100 Subject: [PATCH 02/22] feat: Support new transfer logic in encoding The transfer from the user into the router is supposed to happen in the router (we only support this in the executors for callback constrained protocols). This is necessary because of some security concerns that were found in the audit. This way we reduce the space of attack. - Refactored TransferOptimization not to handle TransferTypes anymore but just return bools. - Split get_transfer_type into get_transfers and get_in_between_transfer. Updates tests - Updated the strategies to use this - Updated function signatures to pass transfer_from and funds_receiver - Updated SwapEncoders to handle this - SplitSwapStrategy just assumes all tokens are sent to and from the router at all times Took 2 hours 46 minutes --- foundry/test/assets/calldata.txt | 56 ++-- src/encoding/evm/constants.rs | 11 +- .../evm/strategy_encoder/strategy_encoders.rs | 174 +++++++---- .../transfer_optimizations.rs | 278 ++++++------------ .../evm/swap_encoder/swap_encoders.rs | 99 ++++--- src/encoding/evm/tycho_encoders.rs | 13 +- src/encoding/models.rs | 26 +- 7 files changed, 318 insertions(+), 339 deletions(-) diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index 09af343..ea9d8d6 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -1,28 +1,28 @@ -test_uniswap_v3_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed000100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010500 -test_single_encoding_strategy_ekubo:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000071a0cb889707d426a7a386870a03bc70d1b069759805cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000000000000000000000000000000000 -test_uniswap_v3_uniswap_v3:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010000000000000000000000 -test_balancer_v2_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010300525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20105000000000000000000000000000000000000000000000000 -test_sequential_swap_strategy_encoder_no_permit2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20105000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000068402a3900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a44100000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000419facefe3089c4d8177dc12ace73e275369649112be2bead25fcd035707a50de67aed574499636214e89fd88bf2907096140c552cecf3a93305d37b8e922166e61c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006840296000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a368000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041488f1442a33f67d75f1c0ecf8c4787e26e497d41a006914d5dbccb7cdd4022256dc21c65ea07eba53897ebafe6e7186737b0aca604ca0425875429254ce3858c1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000 -test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006840296000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a36800000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410d2f0434c42a97db27f008ae4e52187ed01dc74853b13698650aef603f1ea6e8722bb06280aab52379efd2c4945019497abc7c87583f8c6e4f38a081677c0bb61b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000200525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20105000000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_no_permit2:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_single_swap_strategy_encoder_no_transfer_in:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006840296000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a36800000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041a8f9b660b644e089fade56f08c23e15ac3cc99137345ef8ce0c06bfeb2d0c36f1d32cfe9e03cb6527aae9d525dd5a47e07c8c712dd98bf964a95f3cca0811f8d1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330105cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000 -test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006840296000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a36800000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004187214fb9e717d84472b7ef79ec8c0c29a806a5ff6e6267dbebb06f9482d0e7be2247d4d2bcb423c91a47819b6130d7b1d436a344e6a1d0751778ffee57c8bff71c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010200692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000000000000000000000000 -test_single_encoding_strategy_curve_st_eth:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010005cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006840296000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a36800000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410d2f0434c42a97db27f008ae4e52187ed01dc74853b13698650aef603f1ea6e8722bb06280aab52379efd2c4945019497abc7c87583f8c6e4f38a081677c0bb61b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200020000000000000000000000000000 -test_single_encoding_strategy_curve:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000103cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be00000000000000000000000000000000000000000000000000000000000006840296000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a36800000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041a375087487c7481609a5e3ac4d7a493cc4749f4c16f23a17ca3cdbad6d816bd860f88a7bc4e1dff2cfa23bf80a82d65910fd0dfb660f9aea22c69795b8c04acb1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501020000000000000000000000000000 -test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006840296000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a36800000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041a8f9b660b644e089fade56f08c23e15ac3cc99137345ef8ce0c06bfeb2d0c36f1d32cfe9e03cb6527aae9d525dd5a47e07c8c712dd98bf964a95f3cca0811f8d1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006840296000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a36800000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004187214fb9e717d84472b7ef79ec8c0c29a806a5ff6e6267dbebb06f9482d0e7be2247d4d2bcb423c91a47819b6130d7b1d436a344e6a1d0751778ffee57c8bff71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950102006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400000006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000000000000000000 -test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006840296000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a36800000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004187214fb9e717d84472b7ef79ec8c0c29a806a5ff6e6267dbebb06f9482d0e7be2247d4d2bcb423c91a47819b6130d7b1d436a344e6a1d0751778ffee57c8bff71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400102006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80102005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000 -test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006840296000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a3680000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000410d2f0434c42a97db27f008ae4e52187ed01dc74853b13698650aef603f1ea6e8722bb06280aab52379efd2c4945019497abc7c87583f8c6e4f38a081677c0bb61b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950002005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950002005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010000000000000000000000000000000000000000000000000000000000 -test_uniswap_v3_curve:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000105cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000 -test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf00000000000000000000000000000000000000000000000000000000000006840296100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006818a36900000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041d129cab2cc52c54ea03cb937f9bb6ab52b6dbd445f917125e8c582e6685174d86135080d059adf0c0eec2e685a8e9801a263cc21097c9b68887db853ca9a7c651c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501020072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010500691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001053ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598003ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 -test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0105 -test_ekubo_encode_swap_multi:00ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 -test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c -test_encode_uniswap_v4_simple_swap:4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec70100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001 -test_single_encoding_strategy_maverick:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc201000000000000000000000000000000 -test_encode_maverick_v2:40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c671d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e00 \ No newline at end of file +test_uniswap_v3_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c0006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100 +test_single_encoding_strategy_ekubo:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000072a0cb889707d426a7a386870a03bc70d1b06975980000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c0000000000000000000000000000000000000000000000000000 +test_uniswap_v3_uniswap_v3:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100006a2e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc350100010000000000000000 +test_balancer_v2_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 +test_sequential_swap_strategy_encoder_no_permit2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004112ff786cc8a8d24dfe6871e6c581f898b84a73bf68e93825d00425d0e90a03da63d709c708de1e54427deac6eb71c6602528be1a0768868f453446afc04f00d01c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d2311933000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f90000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000418f3422d7328230aea76c4de1731793a8bd744961c9796297abefd7fe5e22820a73117fb461de9eee74d1644876084f0b1683d4916851df285fba8ae8f48cf6671c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007400720001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004110339de0a348f6dc0822b93a4b3764aabd9a7fdd3b248c3baae2a341158a1ff138941375145748d7a6f194808e5a68299882ef00b89bddb95f3d9215fe5db39f1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_no_permit2:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_swap_strategy_encoder_no_transfer_in:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004159eb2cc8eae51e324934272b75187fb7973da58e1fbb52fd1d7c5871995177e26dfd6f50a879b9e3c71295bc2e3ceba72e3293e1382b8057b6690f652c3d6e0a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006df62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000 +test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041220e558f9cb5c8b8e33d592acf1526fe2a56feceb2fc437fff2c443ecc27febc2bae93737bf02a9f65cafa3bc465d6bf96753549be5d1411aa8174f9bf85c1141c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010100006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000000000 +test_single_encoding_strategy_curve_st_eth:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004110339de0a348f6dc0822b93a4b3764aabd9a7fdd3b248c3baae2a341158a1ff138941375145748d7a6f194808e5a68299882ef00b89bddb95f3d9215fe5db39f1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_encoding_strategy_curve:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041ff461fe60fbd9ac8baec2452c4a242f4e4258cb54aa5df5a3cfa4c889be2897628c42ab59513d9aa4d491e22196979e3c1bd4637944f898decee9ae8596586bc1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 +test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004159eb2cc8eae51e324934272b75187fb7973da58e1fbb52fd1d7c5871995177e26dfd6f50a879b9e3c71295bc2e3ceba72e3293e1382b8057b6690f652c3d6e0a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684c57f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1fa0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000418a77e8497940ec9340946d582c7c1fc77ec54d7f2d6b682f2a86694a7836ff553c72e31bd305d158cf97fccf29391b0f7a92ff3dffc3279d09f7a4e4a27314921b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950101006f01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f5640000001006f01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000 +test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684c57f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1fa0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000418a77e8497940ec9340946d582c7c1fc77ec54d7f2d6b682f2a86694a7836ff553c72e31bd305d158cf97fccf29391b0f7a92ff3dffc3279d09f7a4e4a27314921b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b006f00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010001006f00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8010001005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000 +test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684c57f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1fa0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000411127f13839fe5565558bcbdbd7900f23e1374c99164598d4653eefb4ef66f7e85bd3112c15b9e6f3035119daee4c8b8a1220da90a594ed5eb8613892f8a0171e1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950001005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950001005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 +test_uniswap_v3_curve:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d7006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000 +test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684c57f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1fa000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000419731903580c1d9c9909aad47a91667359491e74c0e41a5aecfd40ff760a61a422d6694e613889897ab59341ea22116436db9f8267450b8af94e463d5402e700c1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021600525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001003ede3eca2a72b3aecc820e955b36f38437d013950072a0cb889707d426a7a386870a03bc70d1b069759800013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006df62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000 +test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0100 +test_ekubo_encode_swap_multi:0001ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 +test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c599010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c +test_encode_uniswap_v4_simple_swap:4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec7010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001 +test_single_encoding_strategy_maverick:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014cf6d2fe3e1b326114b07d22a6f6bb59e346c6700000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_encode_maverick_v2:40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c671d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e01 diff --git a/src/encoding/evm/constants.rs b/src/encoding/evm/constants.rs index 2777040..1a51fdf 100644 --- a/src/encoding/evm/constants.rs +++ b/src/encoding/evm/constants.rs @@ -34,11 +34,12 @@ pub static IN_TRANSFER_REQUIRED_PROTOCOLS: LazyLock> = Laz set }); -// The protocols here are a subset of the ones defined in IN_TRANSFER_REQUIRED_PROTOCOLS. The tokens -// can not be sent directly from the previous pool into a pool of this protocol. The tokens need to -// be sent to the router and only then transferred into the pool. This is the case for uniswap v3 -// because of the callback logic. The only way for this to work it would be to call the second swap -// during the callback of the first swap. This is currently not supported. +// The protocols here are a subset of the ones defined in IN_TRANSFER_REQUIRED_PROTOCOLS. The in +// transfer needs to be performed inside the callback logic. This means, the tokens can not be sent +// directly from the previous pool into a pool of this protocol. The tokens need to be sent to the +// router and only then transferred into the pool. This is the case for uniswap v3 because of the +// callback logic. The only way for this to work it would be to call the second swap during the +// callback of the first swap. This is currently not supported. pub static CALLBACK_CONSTRAINED_PROTOCOLS: LazyLock> = LazyLock::new(|| { let mut set = HashSet::new(); set.insert("uniswap_v3"); diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index a3f5a94..a740638 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -1,6 +1,6 @@ use std::{collections::HashSet, str::FromStr}; -use alloy_primitives::{aliases::U24, U256, U8}; +use alloy_primitives::{aliases::U24, Address, U256, U8}; use alloy_sol_types::SolValue; use tycho_common::Bytes; @@ -8,6 +8,7 @@ use crate::encoding::{ errors::EncodingError, evm::{ approvals::permit2::Permit2, + constants::CALLBACK_CONSTRAINED_PROTOCOLS, group_swaps::group_swaps, strategy_encoder::{ strategy_validators::{SequentialSwapValidator, SplitSwapValidator, SwapValidator}, @@ -58,7 +59,6 @@ impl SingleSwapStrategyEncoder { "singleSwap(uint256,address,address,uint256,bool,bool,address,bytes)".to_string(), ) }; - let permit2_is_active = permit2.is_some(); Ok(Self { permit2, selector, @@ -67,7 +67,6 @@ impl SingleSwapStrategyEncoder { transfer_optimization: TransferOptimization::new( chain.native_token()?, chain.wrapped_token()?, - permit2_is_active, token_in_already_in_router, router_address, ), @@ -125,16 +124,17 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { let swap_receiver = if !unwrap { solution.receiver.clone() } else { self.router_address.clone() }; - let transfer_type = self + let (mut transfer_from, mut funds_receiver, transfer) = self .transfer_optimization - .get_transfer_type(grouped_swap.clone(), solution.given_token.clone(), wrap, false); + .get_transfers(grouped_swap.clone(), wrap); let encoding_context = EncodingContext { receiver: swap_receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer_type: transfer_type.clone(), + transfer_from, + transfer, }; let mut grouped_protocol_data: Vec = vec![]; @@ -148,7 +148,19 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { .map_err(|_| EncodingError::FatalError("Invalid executor address".to_string()))?, grouped_protocol_data, ); - + if CALLBACK_CONSTRAINED_PROTOCOLS.contains( + &grouped_swaps[0] + .protocol_system + .as_str(), + ) { + // The first swap is from a callback constrained protocol. This means that the in + // transfer needs to happen at callback time and not before. + transfer_from = false; + funds_receiver = Address::ZERO.to_string(); + } + let funds_receiver = Address::from_str(&funds_receiver).map_err(|_| { + EncodingError::FatalError(format!("Invalid funds receiver address: {funds_receiver}")) + })?; let method_calldata = if let Some(permit2) = self.permit2.clone() { let (permit, signature) = permit2.get_permit( &self.router_address, @@ -164,6 +176,8 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, + transfer_from, + funds_receiver, permit, signature.as_bytes().to_vec(), swap_data, @@ -178,6 +192,8 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, + transfer_from, + funds_receiver, swap_data, ) .abi_encode() @@ -239,7 +255,6 @@ impl SequentialSwapStrategyEncoder { .to_string(), ) }; - let permit2_is_active = permit2.is_some(); Ok(Self { permit2, selector, @@ -251,7 +266,6 @@ impl SequentialSwapStrategyEncoder { transfer_optimization: TransferOptimization::new( chain.native_token()?, chain.wrapped_token()?, - permit2_is_active, token_in_already_in_router, router_address, ), @@ -292,6 +306,9 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { NativeAction::Unwrap => unwrap = true, } } + let (mut transfer_from, mut funds_receiver, transfer) = self + .transfer_optimization + .get_transfers(grouped_swaps[0].clone(), wrap); let mut swaps = vec![]; let mut next_in_between_swap_optimization_allowed = true; @@ -311,21 +328,21 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { .transfer_optimization .get_receiver(solution.receiver.clone(), next_swap)?; next_in_between_swap_optimization_allowed = next_swap_optimization; - let transfer_type = self - .transfer_optimization - .get_transfer_type( - grouped_swap.clone(), - solution.given_token.clone(), - wrap, - in_between_swap_optimization_allowed, - ); + + let in_between_transfer = if i == 0 { + transfer + } else { + self.transfer_optimization + .get_in_between_transfer(&protocol, in_between_swap_optimization_allowed) + }; let encoding_context = EncodingContext { receiver: swap_receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer_type: transfer_type.clone(), + transfer_from: if i == 0 { transfer_from } else { false }, + transfer: in_between_transfer, }; let mut grouped_protocol_data: Vec = vec![]; @@ -344,6 +361,19 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { swaps.push(swap_data); } + if CALLBACK_CONSTRAINED_PROTOCOLS.contains( + &grouped_swaps[0] + .protocol_system + .as_str(), + ) { + // The first swap is from a callback constrained protocol. This means that the in + // transfer needs to happen at callback time and not before. + transfer_from = false; + funds_receiver = Address::ZERO.to_string(); + } + let funds_receiver = Address::from_str(&funds_receiver).map_err(|_| { + EncodingError::FatalError(format!("Invalid funds receiver address: {funds_receiver}")) + })?; let encoded_swaps = ple_encode(swaps); let method_calldata = if let Some(permit2) = self.permit2.clone() { let (permit, signature) = permit2.get_permit( @@ -360,6 +390,8 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, + transfer_from, + funds_receiver, permit, signature.as_bytes().to_vec(), encoded_swaps, @@ -374,6 +406,8 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, + transfer_from, + funds_receiver, encoded_swaps, ) .abi_encode() @@ -435,7 +469,6 @@ impl SplitSwapStrategyEncoder { .to_string(), ) }; - let permit2_is_active = permit2.is_some(); Ok(Self { permit2, selector, @@ -447,7 +480,6 @@ impl SplitSwapStrategyEncoder { transfer_optimization: TransferOptimization::new( chain.native_token()?, chain.wrapped_token()?, - permit2_is_active, token_in_already_in_router, router_address, ), @@ -553,16 +585,17 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { } else { self.router_address.clone() }; - let transfer_type = self + let transfer = self .transfer_optimization - .get_transfer_type(grouped_swap.clone(), solution.given_token.clone(), wrap, false); + .get_in_between_transfer(&protocol, false); let encoding_context = EncodingContext { receiver: swap_receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer_type: transfer_type.clone(), + transfer_from: false, + transfer, }; let mut grouped_protocol_data: Vec = vec![]; @@ -757,6 +790,8 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver + "0000000000000000000000000000000000000000000000000000000000000001", // transfer from + "000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11", // funds receiver ] .join(""); @@ -772,13 +807,13 @@ mod tests { "a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one - "02", // transfer type + "00", // transfer false "0000000000000000000000000000", // padding )); let hex_calldata = encode(&calldata); - assert_eq!(hex_calldata[..456], expected_input); - assert_eq!(hex_calldata[1224..], expected_swap); + assert_eq!(hex_calldata[..584], expected_input); + assert_eq!(hex_calldata[1352..], expected_swap); if expected_amount.is_some() & slippage.is_some() & checked_amount.is_none() { // only write to file for 1 test case write_calldata_to_file( @@ -847,7 +882,9 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000100", // offset of swap bytes + "0000000000000000000000000000000000000000000000000000000000000001", // transfer from + "000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11", // funds receiver + "0000000000000000000000000000000000000000000000000000000000000140", // offset of swap bytes "0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding // Swap data @@ -856,8 +893,8 @@ mod tests { "a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one - "01", // transfer type - "0000000000000000000000000000", // padding + "00", // transfer false + "0000000000000000000000000000", // padding ] .join(""); @@ -929,7 +966,9 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000100", // offset of swap bytes + "0000000000000000000000000000000000000000000000000000000000000000", // transfer from + "0000000000000000000000000000000000000000000000000000000000000000", // funds receiver + "0000000000000000000000000000000000000000000000000000000000000140", // offset of swap bytes "0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding // Swap data @@ -938,7 +977,7 @@ mod tests { "a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one - "00", // transfer type + "01", // transfer true "0000000000000000000000000000", // padding ] .join(""); @@ -1199,7 +1238,9 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000100", /* length ple + "0000000000000000000000000000000000000000000000000000000000000001", /* transfer from */ + "000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940", /* funds receiver */ + "0000000000000000000000000000000000000000000000000000000000000140", /* length ple * encode */ "00000000000000000000000000000000000000000000000000000000000000a8", // swap 1 @@ -1209,7 +1250,7 @@ mod tests { "bb2b8038a1640196fbe3e38816f3e67cba72d940", // component id "004375dff511095cc5a197a54140a24efef3a416", // receiver (next pool) "00", // zero to one - "01", // transfer type + "00", // transfer false // swap 2 "0052", // swap length "5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address @@ -1217,7 +1258,7 @@ mod tests { "004375dff511095cc5a197a54140a24efef3a416", // component id "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver (final user) "01", // zero to one - "05", // transfer type - None + "00", // transfer false "000000000000000000000000000000000000000000000000", // padding )); @@ -1323,12 +1364,14 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap action "0000000000000000000000000000000000000000000000000000000000000000", // unwrap action "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver + "0000000000000000000000000000000000000000000000000000000000000000", // transfer from + "0000000000000000000000000000000000000000000000000000000000000000", // funds receiver ] .join(""); let expected_swaps = [ - "00000000000000000000000000000000000000000000000000000000000000d6", // length of ple encoded swaps without padding - "0069", // ple encoded swaps + "00000000000000000000000000000000000000000000000000000000000000d8", // length of ple encoded swaps without padding + "006a", // ple encoded swaps "2e234dae75c793f67a35089c9d99245e1c58470b", // executor address "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token out @@ -1336,8 +1379,9 @@ mod tests { "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id "01", // zero2one - "02", // transfer type - "0069", // ple encoded swaps + "01", // transfer from true + "00", // transfer false + "006a", // ple encoded swaps "2e234dae75c793f67a35089c9d99245e1c58470b", // executor address "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token out @@ -1345,13 +1389,14 @@ mod tests { "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id "00", // zero2one - "00", // transfer type - "00000000000000000000", // padding + "00", // transfer from false + "01", // transfer true + "0000000000000000", // padding ] .join(""); - assert_eq!(hex_calldata[..456], expected_input); - assert_eq!(hex_calldata[1224..], expected_swaps); + assert_eq!(hex_calldata[..584], expected_input); + assert_eq!(hex_calldata[1352..], expected_swaps); write_calldata_to_file("test_sequential_strategy_cyclic_swap", hex_calldata.as_str()); } @@ -2040,8 +2085,8 @@ mod tests { ] .join(""); let expected_swaps = [ - "0000000000000000000000000000000000000000000000000000000000000139", // length of ple encoded swaps without padding - "006e", // ple encoded swaps + "000000000000000000000000000000000000000000000000000000000000013b", // length of ple encoded swaps without padding + "006f", // ple encoded swaps "00", // token in index "01", // token out index "999999", // split @@ -2052,8 +2097,9 @@ mod tests { "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id "01", // zero2one - "02", // transfer type - "006e", // ple encoded swaps + "00", // transfer from false + "01", // transfer true + "006f", // ple encoded swaps "00", // token in index "01", // token out index "000000", // split @@ -2064,7 +2110,8 @@ mod tests { "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id "01", // zero2one - "02", // transfer type + "00", // transfer from false + "01", // transfer true "0057", // ple encoded swaps "01", // token in index "00", // token out index @@ -2074,8 +2121,8 @@ mod tests { "b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id, "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one - "00", // transfer type - "00000000000000" // padding + "01", // transfer true + "0000000000" // padding ] .join(""); assert_eq!(hex_calldata[..520], expected_input); @@ -2204,7 +2251,7 @@ mod tests { .join(""); let expected_swaps = [ - "0000000000000000000000000000000000000000000000000000000000000139", // length of ple encoded swaps without padding + "000000000000000000000000000000000000000000000000000000000000013b", // length of ple encoded swaps without padding "0057", // ple encoded swaps "00", // token in index "01", // token out index @@ -2214,8 +2261,8 @@ mod tests { "b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "01", // zero2one - "02", // transfer type - "006e", // ple encoded swaps + "01", // transfer true + "006f", // ple encoded swaps "01", // token in index "00", // token out index "999999", // split @@ -2226,8 +2273,9 @@ mod tests { "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id "00", // zero2one - "00", // transfer type - "006e", // ple encoded swaps + "00", // transfer from false + "01", // transfer true + "006f", // ple encoded swaps "01", // token in index "00", // token out index "000000", // split @@ -2238,8 +2286,9 @@ mod tests { "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id "00", // zero2one - "00", // transfer type - "00000000000000" // padding + "00", // transfer from false + "01", // transfer true + "0000000000" // padding ] .join(""); @@ -2600,6 +2649,8 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver + "0000000000000000000000000000000000000000000000000000000000000000", // transfer from + "0000000000000000000000000000000000000000000000000000000000000000", // funds receiver ] .join(""); @@ -2608,14 +2659,15 @@ mod tests { let expected_swaps = String::from(concat!( // length of ple encoded swaps without padding - "0000000000000000000000000000000000000000000000000000000000000086", + "0000000000000000000000000000000000000000000000000000000000000087", // Swap data header "f62849f9a0b5bf2913b396098f7c7019b51a820a", // executor address // Protocol data "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // group token in "6982508145454ce325ddbe47a25d4ec3d2311933", // group token in "00", // zero2one - "02", // transfer type (transfer to router) + "01", // transfer from true + "00", // transfer false "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver // First pool params "0000000000000000000000000000000000000000", // intermediary token (ETH) @@ -2625,13 +2677,13 @@ mod tests { "6982508145454ce325ddbe47a25d4ec3d2311933", // intermediary token (PEPE) "0061a8", // fee "0001f4", // tick spacing - "0000000000000000000000000000000000000000000000000000" // padding + "00000000000000000000000000000000000000000000000000" // padding )); let hex_calldata = encode(&calldata); - assert_eq!(hex_calldata[..456], expected_input); - assert_eq!(hex_calldata[1224..], expected_swaps); + assert_eq!(hex_calldata[..584], expected_input); + assert_eq!(hex_calldata[1352..], expected_swaps); write_calldata_to_file( "test_single_encoding_strategy_usv4_grouped_swap", hex_calldata.as_str(), diff --git a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs index 62bfca1..986e335 100644 --- a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs +++ b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs @@ -8,7 +8,6 @@ use crate::encoding::{ constants::{CALLBACK_CONSTRAINED_PROTOCOLS, IN_TRANSFER_REQUIRED_PROTOCOLS}, group_swaps::SwapGroup, }, - models::TransferType, }; /// A struct that defines how the tokens will be transferred into the given pool given the solution. @@ -16,7 +15,6 @@ use crate::encoding::{ pub struct TransferOptimization { native_token: Bytes, wrapped_token: Bytes, - permit2: bool, token_in_already_in_router: bool, router_address: Bytes, } @@ -25,69 +23,65 @@ impl TransferOptimization { pub fn new( native_token: Bytes, wrapped_token: Bytes, - permit2: bool, token_in_already_in_router: bool, router_address: Bytes, ) -> Self { TransferOptimization { native_token, wrapped_token, - permit2, token_in_already_in_router, router_address, } } - /// Returns the transfer method that should be used for the given swap and solution. - pub fn get_transfer_type( - &self, - swap: SwapGroup, - given_token: Bytes, - wrap: bool, - in_between_swap_optimization: bool, - ) -> TransferType { + /// Returns the information about the necessary transfers. + /// Returns (bool, String, bool) where: + /// * bool: true if a transfer from the user is needed, false otherwise (it might use regular + /// approvals or permit2) + /// * String: the address to transfer from (if not needed it's the zero address) + /// * bool: true if the tokens are already in the router and there only needs to be a transfer + /// from the router into the pool + pub fn get_transfers(&self, swap: SwapGroup, wrap: bool) -> (bool, String, bool) { + let zero_address = Bytes::from([0u8; 20]).to_string(); let in_transfer_required: bool = IN_TRANSFER_REQUIRED_PROTOCOLS.contains(&swap.protocol_system.as_str()); - let is_first_swap = swap.token_in == given_token; - if swap.token_in == self.native_token { // Funds are already in router. All protocols currently take care of native transfers. - TransferType::None + (false, zero_address, false) } else if (swap.token_in == self.wrapped_token) && wrap { - // Wrapping already happened in the router so we can just use a normal transfer. - TransferType::TransferToProtocol - } else if is_first_swap { - if in_transfer_required { - if self.token_in_already_in_router { - // Transfer from router to pool. - TransferType::TransferToProtocol - } else if self.permit2 { - // Transfer from swapper to pool using permit2. - TransferType::TransferPermit2ToProtocol - } else { - // Transfer from swapper to pool. - TransferType::TransferFromToProtocol - } - // in transfer is not necessary for these protocols. Only make a transfer if the - // tokens are not already in the router - } else if !self.token_in_already_in_router { - if self.permit2 { - // Transfer from swapper to router using permit2. - TransferType::TransferPermit2ToRouter - } else { - // Transfer from swapper to router. - TransferType::TransferFromToRouter - } + // Wrapping already happened in the router so, we just do a normal transfer. + (false, zero_address, true) + } else if in_transfer_required { + if self.token_in_already_in_router { + // Transfer from router to pool. + (false, zero_address, true) } else { - TransferType::None + // Transfer from swapper to pool + (true, swap.swaps[0].component.id.clone(), false) } - // all other swaps - } else if !in_transfer_required || in_between_swap_optimization { - // funds should already be in the router or in the next pool - TransferType::None + // in transfer is not necessary for these protocols. Only make a transfer if the + // tokens are not already in the router + } else if !self.token_in_already_in_router { + // Transfer from swapper to router using permit2. + (true, self.router_address.to_string(), false) } else { - TransferType::TransferToProtocol + (false, zero_address, false) + } + } + + pub fn get_in_between_transfer( + &self, + protocol_system: &str, + in_between_swap_optimization: bool, + ) -> bool { + let in_transfer_required: bool = IN_TRANSFER_REQUIRED_PROTOCOLS.contains(protocol_system); + + if !in_transfer_required || in_between_swap_optimization { + // funds should already be in the router or in the next pool + false + } else { + true } } @@ -155,146 +149,68 @@ mod tests { Bytes::from("0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f") } - #[test] - fn test_first_swap_transfer_from_permit2() { + fn zero_address() -> String { + Bytes::from([0u8; 20]).to_string() + } + + #[rstest] + // WETH -(univ2)-> DAI we expect a transfer from the user to the protocol + #[case(weth(), "uniswap_v2".to_string(), false, false, true, "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", false)] + // Native token swap. No transfer is needed + #[case(eth(), "uniswap_v2".to_string(),false, false, false, zero_address(), false)] + // ETH -(wrap)-> WETH -(univ2)-> DAI. Only a transfer from the router into the protocol is + // needed + #[case(weth(), "uniswap_v2".to_string(),true, false, false, zero_address(), true)] + // USDC -(univ2)-> DAI and the tokens are already in the router. Only a transfer from the router + // to the protocol is needed + #[case(usdc(), "uniswap_v2".to_string(),false, true, false, zero_address(), true)] + // USDC -(curve)-> DAI and the tokens are already in the router. No transfer is needed + #[case(usdc(), "vm:curve".to_string(),false, true, false, zero_address(), false)] + fn test_get_transfers( + #[case] token_in: Bytes, + #[case] protocol: String, + #[case] wrap: bool, + #[case] token_in_already_in_router: bool, + #[case] expected_transfer_from: bool, + #[case] expected_receiver: String, + #[case] expected_transfer: bool, + ) { // The swap token is the same as the given token, which is not the native token - let swap = SwapGroup { - protocol_system: "uniswap_v2".to_string(), - token_in: weth(), + let swaps = vec![Swap { + component: ProtocolComponent { + protocol_system: "uniswap_v2".to_string(), + id: "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11".to_string(), + ..Default::default() + }, + token_in: token_in.clone(), token_out: dai(), split: 0f64, - swaps: vec![], - }; - let optimization = TransferOptimization::new(eth(), weth(), true, false, router_address()); - let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false); - assert_eq!(transfer_method, TransferType::TransferPermit2ToProtocol); + }]; + let swap = + SwapGroup { protocol_system: protocol, token_in, token_out: dai(), split: 0f64, swaps }; + let optimization = + TransferOptimization::new(eth(), weth(), token_in_already_in_router, router_address()); + let (transfer_from, receiver, transfer) = optimization.get_transfers(swap.clone(), wrap); + assert_eq!(transfer_from, expected_transfer_from); + assert_eq!(receiver, expected_receiver); + assert_eq!(transfer, expected_transfer); } - #[test] - fn test_first_swap_transfer_from() { - // The swap token is the same as the given token, which is not the native token - let swap = SwapGroup { - protocol_system: "uniswap_v2".to_string(), - token_in: weth(), - token_out: dai(), - split: 0f64, - swaps: vec![], - }; - let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address()); - let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false); - assert_eq!(transfer_method, TransferType::TransferFromToProtocol); - } - - #[test] - fn test_first_swap_native() { - // The swap token is the same as the given token, and it's the native token. - // No transfer action is needed. - let swap = SwapGroup { - protocol_system: "uniswap_v2".to_string(), - token_in: eth(), - token_out: dai(), - split: 0f64, - swaps: vec![], - }; - let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address()); - let transfer_method = optimization.get_transfer_type(swap.clone(), eth(), false, false); - assert_eq!(transfer_method, TransferType::None); - } - - #[test] - fn test_first_swap_wrapped() { - // The swap token is NOT the same as the given token, but we are wrapping. - // Since the swap's token in is the wrapped token - this is the first swap. - let swap = SwapGroup { - protocol_system: "uniswap_v2".to_string(), - token_in: weth(), - token_out: dai(), - split: 0f64, - swaps: vec![], - }; - let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address()); - let transfer_method = optimization.get_transfer_type(swap.clone(), eth(), true, false); - assert_eq!(transfer_method, TransferType::TransferToProtocol); - } - - #[test] - fn test_not_first_swap() { - // The swap token is NOT the same as the given token, and we are NOT wrapping. - // Thus, this is not the first swap. - let swap = SwapGroup { - protocol_system: "uniswap_v2".to_string(), - token_in: usdc(), - token_out: dai(), - split: 0f64, - swaps: vec![], - }; - let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address()); - let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false); - assert_eq!(transfer_method, TransferType::TransferToProtocol); - } - - #[test] - fn test_not_first_swap_funds_in_router() { - // Not the first swap and the protocol requires the funds to be in the router (which they - // already are, so the transfer type is None) - let swap = SwapGroup { - protocol_system: "vm:curve".to_string(), - token_in: usdc(), - token_out: dai(), - split: 0f64, - swaps: vec![], - }; - let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address()); - let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false); - assert_eq!(transfer_method, TransferType::None); - } - - #[test] - fn test_not_first_swap_in_between_swap_optimization() { - // Not the first swap and the in between swaps are optimized. The funds should already be in - // the next pool or in the router - let swap = SwapGroup { - protocol_system: "uniswap_v2".to_string(), - token_in: usdc(), - token_out: dai(), - split: 0f64, - swaps: vec![], - }; - let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address()); - let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, true); - assert_eq!(transfer_method, TransferType::None); - } - - #[test] - fn test_first_swap_tokens_already_in_router_optimization() { - // It is the first swap, tokens are already in the router and the protocol requires the - // transfer in - let swap = SwapGroup { - protocol_system: "uniswap_v2".to_string(), - token_in: usdc(), - token_out: dai(), - split: 0f64, - swaps: vec![], - }; - let optimization = TransferOptimization::new(eth(), weth(), false, true, router_address()); - let transfer_method = optimization.get_transfer_type(swap.clone(), usdc(), false, false); - assert_eq!(transfer_method, TransferType::TransferToProtocol); - } - - #[test] - fn test_first_swap_tokens_already_in_router_no_transfer_needed_optimization() { - // It is the first swap, tokens are already in the router and the protocol does not require - // the transfer in - let swap = SwapGroup { - protocol_system: "vm:curve".to_string(), - token_in: usdc(), - token_out: dai(), - split: 0f64, - swaps: vec![], - }; - let optimization = TransferOptimization::new(eth(), weth(), false, true, router_address()); - let transfer_method = optimization.get_transfer_type(swap.clone(), usdc(), false, false); - assert_eq!(transfer_method, TransferType::None); + #[rstest] + // tokens need to be transferred into the pool + #[case("uniswap_v2", false, true)] + // tokens are already in the pool (optimization) + #[case("uniswap_v2", true, false)] + // tokens are already in the router and don't need a transfer + #[case("vm:curve", false, false)] + fn test_get_in_between_transfers( + #[case] protocol: &str, + #[case] in_between_swap_optimization: bool, + #[case] expected_transfer: bool, + ) { + let optimization = TransferOptimization::new(eth(), weth(), false, router_address()); + let transfer = optimization.get_in_between_transfer(protocol, in_between_swap_optimization); + assert_eq!(transfer, expected_transfer); } fn receiver() -> Bytes { @@ -319,7 +235,7 @@ mod tests { #[case] expected_receiver: Bytes, #[case] expected_optimization: bool, ) { - let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address()); + let optimization = TransferOptimization::new(eth(), weth(), false, router_address()); let next_swap = if protocol.is_none() { None diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index 5e74855..74cc375 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -66,7 +66,7 @@ impl SwapEncoder for UniswapV2SwapEncoder { component_id, bytes_to_address(&encoding_context.receiver)?, zero_to_one, - (encoding_context.transfer_type as u8).to_be_bytes(), + encoding_context.transfer, ); Ok(args.abi_encode_packed()) @@ -129,7 +129,8 @@ impl SwapEncoder for UniswapV3SwapEncoder { bytes_to_address(&encoding_context.receiver)?, component_id, zero_to_one, - (encoding_context.transfer_type as u8).to_be_bytes(), + encoding_context.transfer_from, + encoding_context.transfer, ); Ok(args.abi_encode_packed()) @@ -206,7 +207,8 @@ impl SwapEncoder for UniswapV4SwapEncoder { group_token_in_address, group_token_out_address, zero_to_one, - (encoding_context.transfer_type as u8).to_be_bytes(), + encoding_context.transfer_from, + encoding_context.transfer, bytes_to_address(&encoding_context.receiver)?, pool_params, ); @@ -282,7 +284,7 @@ impl SwapEncoder for BalancerV2SwapEncoder { component_id, bytes_to_address(&encoding_context.receiver)?, approval_needed, - (encoding_context.transfer_type as u8).to_be_bytes(), + encoding_context.transfer, ); Ok(args.abi_encode_packed()) } @@ -344,7 +346,8 @@ impl SwapEncoder for EkuboSwapEncoder { let mut encoded = vec![]; if encoding_context.group_token_in == swap.token_in { - encoded.extend((encoding_context.transfer_type as u8).to_be_bytes()); + encoded.extend((encoding_context.transfer_from as u8).to_be_bytes()); + encoded.extend((encoding_context.transfer as u8).to_be_bytes()); encoded.extend(bytes_to_address(&encoding_context.receiver)?); encoded.extend(bytes_to_address(&swap.token_in)?); } @@ -575,7 +578,7 @@ impl SwapEncoder for CurveSwapEncoder { i.to_be_bytes::<1>(), j.to_be_bytes::<1>(), approval_needed, - (encoding_context.transfer_type as u8).to_be_bytes(), + encoding_context.transfer, bytes_to_address(&encoding_context.receiver)?, ); @@ -620,7 +623,7 @@ impl SwapEncoder for MaverickV2SwapEncoder { bytes_to_address(&swap.token_in)?, component_id, bytes_to_address(&encoding_context.receiver)?, - (encoding_context.transfer_type as u8).to_be_bytes(), + encoding_context.transfer, ); Ok(args.abi_encode_packed()) } @@ -645,7 +648,7 @@ mod tests { }; use super::*; - use crate::encoding::{evm::utils::write_calldata_to_file, models::TransferType}; + use crate::encoding::evm::utils::write_calldata_to_file; mod uniswap_v2 { use super::*; @@ -670,7 +673,8 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_type: TransferType::TransferToProtocol, + transfer: true, + transfer_from: false, }; let encoder = UniswapV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -693,8 +697,8 @@ mod tests { "0000000000000000000000000000000000000001", // zero for one "00", - // transfer type (transfer) - "00", + // transfer true + "01", )) ); } @@ -728,7 +732,8 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_type: TransferType::TransferToProtocol, + transfer: true, + transfer_from: false, }; let encoder = UniswapV3SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -755,8 +760,10 @@ mod tests { "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // zero for one "00", - // transfer type (transfer) + // transfer from false "00", + // transfer true + "01", )) ); } @@ -790,7 +797,8 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_type: TransferType::None, + transfer: false, + transfer_from: false, }; let encoder = BalancerV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -819,8 +827,8 @@ mod tests { "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // approval needed "01", - // transfer type - "05" + // transfer false + "00", )) ); write_calldata_to_file("test_encode_balancer_v2", hex_swap.as_str()); @@ -864,7 +872,8 @@ mod tests { group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_type: TransferType::TransferToProtocol, + transfer: true, + transfer_from: false, }; let encoder = UniswapV4SwapEncoder::new( String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"), @@ -886,8 +895,10 @@ mod tests { "dac17f958d2ee523a2206206994597c13d831ec7", // zero for one "01", - // transfer type + // transfer from false "00", + // transfer true + "01", // receiver "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // pool params: @@ -935,7 +946,8 @@ mod tests { group_token_in: group_token_in.clone(), // Token out is the same as the group token out group_token_out: token_out.clone(), - transfer_type: TransferType::TransferToProtocol, + transfer: true, + transfer_from: false, }; let encoder = UniswapV4SwapEncoder::new( @@ -978,7 +990,8 @@ mod tests { router_address: Some(router_address.clone()), group_token_in: usde_address.clone(), group_token_out: wbtc_address.clone(), - transfer_type: TransferType::TransferToProtocol, + transfer: true, + transfer_from: false, }; // Setup - First sequence: USDE -> USDT @@ -1056,8 +1069,10 @@ mod tests { "2260fac5e5542a773aa44fbcfedf7c193bc2c599", // zero for one "01", - // transfer type + // transfer from false "00", + // transfer true + "01", // receiver "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // pool params: @@ -1113,7 +1128,8 @@ mod tests { group_token_out: token_out.clone(), exact_out: false, router_address: Some(Bytes::default()), - transfer_type: TransferType::TransferToProtocol, + transfer: true, + transfer_from: false, }; let encoder = @@ -1129,8 +1145,10 @@ mod tests { assert_eq!( hex_swap, concat!( - // transfer type + // transfer from false "00", + // transfer true + "01", // receiver "ca4f73fe97d0b987a0d12b39bbd562c779bab6f6", // group token in @@ -1159,7 +1177,8 @@ mod tests { group_token_out: group_token_out.clone(), exact_out: false, router_address: Some(Bytes::default()), - transfer_type: TransferType::TransferToProtocol, + transfer: true, + transfer_from: false, }; let first_swap = Swap { @@ -1209,8 +1228,10 @@ mod tests { combined_hex, // transfer type concat!( - // transfer type + // transfer from false "00", + // transfer true + "01", // receiver "ca4f73fe97d0b987a0d12b39bbd562c779bab6f6", // group token in @@ -1355,7 +1376,8 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_type: TransferType::None, + transfer: false, + transfer_from: false, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1385,8 +1407,8 @@ mod tests { "01", // approval needed "01", - // transfer type - "05", + // transfer false + "00", // receiver, "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" )) @@ -1425,7 +1447,8 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_type: TransferType::None, + transfer: false, + transfer_from: false, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1455,8 +1478,8 @@ mod tests { "00", // approval needed "01", - // transfer type - "05", + // transfer false + "00", // receiver "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" )) @@ -1496,7 +1519,8 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_type: TransferType::None, + transfer: false, + transfer_from: false, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1535,8 +1559,8 @@ mod tests { "01", // approval needed "01", - // transfer type - "05", + // transfer false + "00", // receiver "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" )) @@ -1567,7 +1591,8 @@ mod tests { router_address: Some(Bytes::default()), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_type: TransferType::TransferToProtocol, + transfer: true, + transfer_from: false, }; let encoder = MaverickV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -1590,8 +1615,8 @@ mod tests { "14Cf6D2Fe3E1B326114b07d22A6F6bb59e346c67", // receiver "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", - // transfer from router to protocol - "00", + // transfer true + "01", )) .to_lowercase() ); diff --git a/src/encoding/evm/tycho_encoders.rs b/src/encoding/evm/tycho_encoders.rs index 1eb3390..b377477 100644 --- a/src/encoding/evm/tycho_encoders.rs +++ b/src/encoding/evm/tycho_encoders.rs @@ -13,7 +13,7 @@ use crate::encoding::{ }, swap_encoder::swap_encoder_registry::SwapEncoderRegistry, }, - models::{Chain, EncodingContext, NativeAction, Solution, Transaction, TransferType}, + models::{Chain, EncodingContext, NativeAction, Solution, Transaction}, strategy_encoder::StrategyEncoder, tycho_encoder::TychoEncoder, }; @@ -279,7 +279,8 @@ impl TychoExecutorEncoder { router_address: None, group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer_type: TransferType::TransferToProtocol, + transfer: true, + transfer_from: false, }; let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?; grouped_protocol_data.extend(protocol_data); @@ -1059,8 +1060,8 @@ mod tests { "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // zero for one "00", - // transfer type - "00", + // transfer true + "01", )) ); } @@ -1147,8 +1148,10 @@ mod tests { "6982508145454ce325ddbe47a25d4ec3d2311933", // zero for one "00", - // transfer type + // transfer from false "00", + // transfer true + "01", // receiver "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // first pool intermediary token (ETH) diff --git a/src/encoding/models.rs b/src/encoding/models.rs index 052df36..d85ed63 100644 --- a/src/encoding/models.rs +++ b/src/encoding/models.rs @@ -96,27 +96,6 @@ pub struct Transaction { pub data: Vec, } -/// Represents the type of transfer to be performed into the pool. -/// -/// # Fields -/// -/// * `TransferToProtocol`: Transfer the token from the router into the protocol. -/// * `TransferFromToProtocol`: Transfer the token from the sender to the protocol. -/// * `TransferPermit2ToProtocol`: Transfer the token from the sender to the protocol using Permit2. -/// * `TransferFromToRouter`: Transfer the token from the sender to the router. -/// * `TransferPermit2ToRouter`: Transfer the token from the sender to the router using Permit2. -/// * `None`: No transfer is needed. Tokens are already in the pool. -#[repr(u8)] -#[derive(Clone, Debug, PartialEq)] -pub enum TransferType { - TransferToProtocol = 0, - TransferFromToProtocol = 1, - TransferPermit2ToProtocol = 2, - TransferFromToRouter = 3, - TransferPermit2ToRouter = 4, - None = 5, -} - /// Represents necessary attributes for encoding an order. /// /// # Fields @@ -127,6 +106,8 @@ pub enum TransferType { /// solution does not require router address. /// * `group_token_in`: Token to be used as the input for the group swap. /// * `group_token_out`: Token to be used as the output for the group swap. +/// * `transfer_from`: true if the solution requires a transfer from the user to the router or pool. +/// * `transfer`: true if the solution requires a transfer from the router to the pool. #[derive(Clone, Debug)] pub struct EncodingContext { pub receiver: Bytes, @@ -134,7 +115,8 @@ pub struct EncodingContext { pub router_address: Option, pub group_token_in: Bytes, pub group_token_out: Bytes, - pub transfer_type: TransferType, + pub transfer_from: bool, + pub transfer: bool, } #[derive(Clone, PartialEq, Eq, Hash)] From 27dfde3118a76320b6c51958cae23e0136324802 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Wed, 14 May 2025 20:42:19 -0400 Subject: [PATCH 03/22] feat: Support new transfer logic in all executors TODO: - Fix failing tests - Remove permit2 from initialization of contracts --- foundry/src/OneTransferFromOnly.sol | 7 +- foundry/src/TychoRouter.sol | 46 ++++++- foundry/src/executors/BalancerV2Executor.sol | 21 +--- foundry/src/executors/CurveExecutor.sol | 23 +--- foundry/src/executors/EkuboExecutor.sol | 52 ++++---- foundry/src/executors/MaverickV2Executor.sol | 24 ++-- foundry/src/executors/UniswapV2Executor.sol | 8 +- foundry/src/executors/UniswapV3Executor.sol | 34 +++-- foundry/src/executors/UniswapV4Executor.sol | 80 ++++++------ .../test/TychoRouterProtocolIntegration.t.sol | 24 +++- foundry/test/TychoRouterSequentialSwap.t.sol | 74 +++++------ foundry/test/TychoRouterSingleSwap.t.sol | 55 ++++---- foundry/test/TychoRouterSplitSwap.t.sol | 106 +++++++--------- foundry/test/TychoRouterTestSetup.sol | 13 +- .../test/executors/BalancerV2Executor.t.sol | 22 +--- foundry/test/executors/CurveExecutor.t.sol | 9 +- foundry/test/executors/EkuboExecutor.t.sol | 8 +- .../test/executors/MaverickV2Executor.t.sol | 44 ++----- .../test/executors/UniswapV2Executor.t.sol | 117 +++--------------- .../test/executors/UniswapV3Executor.t.sol | 27 ++-- .../test/executors/UniswapV4Executor.t.sol | 36 +++--- foundry/test/executors/UniswapV4Utils.sol | 10 +- 22 files changed, 378 insertions(+), 462 deletions(-) diff --git a/foundry/src/OneTransferFromOnly.sol b/foundry/src/OneTransferFromOnly.sol index 4cc26f0..78d29bc 100644 --- a/foundry/src/OneTransferFromOnly.sol +++ b/foundry/src/OneTransferFromOnly.sol @@ -27,7 +27,7 @@ contract OneTransferFromOnly { function tstoreTransferFromInfo( address tokenIn, - address amountIn, + uint256 amountIn, bool isPermit2, address sender ) internal { @@ -40,10 +40,7 @@ contract OneTransferFromOnly { } } - function _transfer(address receiver) - // we could pass the amount and address too and compare to what is in the slots? - internal - { + function _transfer(address receiver) internal { address tokenIn; uint256 amount; bool isPermit2; diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 2d193d6..655a6a0 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -122,6 +122,8 @@ contract TychoRouter is * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. + * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -135,9 +137,14 @@ contract TychoRouter is bool unwrapEth, uint256 nTokens, address receiver, + bool transferFromRequired, + address tokenInReceiver, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); + if (transferFromRequired) { + _transfer(tokenInReceiver); + } return _splitSwapChecked( amountIn, tokenIn, @@ -173,6 +180,8 @@ contract TychoRouter is * @param receiver The address to receive the output tokens. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. + * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -188,14 +197,18 @@ contract TychoRouter is address receiver, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, + bool transferFromRequired, + address tokenInReceiver, bytes calldata swaps ) external payable whenNotPaused nonReentrant returns (uint256 amountOut) { // For native ETH, assume funds already in our router. Else, handle approval. if (tokenIn != address(0)) { permit2.permit(msg.sender, permitSingle, signature); } - tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); + if (transferFromRequired) { + _transfer(tokenInReceiver); + } return _splitSwapChecked( amountIn, @@ -228,6 +241,8 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. + * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -240,9 +255,14 @@ contract TychoRouter is bool wrapEth, bool unwrapEth, address receiver, + bool transferFromRequired, + address tokenInReceiver, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); + if (transferFromRequired) { + _transfer(tokenInReceiver); + } return _sequentialSwapChecked( amountIn, tokenIn, @@ -275,6 +295,8 @@ contract TychoRouter is * @param receiver The address to receive the output tokens. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. + * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -289,6 +311,8 @@ contract TychoRouter is address receiver, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, + bool transferFromRequired, + address tokenInReceiver, bytes calldata swaps ) external payable whenNotPaused nonReentrant returns (uint256 amountOut) { // For native ETH, assume funds already in our router. Else, handle approval. @@ -297,6 +321,9 @@ contract TychoRouter is } tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); + if (transferFromRequired) { + _transfer(tokenInReceiver); + } return _sequentialSwapChecked( amountIn, tokenIn, @@ -325,6 +352,8 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. + * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. * @param swapData Encoded swap details. * * @return amountOut The total amount of the output token received by the receiver. @@ -337,13 +366,13 @@ contract TychoRouter is bool wrapEth, bool unwrapEth, address receiver, - bool inTransferNeeded, - address fundsReceiver, + bool transferFromRequired, + address tokenInReceiver, bytes calldata swapData ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); - if (inTransferNeeded) { - _transfer(fundsReceiver); + if (transferFromRequired) { + _transfer(tokenInReceiver); } return _singleSwap( amountIn, @@ -377,6 +406,8 @@ contract TychoRouter is * @param receiver The address to receive the output tokens. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. + * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. * @param swapData Encoded swap details. * * @return amountOut The total amount of the output token received by the receiver. @@ -391,6 +422,8 @@ contract TychoRouter is address receiver, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, + bool transferFromRequired, + address tokenInReceiver, bytes calldata swapData ) external payable whenNotPaused nonReentrant returns (uint256 amountOut) { // For native ETH, assume funds already in our router. Else, handle approval. @@ -398,6 +431,9 @@ contract TychoRouter is permit2.permit(msg.sender, permitSingle, signature); } tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); + if (transferFromRequired) { + _transfer(tokenInReceiver); + } return _singleSwap( amountIn, tokenIn, diff --git a/foundry/src/executors/BalancerV2Executor.sol b/foundry/src/executors/BalancerV2Executor.sol index 00b772a..016163b 100644 --- a/foundry/src/executors/BalancerV2Executor.sol +++ b/foundry/src/executors/BalancerV2Executor.sol @@ -10,16 +10,15 @@ import { import {IAsset} from "@balancer-labs/v2-interfaces/contracts/vault/IAsset.sol"; // slither-disable-next-line solc-version import {IVault} from "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol"; -import {TokenTransfer} from "./TokenTransfer.sol"; error BalancerV2Executor__InvalidDataLength(); -contract BalancerV2Executor is IExecutor, TokenTransfer { +contract BalancerV2Executor is IExecutor { using SafeERC20 for IERC20; address private constant VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; - constructor(address _permit2) TokenTransfer(_permit2) {} + constructor(address _permit2) {} // slither-disable-next-line locked-ether function swap(uint256 givenAmount, bytes calldata data) @@ -33,19 +32,9 @@ contract BalancerV2Executor is IExecutor, TokenTransfer { bytes32 poolId, address receiver, bool needsApproval, - TransferType transferType + bool transferNeeded ) = _decodeData(data); - _transfer( - address(tokenIn), - msg.sender, - // Receiver can never be the pool, since the pool expects funds in the router contract - // Thus, this call will only ever be used to transfer funds from the user into the router. - address(this), - givenAmount, - transferType - ); - if (needsApproval) { // slither-disable-next-line unused-return tokenIn.forceApprove(VAULT, type(uint256).max); @@ -82,7 +71,7 @@ contract BalancerV2Executor is IExecutor, TokenTransfer { bytes32 poolId, address receiver, bool needsApproval, - TransferType transferType + bool transferNeeded ) { if (data.length != 94) { @@ -94,6 +83,6 @@ contract BalancerV2Executor is IExecutor, TokenTransfer { poolId = bytes32(data[40:72]); receiver = address(bytes20(data[72:92])); needsApproval = uint8(data[92]) > 0; - transferType = TransferType(uint8(data[93])); + transferNeeded = uint8(data[93]) > 0; } } diff --git a/foundry/src/executors/CurveExecutor.sol b/foundry/src/executors/CurveExecutor.sol index e10a213..f953a63 100644 --- a/foundry/src/executors/CurveExecutor.sol +++ b/foundry/src/executors/CurveExecutor.sol @@ -3,7 +3,6 @@ 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(); @@ -35,14 +34,12 @@ interface CryptoPoolETH { // slither-disable-end naming-convention } -contract CurveExecutor is IExecutor, TokenTransfer { +contract CurveExecutor is IExecutor { using SafeERC20 for IERC20; address public immutable nativeToken; - constructor(address _nativeToken, address _permit2) - TokenTransfer(_permit2) - { + constructor(address _nativeToken, address _permit2) { if (_nativeToken == address(0)) { revert CurveExecutor__AddressZero(); } @@ -65,20 +62,10 @@ contract CurveExecutor is IExecutor, TokenTransfer { int128 i, int128 j, bool tokenApprovalNeeded, - TransferType transferType, + bool transferNeeded, // TODO remove this with the encoding address receiver ) = _decodeData(data); - _transfer( - tokenIn, - msg.sender, - // Receiver can never be the pool, since the pool expects funds in the router contract - // Thus, this call will only ever be used to transfer funds from the user into the router. - address(this), - amountIn, - transferType - ); - if (tokenApprovalNeeded && tokenIn != nativeToken) { // slither-disable-next-line unused-return IERC20(tokenIn).forceApprove(address(pool), type(uint256).max); @@ -134,7 +121,7 @@ contract CurveExecutor is IExecutor, TokenTransfer { int128 i, int128 j, bool tokenApprovalNeeded, - TransferType transferType, + bool transferNeeded, address receiver ) { @@ -145,7 +132,7 @@ contract CurveExecutor is IExecutor, TokenTransfer { i = int128(uint128(uint8(data[61]))); j = int128(uint128(uint8(data[62]))); tokenApprovalNeeded = data[63] != 0; - transferType = TransferType(uint8(data[64])); + transferNeeded = data[64] != 0; receiver = address(bytes20(data[65:85])); } diff --git a/foundry/src/executors/EkuboExecutor.sol b/foundry/src/executors/EkuboExecutor.sol index 25d40ab..692626d 100644 --- a/foundry/src/executors/EkuboExecutor.sol +++ b/foundry/src/executors/EkuboExecutor.sol @@ -11,14 +11,14 @@ import {SafeTransferLib} from "@solady/utils/SafeTransferLib.sol"; import {LibBytes} from "@solady/utils/LibBytes.sol"; import {Config, EkuboPoolKey} from "@ekubo/types/poolKey.sol"; import {MAX_SQRT_RATIO, MIN_SQRT_RATIO} from "@ekubo/types/sqrtRatio.sol"; -import {TokenTransfer} from "./TokenTransfer.sol"; +import "../OneTransferFromOnly.sol"; contract EkuboExecutor is IExecutor, ILocker, IPayer, ICallback, - TokenTransfer + OneTransferFromOnly { error EkuboExecutor__InvalidDataLength(); error EkuboExecutor__CoreOnly(); @@ -32,7 +32,9 @@ contract EkuboExecutor is bytes4 constant LOCKED_SELECTOR = 0xb45a3c0e; // locked(uint256) bytes4 constant PAY_CALLBACK_SELECTOR = 0x599d0714; // payCallback(uint256,address) - constructor(address _core, address _permit2) TokenTransfer(_permit2) { + constructor(address _core, address _permit2) + OneTransferFromOnly(_permit2) + { core = ICore(_core); } @@ -44,13 +46,8 @@ contract EkuboExecutor is if (data.length < 93) revert EkuboExecutor__InvalidDataLength(); // amountIn must be at most type(int128).MAX - calculatedAmount = uint256( - _lock( - bytes.concat( - bytes16(uint128(amountIn)), bytes20(msg.sender), data - ) - ) - ); + calculatedAmount = + uint256(_lock(bytes.concat(bytes16(uint128(amountIn)), data))); } function handleCallback(bytes calldata raw) @@ -126,10 +123,11 @@ contract EkuboExecutor is int128 nextAmountIn = int128(uint128(bytes16(swapData[0:16]))); uint128 tokenInDebtAmount = uint128(nextAmountIn); address sender = address(bytes20(swapData[16:36])); - uint8 transferType = uint8(swapData[36]); + bool transferFromNeeded = (swapData[36] != 0); + bool transferNeeded = (swapData[37] != 0); - address receiver = address(bytes20(swapData[37:57])); - address tokenIn = address(bytes20(swapData[57:77])); + address receiver = address(bytes20(swapData[38:58])); + address tokenIn = address(bytes20(swapData[58:78])); address nextTokenIn = tokenIn; @@ -163,7 +161,7 @@ contract EkuboExecutor is offset += HOP_BYTE_LEN; } - _pay(tokenIn, tokenInDebtAmount, sender, transferType); + _pay(tokenIn, tokenInDebtAmount, transferFromNeeded, transferNeeded); core.withdraw(nextTokenIn, receiver, uint128(nextAmountIn)); return nextAmountIn; } @@ -171,8 +169,8 @@ contract EkuboExecutor is function _pay( address token, uint128 amount, - address sender, - uint8 transferType + bool transferFromNeeded, + bool transferNeeded ) internal { address target = address(core); @@ -186,11 +184,11 @@ contract EkuboExecutor is mstore(free, shl(224, 0x0c11dedd)) mstore(add(free, 4), token) mstore(add(free, 36), shl(128, amount)) - mstore(add(free, 52), shl(96, sender)) - mstore(add(free, 72), shl(248, transferType)) + mstore(add(free, 52), shl(248, transferFromNeeded)) + mstore(add(free, 53), shl(248, transferNeeded)) - // 4 (selector) + 32 (token) + 16 (amount) + 20 (sender) + 1 (transferType) = 73 - if iszero(call(gas(), target, 0, free, 73, 0, 0)) { + // 4 (selector) + 32 (token) + 16 (amount) + 1 (transferFromNeeded) + 1 (transferNeeded) = 54 + if iszero(call(gas(), target, 0, free, 54, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } @@ -201,9 +199,17 @@ contract EkuboExecutor is function _payCallback(bytes calldata payData) internal { address token = address(bytes20(payData[12:32])); // This arg is abi-encoded uint128 amount = uint128(bytes16(payData[32:48])); - address sender = address(bytes20(payData[48:68])); - TransferType transferType = TransferType(uint8(payData[68])); - _transfer(token, sender, address(core), amount, transferType); + bool transferFromNeeded = (payData[48] != 0); + bool transferNeeded = (payData[49] != 0); + if (transferFromNeeded) { + _transfer(msg.sender); + } else if (transferNeeded) { + if (token == address(0)) { + payable(msg.sender).transfer(amount); + } else { + IERC20(token).transfer(msg.sender, amount); + } + } } // To receive withdrawals from Core diff --git a/foundry/src/executors/MaverickV2Executor.sol b/foundry/src/executors/MaverickV2Executor.sol index caf8ff0..b2dfabe 100644 --- a/foundry/src/executors/MaverickV2Executor.sol +++ b/foundry/src/executors/MaverickV2Executor.sol @@ -9,12 +9,12 @@ error MaverickV2Executor__InvalidDataLength(); error MaverickV2Executor__InvalidTarget(); error MaverickV2Executor__InvalidFactory(); -contract MaverickV2Executor is IExecutor, TokenTransfer { +contract MaverickV2Executor is IExecutor { using SafeERC20 for IERC20; address public immutable factory; - constructor(address _factory, address _permit2) TokenTransfer(_permit2) { + constructor(address _factory, address _permit2) { if (_factory == address(0)) { revert MaverickV2Executor__InvalidFactory(); } @@ -30,9 +30,9 @@ contract MaverickV2Executor is IExecutor, TokenTransfer { address target; address receiver; IERC20 tokenIn; - TransferType transferType; + bool transferNeeded; - (tokenIn, target, receiver, transferType) = _decodeData(data); + (tokenIn, target, receiver, transferNeeded) = _decodeData(data); _verifyPairAddress(target); IMaverickV2Pool pool = IMaverickV2Pool(target); @@ -47,9 +47,15 @@ contract MaverickV2Executor is IExecutor, TokenTransfer { tickLimit: tickLimit }); - _transfer( - address(tokenIn), msg.sender, target, givenAmount, transferType - ); + if (transferNeeded) { + if (address(tokenIn) == address(0)) { + payable(target).transfer(givenAmount); + } else { + // slither-disable-next-line arbitrary-send-erc20 + tokenIn.safeTransferFrom(msg.sender, target, givenAmount); + } + } + // slither-disable-next-line unused-return (, calculatedAmount) = pool.swap(receiver, swapParams, ""); } @@ -61,7 +67,7 @@ contract MaverickV2Executor is IExecutor, TokenTransfer { IERC20 inToken, address target, address receiver, - TransferType transferType + bool transferNeeded ) { if (data.length != 61) { @@ -70,7 +76,7 @@ contract MaverickV2Executor is IExecutor, TokenTransfer { inToken = IERC20(address(bytes20(data[0:20]))); target = address(bytes20(data[20:40])); receiver = address(bytes20(data[40:60])); - transferType = TransferType(uint8(data[60])); + transferNeeded = (data[60] != 0); } function _verifyPairAddress(address target) internal view { diff --git a/foundry/src/executors/UniswapV2Executor.sol b/foundry/src/executors/UniswapV2Executor.sol index 31b6db7..d1f25d9 100644 --- a/foundry/src/executors/UniswapV2Executor.sol +++ b/foundry/src/executors/UniswapV2Executor.sol @@ -59,8 +59,8 @@ contract UniswapV2Executor is IExecutor { calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne); - if (transferNeeded){ - if (tokenIn == address(0)) { + if (transferNeeded) { + if (address(tokenIn) == address(0)) { payable(target).transfer(givenAmount); } else { // slither-disable-next-line arbitrary-send-erc20 @@ -93,8 +93,8 @@ contract UniswapV2Executor is IExecutor { inToken = IERC20(address(bytes20(data[0:20]))); target = address(bytes20(data[20:40])); receiver = address(bytes20(data[40:60])); - zeroForOne = uint8(data[60]) > 0; - transferNeeded = bool(data[61]); + zeroForOne = data[60] != 0; + transferNeeded = data[61] != 0; } function _getAmountOut(address target, uint256 amountIn, bool zeroForOne) diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index 7585384..23ecc27 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -51,8 +51,8 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { address receiver, address target, bool zeroForOne, - bool inTransferNeeded, - bool inBetweenSwapsTransferNeeded + bool transferFromNeeded, + bool transferNeeded ) = _decodeData(data); _verifyPairAddress(tokenIn, tokenOut, fee, target); @@ -62,11 +62,7 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { IUniswapV3Pool pool = IUniswapV3Pool(target); bytes memory callbackData = _makeV3CallbackData( - tokenIn, - tokenOut, - fee, - inTransferNeeded, - inBetweenSwapsTransferNeeded + tokenIn, tokenOut, fee, transferFromNeeded, transferNeeded ); { @@ -104,8 +100,8 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { address tokenIn = address(bytes20(msgData[132:152])); - bool inTransferNeeded = bool(msgData[175]); - bool inBetweenSwapsTransferNeeded = bool(msgData[176]); + bool transferFromNeeded = msgData[175] != 0; + bool transferNeeded = msgData[176] != 0; address sender = address(bytes20(msgData[176:196])); verifyCallback(msgData[132:]); @@ -113,9 +109,9 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { uint256 amountOwed = amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta); - if (inTransferNeeded) { + if (transferFromNeeded) { _transfer(msg.sender); - } else if (inBetweenSwapsTransferNeeded) { + } else if (transferNeeded) { if (tokenIn == address(0)) { payable(msg.sender).transfer(amountOwed); } else { @@ -152,8 +148,8 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { address receiver, address target, bool zeroForOne, - bool inTransferNeeded, - bool inBetweenSwapsTransferNeeded + bool transferFromNeeded, + bool transferNeeded ) { if (data.length != 85) { @@ -165,23 +161,23 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { receiver = address(bytes20(data[43:63])); target = address(bytes20(data[63:83])); zeroForOne = uint8(data[83]) > 0; - inTransferNeeded = bool(data[84]); - inBetweenSwapsTransferNeeded = bool(data[85]); + transferFromNeeded = uint8(data[84]) > 0; + transferNeeded = uint8(data[85]) > 0; } function _makeV3CallbackData( address tokenIn, address tokenOut, uint24 fee, - bool inTransferNeeded, - bool inBetweenSwapsTransferNeeded + bool transferFromNeeded, + bool transferNeeded ) internal view returns (bytes memory) { return abi.encodePacked( tokenIn, tokenOut, fee, - inTransferNeeded, - inBetweenSwapsTransferNeeded, + transferFromNeeded, + transferNeeded, msg.sender ); } diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index 9b878ad..0d00ce9 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.26; import "@interfaces/IExecutor.sol"; import {ICallback} from "@interfaces/ICallback.sol"; -import {TokenTransfer} from "./TokenTransfer.sol"; import { IERC20, SafeERC20 @@ -23,6 +22,7 @@ import {IUnlockCallback} from import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol"; +import "../OneTransferFromOnly.sol"; error UniswapV4Executor__InvalidDataLength(); error UniswapV4Executor__NotPoolManager(); @@ -37,7 +37,7 @@ contract UniswapV4Executor is IExecutor, IUnlockCallback, ICallback, - TokenTransfer + OneTransferFromOnly { using SafeERC20 for IERC20; using CurrencyLibrary for Currency; @@ -57,7 +57,7 @@ contract UniswapV4Executor is } constructor(IPoolManager _poolManager, address _permit2) - TokenTransfer(_permit2) + OneTransferFromOnly(_permit2) { poolManager = _poolManager; _self = address(this); @@ -82,7 +82,8 @@ contract UniswapV4Executor is address tokenIn, address tokenOut, bool zeroForOne, - TransferType transferType, + bool transferFromNeeded, + bool transferNeeded, address receiver, UniswapV4Executor.UniswapV4Pool[] memory pools ) = _decodeData(data); @@ -100,8 +101,8 @@ contract UniswapV4Executor is key, zeroForOne, amountIn, - msg.sender, - transferType, + transferFromNeeded, + transferNeeded, receiver, bytes("") ); @@ -123,8 +124,8 @@ contract UniswapV4Executor is currencyIn, path, amountIn, - msg.sender, - transferType, + transferFromNeeded, + transferNeeded, receiver ); } @@ -142,24 +143,26 @@ contract UniswapV4Executor is address tokenIn, address tokenOut, bool zeroForOne, - TransferType transferType, + bool transferFromNeeded, + bool transferNeeded, address receiver, UniswapV4Pool[] memory pools ) { - if (data.length < 88) { + if (data.length < 89) { revert UniswapV4Executor__InvalidDataLength(); } tokenIn = address(bytes20(data[0:20])); tokenOut = address(bytes20(data[20:40])); zeroForOne = (data[40] != 0); - transferType = TransferType(uint8(data[41])); - receiver = address(bytes20(data[42:62])); + transferFromNeeded = (data[41] != 0); + transferNeeded = (data[42] != 0); + receiver = address(bytes20(data[43:63])); - uint256 poolsLength = (data.length - 62) / 26; // 26 bytes per pool object + uint256 poolsLength = (data.length - 63) / 26; // 26 bytes per pool object pools = new UniswapV4Pool[](poolsLength); - bytes memory poolsData = data[62:]; + bytes memory poolsData = data[63:]; uint256 offset = 0; for (uint256 i = 0; i < poolsLength; i++) { address intermediaryToken; @@ -239,8 +242,8 @@ contract UniswapV4Executor is * @param poolKey The key of the pool to swap in. * @param zeroForOne Whether the swap is from token0 to token1 (true) or vice versa (false). * @param amountIn The amount of tokens to swap in. - * @param sender The address of the sender. - * @param transferType The type of transfer in to use. + * @param transferFromNeeded Whether to transferFrom input tokens into the core contract from the swapper's wallet . + * @param transferNeeded Whether to transfer input tokens into the core contract from the router contract * @param receiver The address of the receiver. * @param hookData Additional data for hook contracts. */ @@ -248,8 +251,8 @@ contract UniswapV4Executor is PoolKey memory poolKey, bool zeroForOne, uint128 amountIn, - address sender, - TransferType transferType, + bool transferFromNeeded, + bool transferNeeded, address receiver, bytes calldata hookData ) external returns (uint128) { @@ -262,7 +265,7 @@ contract UniswapV4Executor is if (amount > amountIn) { revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount); } - _settle(currencyIn, amount, sender, transferType); + _settle(currencyIn, amount, transferFromNeeded, transferNeeded); Currency currencyOut = zeroForOne ? poolKey.currency1 : poolKey.currency0; @@ -275,16 +278,16 @@ contract UniswapV4Executor is * @param currencyIn The currency of the input token. * @param path The path to swap along. * @param amountIn The amount of tokens to swap in. - * @param sender The address of the sender. - * @param transferType The type of transfer in to use. + * @param transferFromNeeded Whether to transferFrom input tokens into the core contract from the swapper's wallet . + * @param transferNeeded Whether to transfer input tokens into the core contract from the router contract * @param receiver The address of the receiver. */ function swapExactInput( Currency currencyIn, PathKey[] calldata path, uint128 amountIn, - address sender, - TransferType transferType, + bool transferFromNeeded, + bool transferNeeded, address receiver ) external returns (uint128) { uint128 amountOut = 0; @@ -315,7 +318,7 @@ contract UniswapV4Executor is if (amount > amountIn) { revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount); } - _settle(currencyIn, amount, sender, transferType); + _settle(currencyIn, amount, transferFromNeeded, transferNeeded); _take( swapCurrencyIn, // at the end of the loop this is actually currency out @@ -387,15 +390,17 @@ contract UniswapV4Executor is * @dev The implementing contract must ensure that the `payer` is a secure address. * @param currency The currency to settle. * @param amount The amount to send. - * @param sender The address of the payer. - * @param transferType The type of transfer to use. + * @param transferFromNeeded Whether to manually transferFrom input tokens into the + * core contract from the swapper. + * @param transferNeeded Whether to manually transfer input tokens into the + * core contract from the router. * @dev Returns early if the amount is 0. */ function _settle( Currency currency, uint256 amount, - address sender, - TransferType transferType + bool transferFromNeeded, + bool transferNeeded ) internal { if (amount == 0) return; poolManager.sync(currency); @@ -403,13 +408,18 @@ contract UniswapV4Executor is // slither-disable-next-line unused-return poolManager.settle{value: amount}(); } else { - _transfer( - Currency.unwrap(currency), - sender, - address(poolManager), - amount, - transferType - ); + if (transferFromNeeded) { + // transferFrom swapper's wallet into the core contract + _transfer(msg.sender); + } else if (transferNeeded) { + address tokenIn = Currency.unwrap(currency); + // transfer from router contract into the core contract + if (tokenIn == address(0)) { + payable(msg.sender).transfer(amount); + } else { + IERC20(tokenIn).safeTransfer(msg.sender, amount); + } + } // slither-disable-next-line unused-return poolManager.settle(); } diff --git a/foundry/test/TychoRouterProtocolIntegration.t.sol b/foundry/test/TychoRouterProtocolIntegration.t.sol index 04af1f0..e1cd732 100644 --- a/foundry/test/TychoRouterProtocolIntegration.t.sol +++ b/foundry/test/TychoRouterProtocolIntegration.t.sol @@ -26,7 +26,8 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { USDE_ADDR, USDT_ADDR, true, - TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL, + true, // permit2 transferFrom to protocol + false, // transfer to protocol ALICE, pools ); @@ -44,6 +45,8 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { ALICE, permitSingle, signature, + false, + address(0), swap ); @@ -74,7 +77,8 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { USDE_ADDR, WBTC_ADDR, true, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL, + true, // permit2 transferFrom to protocol + false, // transfer to protocol ALICE, pools ); @@ -83,7 +87,16 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { encodeSingleSwap(address(usv4Executor), protocolData); tychoRouter.singleSwap( - amountIn, USDE_ADDR, WBTC_ADDR, 118280, false, false, ALICE, swap + amountIn, + USDE_ADDR, + WBTC_ADDR, + 118280, + false, + false, + ALICE, + false, + address(0), + swap ); assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), 118281); @@ -262,7 +275,8 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { ALICE, DAI_WETH_USV3, zeroForOne, - TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL + true, // permit2 transferFrom to protocol + false // transfer to protocol ); bytes memory swap = encodeSingleSwap(address(usv3Executor), protocolData); @@ -277,6 +291,8 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { ALICE, permitSingle, signature, + false, + address(0), swap ); diff --git a/foundry/test/TychoRouterSequentialSwap.t.sol b/foundry/test/TychoRouterSequentialSwap.t.sol index 1d44076..7037e80 100644 --- a/foundry/test/TychoRouterSequentialSwap.t.sol +++ b/foundry/test/TychoRouterSequentialSwap.t.sol @@ -8,25 +8,21 @@ import "./executors/UniswapV4Utils.sol"; import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol"; contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { - function _getSequentialSwaps(bool permit2) - internal - view - returns (bytes[] memory) - { + function _getSequentialSwaps() internal view returns (bytes[] memory) { // Trade 1 WETH for USDC through DAI with 2 swaps on Uniswap V2 // 1 WETH -> DAI -> USDC // (univ2) (univ2) - TokenTransfer.TransferType transferType = permit2 - ? TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL - : TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL; - bytes[] memory swaps = new bytes[](2); // WETH -> DAI swaps[0] = encodeSequentialSwap( address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, transferType + WETH_ADDR, + WETH_DAI_POOL, + DAI_USDC_POOL, // receiver (direct to next pool) + false, + false // transfer to protocol from router ) ); @@ -38,7 +34,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { DAI_USDC_POOL, ALICE, true, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + false // transfer to protocol from router ) ); return swaps; @@ -55,7 +51,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { bytes memory signature ) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn); - bytes[] memory swaps = _getSequentialSwaps(true); + bytes[] memory swaps = _getSequentialSwaps(); tychoRouter.sequentialSwapPermit2( amountIn, WETH_ADDR, @@ -66,6 +62,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { ALICE, permitSingle, signature, + true, + WETH_DAI_POOL, pleEncode(swaps) ); @@ -82,7 +80,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn); - bytes[] memory swaps = _getSequentialSwaps(false); + bytes[] memory swaps = _getSequentialSwaps(); tychoRouter.sequentialSwap( amountIn, WETH_ADDR, @@ -91,6 +89,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, + WETH_DAI_POOL, pleEncode(swaps) ); @@ -107,7 +107,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn); - bytes[] memory swaps = _getSequentialSwaps(false); + bytes[] memory swaps = _getSequentialSwaps(); vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector); tychoRouter.sequentialSwap( amountIn, @@ -117,6 +117,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, + WETH_DAI_POOL, pleEncode(swaps) ); } @@ -129,7 +131,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn - 1); - bytes[] memory swaps = _getSequentialSwaps(false); + bytes[] memory swaps = _getSequentialSwaps(); vm.expectRevert(); tychoRouter.sequentialSwap( amountIn, @@ -139,6 +141,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, + WETH_DAI_POOL, pleEncode(swaps) ); } @@ -154,7 +158,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { bytes memory signature ) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn); - bytes[] memory swaps = _getSequentialSwaps(true); + bytes[] memory swaps = _getSequentialSwaps(); uint256 minAmountOut = 3000 * 1e18; @@ -175,6 +179,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { ALICE, permitSingle, signature, + true, + WETH_DAI_POOL, pleEncode(swaps) ); vm.stopPrank(); @@ -202,24 +208,14 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { swaps[0] = encodeSequentialSwap( address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, - WETH_DAI_POOL, - tychoRouterAddr, - false, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, true ) ); // DAI -> USDC swaps[1] = encodeSequentialSwap( address(usv2Executor), - encodeUniswapV2Swap( - DAI_ADDR, - DAI_USDC_POOL, - ALICE, - true, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL - ) + encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, ALICE, true, true) ); uint256 amountOut = tychoRouter.sequentialSwapPermit2{value: amountIn}( @@ -232,6 +228,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { ALICE, emptyPermitSingle, "", + true, + tychoRouterAddr, pleEncode(swaps) ); uint256 expectedAmount = 2005810530; @@ -262,11 +260,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { swaps[0] = encodeSequentialSwap( address(usv2Executor), encodeUniswapV2Swap( - USDC_ADDR, - DAI_USDC_POOL, - tychoRouterAddr, - false, - TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL + USDC_ADDR, DAI_USDC_POOL, tychoRouterAddr, false, false ) ); @@ -274,11 +268,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { swaps[1] = encodeSequentialSwap( address(usv2Executor), encodeUniswapV2Swap( - DAI_ADDR, - WETH_DAI_POOL, - tychoRouterAddr, - true, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, true ) ); @@ -292,6 +282,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { ALICE, permitSingle, signature, + true, + DAI_USDC_POOL, pleEncode(swaps) ); @@ -315,7 +307,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3, true, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + false, + true ); bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap( @@ -324,7 +317,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3_2, false, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + false, // permit2 transferFrom to protocol + true // transfer to protocol ); bytes[] memory swaps = new bytes[](2); diff --git a/foundry/test/TychoRouterSingleSwap.t.sol b/foundry/test/TychoRouterSingleSwap.t.sol index bf49fbd..84b452e 100644 --- a/foundry/test/TychoRouterSingleSwap.t.sol +++ b/foundry/test/TychoRouterSingleSwap.t.sol @@ -26,7 +26,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL + false // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -42,6 +42,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { ALICE, permitSingle, signature, + true, // transferFrom to WETH_DAI_POOL + WETH_DAI_POOL, // receiver of input tokens swap ); @@ -67,7 +69,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL + false // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -82,6 +84,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, + WETH_DAI_POOL, swap ); @@ -103,20 +107,24 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes memory protocolData = encodeUniswapV2Swap( - WETH_ADDR, - WETH_DAI_POOL, - ALICE, - false, - TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL - ); + bytes memory protocolData = + encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, false); bytes memory swap = encodeSingleSwap(address(usv2Executor), protocolData); vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector); tychoRouter.singleSwap( - amountIn, WETH_ADDR, DAI_ADDR, 0, false, false, ALICE, swap + amountIn, + WETH_ADDR, + DAI_ADDR, + 0, + false, + false, + ALICE, + true, + WETH_DAI_POOL, + swap ); } @@ -134,7 +142,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL + false // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -150,6 +158,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, + WETH_DAI_POOL, swap ); } @@ -169,7 +179,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL + false // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -192,6 +202,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, + WETH_DAI_POOL, swap ); } @@ -213,13 +225,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { sigDeadline: 0 }); - bytes memory protocolData = encodeUniswapV2Swap( - WETH_ADDR, - WETH_DAI_POOL, - ALICE, - false, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL - ); + bytes memory protocolData = + encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, true); bytes memory swap = encodeSingleSwap(address(usv2Executor), protocolData); @@ -234,6 +241,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { ALICE, emptyPermitSingle, "", + true, + tychoRouterAddr, swap ); uint256 expectedAmount = 2018817438608734439722; @@ -257,11 +266,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { ) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn); bytes memory protocolData = encodeUniswapV2Swap( - DAI_ADDR, - WETH_DAI_POOL, - tychoRouterAddr, - true, - TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL + DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, false ); bytes memory swap = @@ -277,6 +282,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { ALICE, permitSingle, signature, + true, // transferFrom to WETH_DAI_POOL + WETH_DAI_POOL, // receiver of input tokens swap ); diff --git a/foundry/test/TychoRouterSplitSwap.t.sol b/foundry/test/TychoRouterSplitSwap.t.sol index 417b350..91f845a 100644 --- a/foundry/test/TychoRouterSplitSwap.t.sol +++ b/foundry/test/TychoRouterSplitSwap.t.sol @@ -8,11 +8,7 @@ import "./executors/UniswapV4Utils.sol"; import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol"; contract TychoRouterSplitSwapTest is TychoRouterTestSetup { - function _getSplitSwaps(bool permit2) - private - view - returns (bytes[] memory) - { + function _getSplitSwaps() private view returns (bytes[] memory) { // Trade 1 WETH for USDC through DAI and WBTC with 4 swaps on Uniswap V2 // -> DAI -> // 1 WETH USDC @@ -20,10 +16,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { // (univ2) (univ2) bytes[] memory swaps = new bytes[](4); - TokenTransfer.TransferType inTransferType = permit2 - ? TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL - : TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL; - // WETH -> WBTC (60%) swaps[0] = encodeSplitSwap( uint8(0), @@ -31,11 +23,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { (0xffffff * 60) / 100, // 60% address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, - WETH_WBTC_POOL, - tychoRouterAddr, - false, - inTransferType + WETH_ADDR, WETH_WBTC_POOL, tychoRouterAddr, false, true ) ); // WBTC -> USDC @@ -44,13 +32,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint8(2), uint24(0), address(usv2Executor), - encodeUniswapV2Swap( - WBTC_ADDR, - USDC_WBTC_POOL, - ALICE, - true, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL - ) + encodeUniswapV2Swap(WBTC_ADDR, USDC_WBTC_POOL, ALICE, true, true) ); // WETH -> DAI swaps[2] = encodeSplitSwap( @@ -59,7 +41,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint24(0), address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, inTransferType + WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, true ) ); @@ -69,13 +51,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint8(2), uint24(0), address(usv2Executor), - encodeUniswapV2Swap( - DAI_ADDR, - DAI_USDC_POOL, - ALICE, - true, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL - ) + encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, ALICE, true, true) ); return swaps; @@ -85,10 +61,9 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { // Trade 1 WETH for USDC through DAI and WBTC - see _getSplitSwaps for more info uint256 amountIn = 1 ether; - deal(WETH_ADDR, ALICE, amountIn); + deal(WETH_ADDR, address(tychoRouterAddr), amountIn); vm.startPrank(ALICE); - IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes[] memory swaps = _getSplitSwaps(false); + bytes[] memory swaps = _getSplitSwaps(); tychoRouter.exposedSplitSwap(amountIn, 4, pleEncode(swaps)); vm.stopPrank(); @@ -109,7 +84,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { bytes memory signature ) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn); - bytes[] memory swaps = _getSplitSwaps(true); + bytes[] memory swaps = _getSplitSwaps(); tychoRouter.splitSwapPermit2( amountIn, @@ -122,6 +97,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { ALICE, permitSingle, signature, + true, + tychoRouterAddr, pleEncode(swaps) ); @@ -138,7 +115,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn); - bytes[] memory swaps = _getSplitSwaps(false); + bytes[] memory swaps = _getSplitSwaps(); tychoRouter.splitSwap( amountIn, @@ -149,6 +126,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, + true, + tychoRouterAddr, pleEncode(swaps) ); @@ -165,7 +144,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes[] memory swaps = _getSplitSwaps(false); + bytes[] memory swaps = _getSplitSwaps(); vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector); tychoRouter.splitSwap( @@ -177,6 +156,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, + true, + tychoRouterAddr, pleEncode(swaps) ); vm.stopPrank(); @@ -190,7 +171,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); // Approve less than the amountIn IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn - 1); - bytes[] memory swaps = _getSplitSwaps(false); + bytes[] memory swaps = _getSplitSwaps(); vm.expectRevert(); tychoRouter.splitSwap( @@ -202,6 +183,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 2, ALICE, + true, + tychoRouterAddr, pleEncode(swaps) ); @@ -219,7 +202,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { bytes memory signature ) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn); - bytes[] memory swaps = _getSplitSwaps(true); + bytes[] memory swaps = _getSplitSwaps(); uint256 minAmountOut = 3000 * 1e18; @@ -241,6 +224,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { ALICE, permitSingle, signature, + true, + tychoRouterAddr, pleEncode(swaps) ); vm.stopPrank(); @@ -265,13 +250,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { spender: address(0), sigDeadline: 0 }); - bytes memory protocolData = encodeUniswapV2Swap( - WETH_ADDR, - WETH_DAI_POOL, - ALICE, - false, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL - ); + bytes memory protocolData = + encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, true); bytes memory swap = encodeSplitSwap( uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData @@ -290,6 +270,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { ALICE, emptyPermitSingle, "", + false, + tychoRouterAddr, pleEncode(swaps) ); uint256 expectedAmount = 2018817438608734439722; @@ -315,11 +297,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { ) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn); bytes memory protocolData = encodeUniswapV2Swap( - DAI_ADDR, - WETH_DAI_POOL, - tychoRouterAddr, - true, - TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL + DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, true ); bytes memory swap = encodeSplitSwap( @@ -339,6 +317,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { ALICE, permitSingle, signature, + true, + tychoRouterAddr, pleEncode(swaps) ); @@ -365,10 +345,10 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { // │ │ // └─ (USV3, 40% split) ──> WETH ─┘ uint256 amountIn = 100 * 10 ** 6; - deal(USDC_ADDR, ALICE, amountIn); + + // Assume funds have already been transferred to tychoRouter + deal(USDC_ADDR, tychoRouterAddr, amountIn); vm.startPrank(ALICE); - // Approve the TychoRouter to spend USDC - IERC20(USDC_ADDR).approve(tychoRouterAddr, amountIn); bytes memory usdcWethV3Pool1ZeroOneData = encodeUniswapV3Swap( USDC_ADDR, @@ -376,7 +356,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3, true, - TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL + false, // transferFrom swapper required + true // transfer from tycho router to protocol ); bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap( @@ -385,7 +366,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3_2, true, - TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL + false, // transferFrom swapper required + true // transfer from tycho router to protocol ); bytes memory wethUsdcV2OneZeroData = encodeUniswapV2Swap( @@ -393,7 +375,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { USDC_WETH_USV2, tychoRouterAddr, false, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + true // transfer from tycho router to protocol ); bytes[] memory swaps = new bytes[](3); @@ -443,7 +425,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { USDC_WETH_USV2, tychoRouterAddr, true, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + true // transfer required ); bytes memory usdcWethV3Pool1OneZeroData = encodeUniswapV3Swap( @@ -452,7 +434,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3, false, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + false, // transferFrom required + true // transfer required ); bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap( @@ -461,7 +444,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3_2, false, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + false, // transferFrom required + true // transfer required ); bytes[] memory swaps = new bytes[](3); @@ -500,11 +484,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { deal(BASE_USDC, tychoRouterAddr, amountIn); bytes memory protocolData = encodeUniswapV2Swap( - BASE_USDC, - USDC_MAG7_POOL, - tychoRouterAddr, - true, - TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL + BASE_USDC, USDC_MAG7_POOL, tychoRouterAddr, true, true ); bytes memory swap = encodeSplitSwap( diff --git a/foundry/test/TychoRouterTestSetup.sol b/foundry/test/TychoRouterTestSetup.sol index 540027c..31dd507 100644 --- a/foundry/test/TychoRouterTestSetup.sol +++ b/foundry/test/TychoRouterTestSetup.sol @@ -185,10 +185,11 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { address target, address receiver, bool zero2one, - TokenTransfer.TransferType transferType + bool transferNeeded ) internal pure returns (bytes memory) { - return - abi.encodePacked(tokenIn, target, receiver, zero2one, transferType); + return abi.encodePacked( + tokenIn, target, receiver, zero2one, transferNeeded + ); } function encodeUniswapV3Swap( @@ -197,7 +198,8 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { address receiver, address target, bool zero2one, - TokenTransfer.TransferType transferType + bool transferFromNeeded, + bool transferNeeded ) internal view returns (bytes memory) { IUniswapV3Pool pool = IUniswapV3Pool(target); return abi.encodePacked( @@ -207,7 +209,8 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { receiver, target, zero2one, - transferType + transferFromNeeded, + transferNeeded ); } } diff --git a/foundry/test/executors/BalancerV2Executor.t.sol b/foundry/test/executors/BalancerV2Executor.t.sol index 1ad790e..10cf988 100644 --- a/foundry/test/executors/BalancerV2Executor.t.sol +++ b/foundry/test/executors/BalancerV2Executor.t.sol @@ -17,7 +17,7 @@ contract BalancerV2ExecutorExposed is BalancerV2Executor { bytes32 poolId, address receiver, bool needsApproval, - TransferType transferType + bool transferNeeded ) { return _decodeData(data); @@ -41,12 +41,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { function testDecodeParams() public view { bytes memory params = abi.encodePacked( - WETH_ADDR, - BAL_ADDR, - WETH_BAL_POOL_ID, - address(2), - true, - TokenTransfer.TransferType.NONE + WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, address(2), true, false ); ( @@ -55,7 +50,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { bytes32 poolId, address receiver, bool needsApproval, - TokenTransfer.TransferType transferType + bool transferNeeded ) = balancerV2Exposed.decodeParams(params); assertEq(address(tokenIn), WETH_ADDR); @@ -63,7 +58,6 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { assertEq(poolId, WETH_BAL_POOL_ID); assertEq(receiver, address(2)); assertEq(needsApproval, true); - assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE)); } function testDecodeParamsInvalidDataLength() public { @@ -77,12 +71,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { function testSwap() public { uint256 amountIn = 10 ** 18; bytes memory protocolData = abi.encodePacked( - WETH_ADDR, - BAL_ADDR, - WETH_BAL_POOL_ID, - BOB, - true, - TokenTransfer.TransferType.NONE + WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, BOB, true, false ); deal(WETH_ADDR, address(balancerV2Exposed), amountIn); @@ -104,7 +93,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { bytes32 poolId, address receiver, bool needsApproval, - TokenTransfer.TransferType transferType + bool transferNeeded ) = balancerV2Exposed.decodeParams(protocolData); assertEq(address(tokenIn), WETH_ADDR); @@ -112,7 +101,6 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { assertEq(poolId, WETH_BAL_POOL_ID); assertEq(receiver, BOB); assertEq(needsApproval, true); - assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE)); } function testSwapIntegration() public { diff --git a/foundry/test/executors/CurveExecutor.t.sol b/foundry/test/executors/CurveExecutor.t.sol index 629ce79..3d61d60 100644 --- a/foundry/test/executors/CurveExecutor.t.sol +++ b/foundry/test/executors/CurveExecutor.t.sol @@ -37,7 +37,7 @@ contract CurveExecutorExposed is CurveExecutor { int128 i, int128 j, bool tokenApprovalNeeded, - TokenTransfer.TransferType transferType, + bool transferNeeded, address receiver ) { @@ -68,7 +68,7 @@ contract CurveExecutorTest is Test, Constants { uint8(2), uint8(0), true, - TokenTransfer.TransferType.NONE, + false, ALICE ); @@ -80,7 +80,7 @@ contract CurveExecutorTest is Test, Constants { int128 i, int128 j, bool tokenApprovalNeeded, - TokenTransfer.TransferType transferType, + bool transferNeeded, address receiver ) = curveExecutorExposed.decodeData(data); @@ -91,7 +91,6 @@ contract CurveExecutorTest is Test, Constants { assertEq(i, 2); assertEq(j, 0); assertEq(tokenApprovalNeeded, true); - assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE)); assertEq(receiver, ALICE); } @@ -295,7 +294,7 @@ contract CurveExecutorTest is Test, Constants { uint8(uint256(uint128(i))), uint8(uint256(uint128(j))), true, - TokenTransfer.TransferType.NONE, + false, receiver ); } diff --git a/foundry/test/executors/EkuboExecutor.t.sol b/foundry/test/executors/EkuboExecutor.t.sol index 23996f9..8b2026b 100644 --- a/foundry/test/executors/EkuboExecutor.t.sol +++ b/foundry/test/executors/EkuboExecutor.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.26; import "../TestUtils.sol"; import {Constants} from "../Constants.sol"; -import {EkuboExecutor, TokenTransfer} from "@src/executors/EkuboExecutor.sol"; +import {EkuboExecutor} from "@src/executors/EkuboExecutor.sol"; import {ICore} from "@ekubo/interfaces/ICore.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {NATIVE_TOKEN_ADDRESS} from "@ekubo/math/constants.sol"; @@ -45,7 +45,7 @@ contract EkuboExecutorTest is Constants, TestUtils { uint256 usdcBalanceBeforeExecutor = USDC.balanceOf(address(executor)); bytes memory data = abi.encodePacked( - uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL), // transferType (transfer from executor to core) + true, // transferNeeded (transfer from executor to core) address(executor), // receiver NATIVE_TOKEN_ADDRESS, // tokenIn USDC_ADDR, // tokenOut @@ -82,7 +82,7 @@ contract EkuboExecutorTest is Constants, TestUtils { uint256 ethBalanceBeforeExecutor = address(executor).balance; bytes memory data = abi.encodePacked( - uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL), // transferType (transfer from executor to core) + true, // transferNeeded (transfer from executor to core) address(executor), // receiver USDC_ADDR, // tokenIn NATIVE_TOKEN_ADDRESS, // tokenOut @@ -140,7 +140,7 @@ contract EkuboExecutorTest is Constants, TestUtils { // Same test case as in swap_encoder::tests::ekubo::test_encode_swap_multi function testMultiHopSwap() public { bytes memory data = abi.encodePacked( - uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL), // transferType + true, // transferNeeded (transfer from executor to core) address(executor), // receiver NATIVE_TOKEN_ADDRESS, // tokenIn USDC_ADDR, // tokenOut of 1st swap diff --git a/foundry/test/executors/MaverickV2Executor.t.sol b/foundry/test/executors/MaverickV2Executor.t.sol index 755570d..241d265 100644 --- a/foundry/test/executors/MaverickV2Executor.t.sol +++ b/foundry/test/executors/MaverickV2Executor.t.sol @@ -17,7 +17,7 @@ contract MaverickV2ExecutorExposed is MaverickV2Executor { IERC20 tokenIn, address target, address receiver, - TransferType transferType + bool transferNeeded ) { return _decodeData(data); @@ -39,27 +39,16 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { } function testDecodeParams() public view { - bytes memory params = abi.encodePacked( - GHO_ADDR, - GHO_USDC_POOL, - address(2), - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL - ); + bytes memory params = + abi.encodePacked(GHO_ADDR, GHO_USDC_POOL, address(2), true); - ( - IERC20 tokenIn, - address target, - address receiver, - TokenTransfer.TransferType transferType - ) = maverickV2Exposed.decodeParams(params); + (IERC20 tokenIn, address target, address receiver, bool transferNeeded) + = maverickV2Exposed.decodeParams(params); assertEq(address(tokenIn), GHO_ADDR); assertEq(target, GHO_USDC_POOL); assertEq(receiver, address(2)); - assertEq( - uint8(transferType), - uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL) - ); + assertEq(transferNeeded, true); } function testDecodeParamsInvalidDataLength() public { @@ -72,12 +61,8 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { function testSwap() public { uint256 amountIn = 10e18; - bytes memory protocolData = abi.encodePacked( - GHO_ADDR, - GHO_USDC_POOL, - BOB, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL - ); + bytes memory protocolData = + abi.encodePacked(GHO_ADDR, GHO_USDC_POOL, BOB, true); deal(GHO_ADDR, address(maverickV2Exposed), amountIn); uint256 balanceBefore = USDC.balanceOf(BOB); @@ -94,20 +79,13 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { bytes memory protocolData = loadCallDataFromFile("test_encode_maverick_v2"); - ( - IERC20 tokenIn, - address pool, - address receiver, - TokenTransfer.TransferType transferType - ) = maverickV2Exposed.decodeParams(protocolData); + (IERC20 tokenIn, address pool, address receiver, bool transferNeeded) = + maverickV2Exposed.decodeParams(protocolData); assertEq(address(tokenIn), GHO_ADDR); assertEq(pool, GHO_USDC_POOL); assertEq(receiver, BOB); - assertEq( - uint8(transferType), - uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL) - ); + assertEq(transferNeeded, true); } function testSwapIntegration() public { diff --git a/foundry/test/executors/UniswapV2Executor.t.sol b/foundry/test/executors/UniswapV2Executor.t.sol index 5f81427..0f1b2a5 100644 --- a/foundry/test/executors/UniswapV2Executor.t.sol +++ b/foundry/test/executors/UniswapV2Executor.t.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.26; import "@src/executors/UniswapV2Executor.sol"; -import "@src/executors/TokenTransfer.sol"; import {Test} from "../../lib/forge-std/src/Test.sol"; import {Constants} from "../Constants.sol"; import {Permit2TestHelper} from "../Permit2TestHelper.sol"; @@ -23,7 +22,7 @@ contract UniswapV2ExecutorExposed is UniswapV2Executor { address target, address receiver, bool zeroForOne, - TransferType transferType + bool transferNeeded ) { return _decodeData(data); @@ -60,7 +59,6 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper { UniswapV2ExecutorExposed pancakeswapV2Exposed; IERC20 WETH = IERC20(WETH_ADDR); IERC20 DAI = IERC20(DAI_ADDR); - IAllowanceTransfer permit2; function setUp() public { uint256 forkBlock = 17323404; @@ -80,34 +78,25 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper { PERMIT2_ADDRESS, 25 ); - permit2 = IAllowanceTransfer(PERMIT2_ADDRESS); } function testDecodeParams() public view { - bytes memory params = abi.encodePacked( - WETH_ADDR, - address(2), - address(3), - false, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL - ); + bytes memory params = + abi.encodePacked(WETH_ADDR, address(2), address(3), false, true); ( IERC20 tokenIn, address target, address receiver, bool zeroForOne, - TokenTransfer.TransferType transferType + bool transferNeeded ) = uniswapV2Exposed.decodeParams(params); assertEq(address(tokenIn), WETH_ADDR); assertEq(target, address(2)); assertEq(receiver, address(3)); assertEq(zeroForOne, false); - assertEq( - uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL), - uint8(transferType) - ); + assertEq(transferNeeded, true); } function testDecodeParamsInvalidDataLength() public { @@ -158,13 +147,8 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper { uint256 amountIn = 10 ** 18; uint256 amountOut = 1847751195973566072891; bool zeroForOne = false; - bytes memory protocolData = abi.encodePacked( - WETH_ADDR, - WETH_DAI_POOL, - BOB, - zeroForOne, - uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL) - ); + bytes memory protocolData = + abi.encodePacked(WETH_ADDR, WETH_DAI_POOL, BOB, zeroForOne, true); deal(WETH_ADDR, address(uniswapV2Exposed), amountIn); uniswapV2Exposed.swap(amountIn, protocolData); @@ -173,70 +157,12 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper { assertGe(finalBalance, amountOut); } - function testSwapWithTransferFrom() public { - uint256 amountIn = 10 ** 18; - uint256 amountOut = 1847751195973566072891; - bool zeroForOne = false; - bytes memory protocolData = abi.encodePacked( - WETH_ADDR, - WETH_DAI_POOL, - BOB, - zeroForOne, - uint8(TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL) - ); - - deal(WETH_ADDR, address(this), amountIn); - IERC20(WETH_ADDR).approve(address(uniswapV2Exposed), amountIn); - - uniswapV2Exposed.swap(amountIn, protocolData); - - uint256 finalBalance = DAI.balanceOf(BOB); - assertGe(finalBalance, amountOut); - } - - function testSwapWithPermit2TransferFrom() public { - uint256 amountIn = 10 ** 18; - uint256 amountOut = 1847751195973566072891; - bool zeroForOne = false; - bytes memory protocolData = abi.encodePacked( - WETH_ADDR, - WETH_DAI_POOL, - ALICE, - zeroForOne, - uint8(TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL) - ); - - deal(WETH_ADDR, ALICE, amountIn); - vm.startPrank(ALICE); - ( - IAllowanceTransfer.PermitSingle memory permitSingle, - bytes memory signature - ) = handlePermit2Approval( - WETH_ADDR, address(uniswapV2Exposed), amountIn - ); - - // Assume the permit2.approve method will be called from the TychoRouter - // Replicate this scenario in this test. - permit2.permit(ALICE, permitSingle, signature); - - uniswapV2Exposed.swap(amountIn, protocolData); - vm.stopPrank(); - - uint256 finalBalance = DAI.balanceOf(ALICE); - assertGe(finalBalance, amountOut); - } - function testSwapNoTransfer() public { uint256 amountIn = 10 ** 18; uint256 amountOut = 1847751195973566072891; bool zeroForOne = false; - bytes memory protocolData = abi.encodePacked( - WETH_ADDR, - WETH_DAI_POOL, - BOB, - zeroForOne, - uint8(TokenTransfer.TransferType.NONE) - ); + bytes memory protocolData = + abi.encodePacked(WETH_ADDR, WETH_DAI_POOL, BOB, zeroForOne, false); deal(WETH_ADDR, address(this), amountIn); IERC20(WETH_ADDR).transfer(address(WETH_DAI_POOL), amountIn); @@ -255,20 +181,19 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper { address target, address receiver, bool zeroForOne, - TokenTransfer.TransferType transferType + bool transferNeeded ) = uniswapV2Exposed.decodeParams(protocolData); assertEq(address(tokenIn), WETH_ADDR); assertEq(target, 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640); assertEq(receiver, 0x0000000000000000000000000000000000000001); assertEq(zeroForOne, false); - // TRANSFER = 0 - assertEq(0, uint8(transferType)); + assertEq(transferNeeded, false); } function testSwapIntegration() public { bytes memory protocolData = - hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0000"; + hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0001"; uint256 amountIn = 10 ** 18; uint256 amountOut = 1847751195973566072891; deal(WETH_ADDR, address(uniswapV2Exposed), amountIn); @@ -282,13 +207,8 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper { uint256 amountIn = 10 ** 18; bool zeroForOne = false; address fakePool = address(new FakeUniswapV2Pool(WETH_ADDR, DAI_ADDR)); - bytes memory protocolData = abi.encodePacked( - WETH_ADDR, - fakePool, - BOB, - zeroForOne, - uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL) - ); + bytes memory protocolData = + abi.encodePacked(WETH_ADDR, fakePool, BOB, zeroForOne, true); deal(WETH_ADDR, address(uniswapV2Exposed), amountIn); vm.expectRevert(UniswapV2Executor__InvalidTarget.selector); @@ -302,13 +222,8 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper { vm.rollFork(26857267); uint256 amountIn = 10 * 10 ** 6; bool zeroForOne = true; - bytes memory protocolData = abi.encodePacked( - BASE_USDC, - USDC_MAG7_POOL, - BOB, - zeroForOne, - uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL) - ); + bytes memory protocolData = + abi.encodePacked(BASE_USDC, USDC_MAG7_POOL, BOB, zeroForOne, true); deal(BASE_USDC, address(uniswapV2Exposed), amountIn); diff --git a/foundry/test/executors/UniswapV3Executor.t.sol b/foundry/test/executors/UniswapV3Executor.t.sol index e9d95e6..9f3e1dd 100644 --- a/foundry/test/executors/UniswapV3Executor.t.sol +++ b/foundry/test/executors/UniswapV3Executor.t.sol @@ -22,7 +22,8 @@ contract UniswapV3ExecutorExposed is UniswapV3Executor { address receiver, address target, bool zeroForOne, - TransferType transferType + bool transferFromNeeded, + bool transferNeeded ) { return _decodeData(data); @@ -71,7 +72,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address(2), address(3), false, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + false, + true ); ( @@ -81,7 +83,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address receiver, address target, bool zeroForOne, - TokenTransfer.TransferType transferType + bool transferFromNeeded, + bool transferNeeded ) = uniswapV3Exposed.decodeData(data); assertEq(tokenIn, WETH_ADDR); @@ -90,10 +93,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { assertEq(receiver, address(2)); assertEq(target, address(3)); assertEq(zeroForOne, false); - assertEq( - uint8(transferType), - uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL) - ); + assertEq(transferFromNeeded, false); + assertEq(transferNeeded, true); } function testSwapIntegration() public { @@ -109,7 +110,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address(this), DAI_WETH_USV3, zeroForOne, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + false, + true ); uint256 amountOut = uniswapV3Exposed.swap(amountIn, data); @@ -184,7 +186,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address(this), fakePool, zeroForOne, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL + false, + true ); vm.expectRevert(UniswapV3Executor__InvalidTarget.selector); @@ -197,7 +200,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address receiver, address target, bool zero2one, - TokenTransfer.TransferType transferType + bool transferFromNeeded, + bool transferNeeded ) internal view returns (bytes memory) { IUniswapV3Pool pool = IUniswapV3Pool(target); return abi.encodePacked( @@ -207,7 +211,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { receiver, target, zero2one, - transferType + transferFromNeeded, + transferNeeded ); } } diff --git a/foundry/test/executors/UniswapV4Executor.t.sol b/foundry/test/executors/UniswapV4Executor.t.sol index 8f2c292..d2918a0 100644 --- a/foundry/test/executors/UniswapV4Executor.t.sol +++ b/foundry/test/executors/UniswapV4Executor.t.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.26; import "../../src/executors/UniswapV4Executor.sol"; import "../TestUtils.sol"; import "./UniswapV4Utils.sol"; -import "@src/executors/TokenTransfer.sol"; import "@src/executors/UniswapV4Executor.sol"; import {Constants} from "../Constants.sol"; import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol"; @@ -22,7 +21,8 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor { address tokenIn, address tokenOut, bool zeroForOne, - TokenTransfer.TransferType transferType, + bool transferFromNeeded, + bool transferNeeded, address receiver, UniswapV4Pool[] memory pools ) @@ -53,8 +53,8 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { int24 tickSpacing1 = 60; uint24 pool2Fee = 1000; int24 tickSpacing2 = -10; - TokenTransfer.TransferType transferType = - TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL; + bool transferFromNeeded = false; + bool transferNeeded = true; UniswapV4Executor.UniswapV4Pool[] memory pools = new UniswapV4Executor.UniswapV4Pool[](2); @@ -70,14 +70,21 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, USDT_ADDR, zeroForOne, transferType, ALICE, pools + USDE_ADDR, + USDT_ADDR, + zeroForOne, + transferFromNeeded, + transferNeeded, + ALICE, + pools ); ( address tokenIn, address tokenOut, bool zeroForOneDecoded, - TokenTransfer.TransferType transferTypeDecoded, + bool transferFromNeededDecoded, + bool transferNeededDecoded, address receiver, UniswapV4Executor.UniswapV4Pool[] memory decodedPools ) = uniswapV4Exposed.decodeData(data); @@ -85,7 +92,8 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { assertEq(tokenIn, USDE_ADDR); assertEq(tokenOut, USDT_ADDR); assertEq(zeroForOneDecoded, zeroForOne); - assertEq(uint8(transferTypeDecoded), uint8(transferType)); + assertEq(transferFromNeededDecoded, transferFromNeeded); + assertEq(transferNeededDecoded, transferNeeded); assertEq(receiver, ALICE); assertEq(decodedPools.length, 2); assertEq(decodedPools[0].intermediaryToken, USDT_ADDR); @@ -112,12 +120,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, - USDT_ADDR, - true, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL, - ALICE, - pools + USDE_ADDR, USDT_ADDR, true, false, true, ALICE, pools ); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); @@ -169,12 +172,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, - WBTC_ADDR, - true, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL, - ALICE, - pools + USDE_ADDR, WBTC_ADDR, true, false, true, ALICE, pools ); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); diff --git a/foundry/test/executors/UniswapV4Utils.sol b/foundry/test/executors/UniswapV4Utils.sol index c96465c..aa1e5eb 100644 --- a/foundry/test/executors/UniswapV4Utils.sol +++ b/foundry/test/executors/UniswapV4Utils.sol @@ -8,7 +8,8 @@ library UniswapV4Utils { address tokenIn, address tokenOut, bool zeroForOne, - UniswapV4Executor.TransferType transferType, + bool transferFromNeeded, + bool transferNeeded, address receiver, UniswapV4Executor.UniswapV4Pool[] memory pools ) public pure returns (bytes memory) { @@ -24,7 +25,12 @@ library UniswapV4Utils { } return abi.encodePacked( - tokenIn, tokenOut, zeroForOne, transferType, receiver, encodedPools + tokenIn, + tokenOut, + zeroForOne, + transferNeeded, + receiver, + encodedPools ); } } From ee687038c5f8fefdc97b52991de8338c5351b90d Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Thu, 15 May 2025 13:11:34 +0100 Subject: [PATCH 04/22] fix: Make all tests pass! Delete TokenTransfer.sol Make slither happy Bugfixes: - Executors - Ekubo: - Fix the POOL_DATA_OFFSET value and remove sender from callback data - Use SafeERC20 - Maverick and Univ2: Use safeTransfer and not safeTransferFrom - Univ3: update expected data length - Univ4: update the selectors (the signature changed) - Router: - For split swap we don't need to pass the tokenInReceiver, it should always be the router address - For single and sequential: change order of the parameters (to be before the permit2 specific objects) - Encoders: - Update selector signatures - For split swap pass the transfer_from (we might not need to if the token in is ETH) Took 2 hours 51 minutes --- foundry/src/OneTransferFromOnly.sol | 2 + foundry/src/TychoRouter.sol | 28 ++++---- foundry/src/executors/EkuboExecutor.sol | 18 ++--- foundry/src/executors/MaverickV2Executor.sol | 4 +- foundry/src/executors/TokenTransfer.sol | 70 ------------------- foundry/src/executors/UniswapV2Executor.sol | 8 +-- foundry/src/executors/UniswapV3Executor.sol | 3 +- foundry/src/executors/UniswapV4Executor.sol | 4 +- .../test/TychoRouterProtocolIntegration.t.sol | 14 ++-- foundry/test/TychoRouterSequentialSwap.t.sol | 20 +++--- foundry/test/TychoRouterSingleSwap.t.sol | 12 ++-- foundry/test/TychoRouterSplitSwap.t.sol | 15 ++-- foundry/test/assets/calldata.txt | 47 +++++++------ foundry/test/executors/EkuboExecutor.t.sol | 3 + .../test/executors/UniswapV2Executor.t.sol | 7 +- .../test/executors/UniswapV3Executor.t.sol | 6 +- foundry/test/executors/UniswapV4Utils.sol | 1 + .../evm/strategy_encoder/strategy_encoders.rs | 46 +++++++----- .../evm/swap_encoder/swap_encoders.rs | 9 +-- src/encoding/evm/tycho_encoders.rs | 6 +- 20 files changed, 126 insertions(+), 197 deletions(-) delete mode 100644 foundry/src/executors/TokenTransfer.sol diff --git a/foundry/src/OneTransferFromOnly.sol b/foundry/src/OneTransferFromOnly.sol index 78d29bc..072ac48 100644 --- a/foundry/src/OneTransferFromOnly.sol +++ b/foundry/src/OneTransferFromOnly.sol @@ -25,6 +25,7 @@ contract OneTransferFromOnly { permit2lal = IAllowanceTransfer(_permit2); } + // slither-disable-next-line assembly function tstoreTransferFromInfo( address tokenIn, uint256 amountIn, @@ -40,6 +41,7 @@ contract OneTransferFromOnly { } } + // slither-disable-next-line assembly function _transfer(address receiver) internal { address tokenIn; uint256 amount; diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 655a6a0..ffd6420 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -123,7 +123,6 @@ contract TychoRouter is * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. - * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -138,12 +137,11 @@ contract TychoRouter is uint256 nTokens, address receiver, bool transferFromRequired, - address tokenInReceiver, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); if (transferFromRequired) { - _transfer(tokenInReceiver); + _transfer(address(this)); } return _splitSwapChecked( amountIn, @@ -178,10 +176,9 @@ contract TychoRouter is * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. + * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. - * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. - * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -195,10 +192,9 @@ contract TychoRouter is bool unwrapEth, uint256 nTokens, address receiver, + bool transferFromRequired, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, - bool transferFromRequired, - address tokenInReceiver, bytes calldata swaps ) external payable whenNotPaused nonReentrant returns (uint256 amountOut) { // For native ETH, assume funds already in our router. Else, handle approval. @@ -207,7 +203,7 @@ contract TychoRouter is } tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); if (transferFromRequired) { - _transfer(tokenInReceiver); + _transfer(address(this)); } return _splitSwapChecked( @@ -293,10 +289,10 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. - * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. + * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. + * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -309,10 +305,10 @@ contract TychoRouter is bool wrapEth, bool unwrapEth, address receiver, - IAllowanceTransfer.PermitSingle calldata permitSingle, - bytes calldata signature, bool transferFromRequired, address tokenInReceiver, + IAllowanceTransfer.PermitSingle calldata permitSingle, + bytes calldata signature, bytes calldata swaps ) external payable whenNotPaused nonReentrant returns (uint256 amountOut) { // For native ETH, assume funds already in our router. Else, handle approval. @@ -404,10 +400,10 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. - * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. + * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. + * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swapData Encoded swap details. * * @return amountOut The total amount of the output token received by the receiver. @@ -420,10 +416,10 @@ contract TychoRouter is bool wrapEth, bool unwrapEth, address receiver, - IAllowanceTransfer.PermitSingle calldata permitSingle, - bytes calldata signature, bool transferFromRequired, address tokenInReceiver, + IAllowanceTransfer.PermitSingle calldata permitSingle, + bytes calldata signature, bytes calldata swapData ) external payable whenNotPaused nonReentrant returns (uint256 amountOut) { // For native ETH, assume funds already in our router. Else, handle approval. diff --git a/foundry/src/executors/EkuboExecutor.sol b/foundry/src/executors/EkuboExecutor.sol index 692626d..90ee2f5 100644 --- a/foundry/src/executors/EkuboExecutor.sol +++ b/foundry/src/executors/EkuboExecutor.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.26; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IExecutor} from "@interfaces/IExecutor.sol"; import {ICallback} from "@interfaces/ICallback.sol"; import {ICore} from "@ekubo/interfaces/ICore.sol"; @@ -26,12 +26,14 @@ contract EkuboExecutor is ICore immutable core; - uint256 constant POOL_DATA_OFFSET = 77; + uint256 constant POOL_DATA_OFFSET = 58; uint256 constant HOP_BYTE_LEN = 52; bytes4 constant LOCKED_SELECTOR = 0xb45a3c0e; // locked(uint256) bytes4 constant PAY_CALLBACK_SELECTOR = 0x599d0714; // payCallback(uint256,address) + using SafeERC20 for IERC20; + constructor(address _core, address _permit2) OneTransferFromOnly(_permit2) { @@ -122,12 +124,10 @@ contract EkuboExecutor is function _locked(bytes calldata swapData) internal returns (int128) { int128 nextAmountIn = int128(uint128(bytes16(swapData[0:16]))); uint128 tokenInDebtAmount = uint128(nextAmountIn); - address sender = address(bytes20(swapData[16:36])); - bool transferFromNeeded = (swapData[36] != 0); - bool transferNeeded = (swapData[37] != 0); - - address receiver = address(bytes20(swapData[38:58])); - address tokenIn = address(bytes20(swapData[58:78])); + bool transferFromNeeded = (swapData[16] != 0); + bool transferNeeded = (swapData[17] != 0); + address receiver = address(bytes20(swapData[18:38])); + address tokenIn = address(bytes20(swapData[38:58])); address nextTokenIn = tokenIn; @@ -207,7 +207,7 @@ contract EkuboExecutor is if (token == address(0)) { payable(msg.sender).transfer(amount); } else { - IERC20(token).transfer(msg.sender, amount); + IERC20(token).safeTransfer(msg.sender, amount); } } } diff --git a/foundry/src/executors/MaverickV2Executor.sol b/foundry/src/executors/MaverickV2Executor.sol index b2dfabe..24dcd00 100644 --- a/foundry/src/executors/MaverickV2Executor.sol +++ b/foundry/src/executors/MaverickV2Executor.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.26; import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "./TokenTransfer.sol"; error MaverickV2Executor__InvalidDataLength(); error MaverickV2Executor__InvalidTarget(); @@ -49,10 +48,11 @@ contract MaverickV2Executor is IExecutor { if (transferNeeded) { if (address(tokenIn) == address(0)) { + // slither-disable-next-line arbitrary-send-eth payable(target).transfer(givenAmount); } else { // slither-disable-next-line arbitrary-send-erc20 - tokenIn.safeTransferFrom(msg.sender, target, givenAmount); + tokenIn.safeTransfer(target, givenAmount); } } diff --git a/foundry/src/executors/TokenTransfer.sol b/foundry/src/executors/TokenTransfer.sol deleted file mode 100644 index b5f8629..0000000 --- a/foundry/src/executors/TokenTransfer.sol +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.26; - -import "@interfaces/IExecutor.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@permit2/src/interfaces/IAllowanceTransfer.sol"; - -error TokenTransfer__AddressZero(); - -contract TokenTransfer { - using SafeERC20 for IERC20; - - IAllowanceTransfer public immutable permit2; - - enum TransferType { - // Assume funds are in the TychoRouter - transfer into the pool - TRANSFER_TO_PROTOCOL, - // Assume funds are in msg.sender's wallet - transferFrom into the pool - TRANSFER_FROM_TO_PROTOCOL, - // Assume funds are in msg.sender's wallet - permit2TransferFrom into the pool - TRANSFER_PERMIT2_TO_PROTOCOL, - // Assume funds are in msg.sender's wallet - but the pool requires it to be - // in the router contract when calling swap - transferFrom into the router - // contract - TRANSFER_FROM_TO_ROUTER, - // Assume funds are in msg.sender's wallet - but the pool requires it to be - // in the router contract when calling swap - transferFrom into the router - // contract using permit2 - TRANSFER_PERMIT2_TO_ROUTER, - // Assume funds have already been transferred into the pool. Do nothing. - NONE - } - - constructor(address _permit2) { - if (_permit2 == address(0)) { - revert TokenTransfer__AddressZero(); - } - permit2 = IAllowanceTransfer(_permit2); - } - - function _transfer( - address tokenIn, - address sender, - address receiver, - uint256 amount, - TransferType transferType - ) internal { - if (transferType == TransferType.TRANSFER_TO_PROTOCOL) { - if (tokenIn == address(0)) { - payable(receiver).transfer(amount); - } else { - IERC20(tokenIn).safeTransfer(receiver, amount); - } - } else if (transferType == TransferType.TRANSFER_FROM_TO_PROTOCOL) { - // slither-disable-next-line arbitrary-send-erc20 - IERC20(tokenIn).safeTransferFrom(sender, receiver, amount); - } else if (transferType == TransferType.TRANSFER_PERMIT2_TO_PROTOCOL) { - // Permit2.permit is already called from the TychoRouter - permit2.transferFrom(sender, receiver, uint160(amount), tokenIn); - } else if (transferType == TransferType.TRANSFER_FROM_TO_ROUTER) { - // slither-disable-next-line arbitrary-send-erc20 - IERC20(tokenIn).safeTransferFrom(sender, address(this), amount); - } else if (transferType == TransferType.TRANSFER_PERMIT2_TO_ROUTER) { - // Permit2.permit is already called from the TychoRouter - permit2.transferFrom( - sender, address(this), uint160(amount), tokenIn - ); - } - } -} diff --git a/foundry/src/executors/UniswapV2Executor.sol b/foundry/src/executors/UniswapV2Executor.sol index d1f25d9..d5b1831 100644 --- a/foundry/src/executors/UniswapV2Executor.sol +++ b/foundry/src/executors/UniswapV2Executor.sol @@ -60,12 +60,8 @@ contract UniswapV2Executor is IExecutor { calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne); if (transferNeeded) { - if (address(tokenIn) == address(0)) { - payable(target).transfer(givenAmount); - } else { - // slither-disable-next-line arbitrary-send-erc20 - tokenIn.safeTransferFrom(msg.sender, target, givenAmount); - } + // slither-disable-next-line arbitrary-send-erc20 + tokenIn.safeTransfer(target, givenAmount); } IUniswapV2Pair pool = IUniswapV2Pair(target); diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index 23ecc27..9d4e1e1 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -5,7 +5,6 @@ import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; import "@interfaces/ICallback.sol"; -import {TokenTransfer} from "./TokenTransfer.sol"; import {OneTransferFromOnly} from "../OneTransferFromOnly.sol"; error UniswapV3Executor__InvalidDataLength(); @@ -152,7 +151,7 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { bool transferNeeded ) { - if (data.length != 85) { + if (data.length != 86) { revert UniswapV3Executor__InvalidDataLength(); } tokenIn = address(bytes20(data[0:20])); diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index 0d00ce9..1867a6e 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -47,8 +47,8 @@ contract UniswapV4Executor is IPoolManager public immutable poolManager; address private immutable _self; - bytes4 constant SWAP_EXACT_INPUT_SINGLE_SELECTOR = 0x8bc6d0d7; - bytes4 constant SWAP_EXACT_INPUT_SELECTOR = 0xaf90aeb1; + bytes4 constant SWAP_EXACT_INPUT_SINGLE_SELECTOR = 0xbaa46608; + bytes4 constant SWAP_EXACT_INPUT_SELECTOR = 0x653f1785; struct UniswapV4Pool { address intermediaryToken; diff --git a/foundry/test/TychoRouterProtocolIntegration.t.sol b/foundry/test/TychoRouterProtocolIntegration.t.sol index e1cd732..a7761d3 100644 --- a/foundry/test/TychoRouterProtocolIntegration.t.sol +++ b/foundry/test/TychoRouterProtocolIntegration.t.sol @@ -43,10 +43,10 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { false, false, ALICE, - permitSingle, - signature, false, address(0), + permitSingle, + signature, swap ); @@ -58,7 +58,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { // This test has two uniswap v4 hops that will be executed inside of the V4 pool manager // USDE -> USDT -> WBTC uint256 amountIn = 100 ether; - deal(USDE_ADDR, tychoRouterAddr, amountIn); + deal(USDE_ADDR, ALICE, amountIn); UniswapV4Executor.UniswapV4Pool[] memory pools = new UniswapV4Executor.UniswapV4Pool[](2); @@ -77,7 +77,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { USDE_ADDR, WBTC_ADDR, true, - true, // permit2 transferFrom to protocol + true, // transferFrom to protocol false, // transfer to protocol ALICE, pools @@ -86,6 +86,8 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { bytes memory swap = encodeSingleSwap(address(usv4Executor), protocolData); + vm.startPrank(ALICE); + IERC20(USDE_ADDR).approve(tychoRouterAddr, amountIn); tychoRouter.singleSwap( amountIn, USDE_ADDR, @@ -289,10 +291,10 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { false, false, ALICE, - permitSingle, - signature, false, address(0), + permitSingle, + signature, swap ); diff --git a/foundry/test/TychoRouterSequentialSwap.t.sol b/foundry/test/TychoRouterSequentialSwap.t.sol index 7037e80..7a0459c 100644 --- a/foundry/test/TychoRouterSequentialSwap.t.sol +++ b/foundry/test/TychoRouterSequentialSwap.t.sol @@ -60,10 +60,10 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - permitSingle, - signature, true, WETH_DAI_POOL, + permitSingle, + signature, pleEncode(swaps) ); @@ -177,10 +177,10 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - permitSingle, - signature, true, WETH_DAI_POOL, + permitSingle, + signature, pleEncode(swaps) ); vm.stopPrank(); @@ -208,14 +208,14 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { swaps[0] = encodeSequentialSwap( address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, true + WETH_ADDR, WETH_DAI_POOL, DAI_USDC_POOL, false, true ) ); // DAI -> USDC swaps[1] = encodeSequentialSwap( address(usv2Executor), - encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, ALICE, true, true) + encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, ALICE, true, false) ); uint256 amountOut = tychoRouter.sequentialSwapPermit2{value: amountIn}( @@ -226,10 +226,10 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { true, false, ALICE, + false, + address(0), emptyPermitSingle, "", - true, - tychoRouterAddr, pleEncode(swaps) ); uint256 expectedAmount = 2005810530; @@ -280,10 +280,10 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, true, ALICE, - permitSingle, - signature, true, DAI_USDC_POOL, + permitSingle, + signature, pleEncode(swaps) ); diff --git a/foundry/test/TychoRouterSingleSwap.t.sol b/foundry/test/TychoRouterSingleSwap.t.sol index 84b452e..97e9468 100644 --- a/foundry/test/TychoRouterSingleSwap.t.sol +++ b/foundry/test/TychoRouterSingleSwap.t.sol @@ -40,10 +40,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, - permitSingle, - signature, true, // transferFrom to WETH_DAI_POOL WETH_DAI_POOL, // receiver of input tokens + permitSingle, + signature, swap ); @@ -239,10 +239,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { true, false, ALICE, + false, + tychoRouterAddr, emptyPermitSingle, "", - true, - tychoRouterAddr, swap ); uint256 expectedAmount = 2018817438608734439722; @@ -280,10 +280,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, true, ALICE, - permitSingle, - signature, true, // transferFrom to WETH_DAI_POOL WETH_DAI_POOL, // receiver of input tokens + permitSingle, + signature, swap ); diff --git a/foundry/test/TychoRouterSplitSwap.t.sol b/foundry/test/TychoRouterSplitSwap.t.sol index 91f845a..b259b0a 100644 --- a/foundry/test/TychoRouterSplitSwap.t.sol +++ b/foundry/test/TychoRouterSplitSwap.t.sol @@ -95,10 +95,9 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, + true, permitSingle, signature, - true, - tychoRouterAddr, pleEncode(swaps) ); @@ -127,7 +126,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { 4, ALICE, true, - tychoRouterAddr, pleEncode(swaps) ); @@ -157,7 +155,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { 4, ALICE, true, - tychoRouterAddr, pleEncode(swaps) ); vm.stopPrank(); @@ -184,7 +181,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { 2, ALICE, true, - tychoRouterAddr, pleEncode(swaps) ); @@ -222,10 +218,9 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, + true, permitSingle, signature, - true, - tychoRouterAddr, pleEncode(swaps) ); vm.stopPrank(); @@ -268,10 +263,9 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 2, ALICE, + false, emptyPermitSingle, "", - false, - tychoRouterAddr, pleEncode(swaps) ); uint256 expectedAmount = 2018817438608734439722; @@ -315,10 +309,9 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { true, 2, ALICE, + true, permitSingle, signature, - true, - tychoRouterAddr, pleEncode(swaps) ); diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index ea9d8d6..bd7751b 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -1,28 +1,29 @@ -test_uniswap_v3_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c0006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100 -test_single_encoding_strategy_ekubo:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000072a0cb889707d426a7a386870a03bc70d1b06975980000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c0000000000000000000000000000000000000000000000000000 -test_uniswap_v3_uniswap_v3:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100006a2e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc350100010000000000000000 -test_balancer_v2_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 -test_sequential_swap_strategy_encoder_no_permit2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004112ff786cc8a8d24dfe6871e6c581f898b84a73bf68e93825d00425d0e90a03da63d709c708de1e54427deac6eb71c6602528be1a0768868f453446afc04f00d01c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d2311933000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f90000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000418f3422d7328230aea76c4de1731793a8bd744961c9796297abefd7fe5e22820a73117fb461de9eee74d1644876084f0b1683d4916851df285fba8ae8f48cf6671c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007400720001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 -test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004110339de0a348f6dc0822b93a4b3764aabd9a7fdd3b248c3baae2a341158a1ff138941375145748d7a6f194808e5a68299882ef00b89bddb95f3d9215fe5db39f1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_no_permit2:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_single_swap_strategy_encoder_no_transfer_in:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004159eb2cc8eae51e324934272b75187fb7973da58e1fbb52fd1d7c5871995177e26dfd6f50a879b9e3c71295bc2e3ceba72e3293e1382b8057b6690f652c3d6e0a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006df62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000 -test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041220e558f9cb5c8b8e33d592acf1526fe2a56feceb2fc437fff2c443ecc27febc2bae93737bf02a9f65cafa3bc465d6bf96753549be5d1411aa8174f9bf85c1141c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010100006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000000000 -test_single_encoding_strategy_curve_st_eth:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004110339de0a348f6dc0822b93a4b3764aabd9a7fdd3b248c3baae2a341158a1ff138941375145748d7a6f194808e5a68299882ef00b89bddb95f3d9215fe5db39f1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_single_encoding_strategy_curve:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041ff461fe60fbd9ac8baec2452c4a242f4e4258cb54aa5df5a3cfa4c889be2897628c42ab59513d9aa4d491e22196979e3c1bd4637944f898decee9ae8596586bc1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 -test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684c57f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1f9000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004159eb2cc8eae51e324934272b75187fb7973da58e1fbb52fd1d7c5871995177e26dfd6f50a879b9e3c71295bc2e3ceba72e3293e1382b8057b6690f652c3d6e0a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684c57f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1fa0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000418a77e8497940ec9340946d582c7c1fc77ec54d7f2d6b682f2a86694a7836ff553c72e31bd305d158cf97fccf29391b0f7a92ff3dffc3279d09f7a4e4a27314921b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950101006f01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f5640000001006f01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000 -test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684c57f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1fa0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000418a77e8497940ec9340946d582c7c1fc77ec54d7f2d6b682f2a86694a7836ff553c72e31bd305d158cf97fccf29391b0f7a92ff3dffc3279d09f7a4e4a27314921b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b006f00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010001006f00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8010001005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000 -test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684c57f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1fa0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000411127f13839fe5565558bcbdbd7900f23e1374c99164598d4653eefb4ef66f7e85bd3112c15b9e6f3035119daee4c8b8a1220da90a594ed5eb8613892f8a0171e1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950001005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950001005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 -test_uniswap_v3_curve:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d7006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000 -test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684c57f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006824d1fa000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000419731903580c1d9c9909aad47a91667359491e74c0e41a5aecfd40ff760a61a422d6694e613889897ab59341ea22116436db9f8267450b8af94e463d5402e700c1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021600525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001003ede3eca2a72b3aecc820e955b36f38437d013950072a0cb889707d426a7a386870a03bc70d1b069759800013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006df62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000 +test_uniswap_v3_uniswap_v2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c0006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100 +test_single_encoding_strategy_ekubo:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000072a0cb889707d426a7a386870a03bc70d1b06975980000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c0000000000000000000000000000000000000000000000000000 +test_uniswap_v3_uniswap_v3:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100006a2e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc350100010000000000000000 +test_balancer_v2_uniswap_v2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 +test_sequential_swap_strategy_encoder_no_permit2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_grouped_swap:a93aabdf000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041d36eb2be80356e97c2d0e7726d39deee88a0783625003cd5798d6bcabc0caac13a3d993f6b54b919a882d87d21610bef3538f2129297e1511a42bbdb2ee92ce61b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d2311933000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_out:308f3ce000000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041b667ad8daec1244238531f2a04241abe60ec826e6df8497f38deeab4a9dac8d27feffca7c9fd592314a6e5b439e583e3d698ebf2cedf4bab314158516d8ef2db1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007400720001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_sequential_swap_strategy_encoder:740bae0c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041352d42752c363d0b5bf0bdfc57e7fbfe7a4e96bddb9f647ab8a477d8c4b04b1633e1de502b4b5ae1e6bf2a234d82c14531b3e87ee8a186605b55cac47f0c86b41c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_no_permit2:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_swap_strategy_encoder_no_transfer_in:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_in:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000414c26afe0fc34a28fd007dd207df3f51839c6c3c7dd4a08676529b3b626df298b3463221a1258f90456b01931559dfda4b644d5cac5f40fc25aaab9aee5b186041b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006df62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000 +test_sequential_strategy_cyclic_swap:740bae0c0000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041dcc698726b46ad05d893791221c8e262d6c36e3acefe39533df3322a5d23061b442569bdd6513fab360cc62f52862325388a4b202e1071e7bad49e276b4977681b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010100006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000000000 +test_single_encoding_strategy_curve_st_eth:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041352d42752c363d0b5bf0bdfc57e7fbfe7a4e96bddb9f647ab8a477d8c4b04b1633e1de502b4b5ae1e6bf2a234d82c14531b3e87ee8a186605b55cac47f0c86b41c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_encoding_strategy_curve:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_unwrap:a93aabdf0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041d4fab3c0f4fd5dc04d1ea95d8f285aef506e5cc64782c2d0ad5f6da3716f1901143b809583220cc27df671bfaccb82911ef7cf90dbd6d534bff0760199085bf61c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 +test_single_swap_strategy_encoder_wrap:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d62e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dceb000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041e035f3359c2b112767b3eae4455a14431e1e5931822cd343989b09529109f280049a9cb9f86e91308bcc37ce189b1d70d5e8e93d10ac13edcf40b93d20f7e04a1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_split_output_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d62e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dceb000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041efb94240d1526a6eeec0fe8b8e6afb3d88a67986fe718693b05030942d55a460339293f146d30223ea99f691ec5ca2ad39cf838c60caed0d98b534bd4b1077dd1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950101006f01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f5640000001006f01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000 +test_split_input_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d62e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dceb000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041efb94240d1526a6eeec0fe8b8e6afb3d88a67986fe718693b05030942d55a460339293f146d30223ea99f691ec5ca2ad39cf838c60caed0d98b534bd4b1077dd1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b006f00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010001006f00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8010001005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000 +test_split_swap_strategy_encoder:308f3ce00000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d62e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dceb000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004105e7ae02a577a9429e46a62b9fdb773227b25dcd25b75f0b6fecc367c315d9f124c90acac65f984544dc2b115f1fd5fb9edb600370af335cdb8548f31efbc2031b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950001005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950001005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 +test_uniswap_v3_curve:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d7006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000 +test_multi_protocol:740bae0c00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684d62e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dceb000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041a4dd23077bc2838b2bc7bdf64e17d9dcdaee7132974b4f9ba15b8e53cdadb89a53cf0e800b6d4d06ae754e213df9929507d3811bff1e9076c9acdedaff9cf8571b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021600525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001003ede3eca2a72b3aecc820e955b36f38437d013950072a0cb889707d426a7a386870a03bc70d1b069759800013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006df62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000 test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0100 test_ekubo_encode_swap_multi:0001ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c599010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c test_encode_uniswap_v4_simple_swap:4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec7010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001 -test_single_encoding_strategy_maverick:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014cf6d2fe3e1b326114b07d22a6f6bb59e346c6700000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_encoding_strategy_maverick:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014cf6d2fe3e1b326114b07d22a6f6bb59e346c6700000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_encode_maverick_v2:40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c671d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e01 +test_encode_uniswap_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0001 diff --git a/foundry/test/executors/EkuboExecutor.t.sol b/foundry/test/executors/EkuboExecutor.t.sol index 8b2026b..b46e983 100644 --- a/foundry/test/executors/EkuboExecutor.t.sol +++ b/foundry/test/executors/EkuboExecutor.t.sol @@ -45,6 +45,7 @@ contract EkuboExecutorTest is Constants, TestUtils { uint256 usdcBalanceBeforeExecutor = USDC.balanceOf(address(executor)); bytes memory data = abi.encodePacked( + false, // transferFromNeeded (transfer user to core) true, // transferNeeded (transfer from executor to core) address(executor), // receiver NATIVE_TOKEN_ADDRESS, // tokenIn @@ -82,6 +83,7 @@ contract EkuboExecutorTest is Constants, TestUtils { uint256 ethBalanceBeforeExecutor = address(executor).balance; bytes memory data = abi.encodePacked( + false, // transferFromNeeded (transfer user to core) true, // transferNeeded (transfer from executor to core) address(executor), // receiver USDC_ADDR, // tokenIn @@ -140,6 +142,7 @@ contract EkuboExecutorTest is Constants, TestUtils { // Same test case as in swap_encoder::tests::ekubo::test_encode_swap_multi function testMultiHopSwap() public { bytes memory data = abi.encodePacked( + false, // transferFromNeeded (transfer user to core) true, // transferNeeded (transfer from executor to core) address(executor), // receiver NATIVE_TOKEN_ADDRESS, // tokenIn diff --git a/foundry/test/executors/UniswapV2Executor.t.sol b/foundry/test/executors/UniswapV2Executor.t.sol index 0f1b2a5..a6a34bd 100644 --- a/foundry/test/executors/UniswapV2Executor.t.sol +++ b/foundry/test/executors/UniswapV2Executor.t.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.26; +import "../TestUtils.sol"; import "@src/executors/UniswapV2Executor.sol"; -import {Test} from "../../lib/forge-std/src/Test.sol"; import {Constants} from "../Constants.sol"; import {Permit2TestHelper} from "../Permit2TestHelper.sol"; +import {Test} from "../../lib/forge-std/src/Test.sol"; contract UniswapV2ExecutorExposed is UniswapV2Executor { constructor( @@ -51,7 +52,7 @@ contract FakeUniswapV2Pool { } } -contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper { +contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { using SafeERC20 for IERC20; UniswapV2ExecutorExposed uniswapV2Exposed; @@ -193,7 +194,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper { function testSwapIntegration() public { bytes memory protocolData = - hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0001"; + loadCallDataFromFile("test_encode_uniswap_v2"); uint256 amountIn = 10 ** 18; uint256 amountOut = 1847751195973566072891; deal(WETH_ADDR, address(uniswapV2Exposed), amountIn); diff --git a/foundry/test/executors/UniswapV3Executor.t.sol b/foundry/test/executors/UniswapV3Executor.t.sol index 9f3e1dd..b3335d4 100644 --- a/foundry/test/executors/UniswapV3Executor.t.sol +++ b/foundry/test/executors/UniswapV3Executor.t.sol @@ -149,11 +149,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { vm.startPrank(DAI_WETH_USV3); bytes memory protocolData = abi.encodePacked( - WETH_ADDR, - DAI_ADDR, - poolFee, - TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL, - address(uniswapV3Exposed) + WETH_ADDR, DAI_ADDR, poolFee, false, true, address(uniswapV3Exposed) ); uint256 dataOffset = 3; // some offset uint256 dataLength = protocolData.length; diff --git a/foundry/test/executors/UniswapV4Utils.sol b/foundry/test/executors/UniswapV4Utils.sol index aa1e5eb..6746ebe 100644 --- a/foundry/test/executors/UniswapV4Utils.sol +++ b/foundry/test/executors/UniswapV4Utils.sol @@ -28,6 +28,7 @@ library UniswapV4Utils { tokenIn, tokenOut, zeroForOne, + transferFromNeeded, transferNeeded, receiver, encodedPools diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index a740638..815fae8 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -52,11 +52,12 @@ impl SingleSwapStrategyEncoder { token_in_already_in_router: bool, ) -> Result { let (permit2, selector) = if let Some(swapper_pk) = swapper_pk { - (Some(Permit2::new(swapper_pk, chain.clone())?), "singleSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) + (Some(Permit2::new(swapper_pk, chain.clone())?), "singleSwapPermit2(uint256,address,address,uint256,bool,bool,address,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) } else { ( None, - "singleSwap(uint256,address,address,uint256,bool,bool,address,bytes)".to_string(), + "singleSwap(uint256,address,address,uint256,bool,bool,address,bool,address,bytes)" + .to_string(), ) }; Ok(Self { @@ -247,11 +248,11 @@ impl SequentialSwapStrategyEncoder { token_in_already_in_router: bool, ) -> Result { let (permit2, selector) = if let Some(swapper_pk) = swapper_pk { - (Some(Permit2::new(swapper_pk, chain.clone())?), "sequentialSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) + (Some(Permit2::new(swapper_pk, chain.clone())?), "sequentialSwapPermit2(uint256,address,address,uint256,bool,bool,address,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) } else { ( None, - "sequentialSwap(uint256,address,address,uint256,bool,bool,address,bytes)" + "sequentialSwap(uint256,address,address,uint256,bool,bool,address,bool,address,bytes)" .to_string(), ) }; @@ -461,11 +462,11 @@ impl SplitSwapStrategyEncoder { token_in_already_in_router: bool, ) -> Result { let (permit2, selector) = if let Some(swapper_pk) = swapper_pk { - (Some(Permit2::new(swapper_pk, chain.clone())?), "splitSwapPermit2(uint256,address,address,uint256,bool,bool,uint256,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) + (Some(Permit2::new(swapper_pk, chain.clone())?), "splitSwapPermit2(uint256,address,address,uint256,bool,bool,uint256,address,bool,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) } else { ( None, - "splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bytes)" + "splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bool,bytes)" .to_string(), ) }; @@ -569,6 +570,9 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { tokens.push(solution.checked_token.clone()); } + let (transfer_from, _funds_receiver, _transfer) = self + .transfer_optimization + .get_transfers(grouped_swaps[0].clone(), wrap); let mut swaps = vec![]; for grouped_swap in grouped_swaps.iter() { let protocol = grouped_swap.protocol_system.clone(); @@ -639,6 +643,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { unwrap, U256::from(tokens_len), bytes_to_address(&solution.receiver)?, + transfer_from, permit, signature.as_bytes().to_vec(), encoded_swaps, @@ -654,6 +659,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { unwrap, U256::from(tokens_len), bytes_to_address(&solution.receiver)?, + transfer_from, encoded_swaps, ) .abi_encode() @@ -782,8 +788,8 @@ mod tests { .unwrap(); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_input = [ - "30ace1b1", // Function selector - "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount out + "a93aabdf", // Function selector + "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out &expected_min_amount_encoded, // min amount out @@ -874,7 +880,7 @@ mod tests { .unwrap(); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_input = [ - "20144a07", // Function selector + "cc60c623", // Function selector "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out @@ -958,7 +964,7 @@ mod tests { .unwrap(); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_input = [ - "20144a07", // Function selector + "cc60c623", // Function selector "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out @@ -1230,7 +1236,7 @@ mod tests { let hex_calldata = encode(&calldata); let expected = String::from(concat!( - "e8a980d7", /* function selector */ + "59e3efbb", /* function selector */ "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token ou @@ -1356,7 +1362,7 @@ mod tests { .unwrap(); let hex_calldata = hex::encode(&calldata); let expected_input = [ - "51bcc7b6", // selector + "740bae0c", // selector "0000000000000000000000000000000000000000000000000000000005f5e100", // given amount "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token @@ -2073,7 +2079,7 @@ mod tests { let hex_calldata = hex::encode(&calldata); let expected_input = [ - "7c553846", // selector + "308f3ce0", // selector "0000000000000000000000000000000000000000000000000000000005f5e100", // given amount "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token @@ -2082,6 +2088,7 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // unwrap action "0000000000000000000000000000000000000000000000000000000000000002", // tokens length "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver + "0000000000000000000000000000000000000000000000000000000000000001", // transfer from ] .join(""); let expected_swaps = [ @@ -2125,8 +2132,8 @@ mod tests { "0000000000" // padding ] .join(""); - assert_eq!(hex_calldata[..520], expected_input); - assert_eq!(hex_calldata[1288..], expected_swaps); + assert_eq!(hex_calldata[..584], expected_input); + assert_eq!(hex_calldata[1352..], expected_swaps); write_calldata_to_file("test_split_input_cyclic_swap", hex_calldata.as_str()); } @@ -2238,7 +2245,7 @@ mod tests { let hex_calldata = hex::encode(&calldata); let expected_input = [ - "7c553846", // selector + "308f3ce0", // selector "0000000000000000000000000000000000000000000000000000000005f5e100", // given amount "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token @@ -2247,6 +2254,7 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // unwrap action "0000000000000000000000000000000000000000000000000000000000000002", // tokens length "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver + "0000000000000000000000000000000000000000000000000000000000000001", // transfer from ] .join(""); @@ -2292,8 +2300,8 @@ mod tests { ] .join(""); - assert_eq!(hex_calldata[..520], expected_input); - assert_eq!(hex_calldata[1288..], expected_swaps); + assert_eq!(hex_calldata[..584], expected_input); + assert_eq!(hex_calldata[1352..], expected_swaps); write_calldata_to_file("test_split_output_cyclic_swap", hex_calldata.as_str()); } } @@ -2641,7 +2649,7 @@ mod tests { .unwrap(); let expected_input = [ - "30ace1b1", // Function selector (single swap) + "a93aabdf", // Function selector (single swap) "000000000000000000000000000000000000000000000000000000003b9aca00", // amount in "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in "0000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933", // token out diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index 74cc375..7c1b8f8 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -655,7 +655,7 @@ mod tests { #[test] fn test_encode_uniswap_v2() { let usv2_pool = ProtocolComponent { - id: String::from("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"), + id: String::from("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11"), ..Default::default() }; @@ -668,7 +668,7 @@ mod tests { split: 0f64, }; let encoding_context = EncodingContext { - receiver: Bytes::from("0x0000000000000000000000000000000000000001"), + receiver: Bytes::from("0x1D96F2f6BeF1202E4Ce1Ff6Dad0c2CB002861d3e"), // BOB exact_out: false, router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), @@ -692,15 +692,16 @@ mod tests { // in token "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // component id - "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", + "a478c2975ab1ea89e8196811f51a7b7ade33eb11", // receiver - "0000000000000000000000000000000000000001", + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // zero for one "00", // transfer true "01", )) ); + write_calldata_to_file("test_encode_uniswap_v2", hex_swap.as_str()); } } diff --git a/src/encoding/evm/tycho_encoders.rs b/src/encoding/evm/tycho_encoders.rs index b377477..9dddecf 100644 --- a/src/encoding/evm/tycho_encoders.rs +++ b/src/encoding/evm/tycho_encoders.rs @@ -462,7 +462,7 @@ mod tests { Bytes::from_str("0x3ede3eca2a72b3aecc820e955b36f38437d01395").unwrap() ); // single swap selector - assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "20144a07"); + assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "cc60c623"); } #[test] @@ -487,7 +487,7 @@ mod tests { let transactions = transactions.unwrap(); assert_eq!(transactions.len(), 1); // single swap selector - assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "20144a07"); + assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "cc60c623"); } #[test] @@ -534,7 +534,7 @@ mod tests { assert_eq!(transactions.len(), 1); assert_eq!(transactions[0].value, eth_amount_in); // sequential swap selector - assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "e8a980d7"); + assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "59e3efbb"); } #[test] From b0b98c5e5de7d248f2f98734a8fca3897946861d Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Thu, 15 May 2025 08:23:55 -0400 Subject: [PATCH 05/22] chore: Remove permit2 from executor constructor... whenever not needed. --- foundry/scripts/deploy-executors.js | 96 +++++++++---------- foundry/src/executors/BalancerV2Executor.sol | 2 - foundry/src/executors/CurveExecutor.sol | 2 +- foundry/src/executors/MaverickV2Executor.sol | 2 +- foundry/src/executors/UniswapV2Executor.sol | 7 +- foundry/test/TychoRouterTestSetup.sol | 10 +- .../test/executors/BalancerV2Executor.t.sol | 4 +- foundry/test/executors/CurveExecutor.t.sol | 7 +- .../test/executors/MaverickV2Executor.t.sol | 7 +- .../test/executors/UniswapV2Executor.t.sol | 21 ++-- 10 files changed, 62 insertions(+), 96 deletions(-) diff --git a/foundry/scripts/deploy-executors.js b/foundry/scripts/deploy-executors.js index f6a6364..9192e1c 100644 --- a/foundry/scripts/deploy-executors.js +++ b/foundry/scripts/deploy-executors.js @@ -5,30 +5,27 @@ const hre = require("hardhat"); // Comment out the executors you don't want to deploy const executors_to_deploy = { "ethereum": [ - // USV2 - Args: Factory, Pool Init Code Hash, Permit2, Fee BPS + // USV2 - Args: Factory, Pool Init Code Hash, Fee BPS { exchange: "UniswapV2Executor", args: [ "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f", "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f", - "0x000000000022D473030F116dDEE9F6B43aC78BA3", 30 ] }, - // SUSHISWAP - Args: Factory, Pool Init Code Hash, Fee BPS, Permit2, Fee BPS + // SUSHISWAP - Args: Factory, Pool Init Code Hash, Fee BPS, Fee BPS { exchange: "UniswapV2Executor", args: [ "0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac", "0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303", - "0x000000000022D473030F116dDEE9F6B43aC78BA3", 30 ] }, - // PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash, Permit2, Fee BPS + // PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash, Fee BPS { exchange: "UniswapV2Executor", args: [ "0x1097053Fd2ea711dad45caCcc45EfF7548fCB362", "0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d", - "0x000000000022D473030F116dDEE9F6B43aC78BA3", 25 ] }, @@ -53,8 +50,8 @@ const executors_to_deploy = { "0x000000000004444c5dc75cB358380D2e3dE08A90", "0x000000000022D473030F116dDEE9F6B43aC78BA3" ]}, - // Args: Permit2 - {exchange: "BalancerV2Executor", args: ["0x000000000022D473030F116dDEE9F6B43aC78BA3"]}, + // Args: None + {exchange: "BalancerV2Executor", args: []}, // Args: Ekubo core contract, Permit2 { exchange: "EkuboExecutor", args: [ @@ -62,69 +59,64 @@ const executors_to_deploy = { "0x000000000022D473030F116dDEE9F6B43aC78BA3" ] }, - // Args: ETH address in curve pools, Permit2 + // Args: ETH address in curve pools { exchange: "CurveExecutor", args: [ - "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", - "0x000000000022D473030F116dDEE9F6B43aC78BA3" + "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" ] } ], "base": [ - // // Args: Factory, Pool Init Code Hash, Permit2, Fee BPS - // { - // exchange: "UniswapV2Executor", args: [ - // "0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6", - // "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f", - // "0x000000000022D473030F116dDEE9F6B43aC78BA3", - // 30 - // ] - // }, - // // SUSHISWAP V2 - Args: Factory, Pool Init Code Hash, Permit2, Fee BPS - // { - // exchange: "UniswapV2Executor", args: [ - // "0x71524B4f93c58fcbF659783284E38825f0622859", - // "0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303", - // "0x000000000022D473030F116dDEE9F6B43aC78BA3", - // 30 - // ] - // }, - // PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash, Permit2, Fee BPS + // Args: Factory, Pool Init Code Hash, Fee BPS + { + exchange: "UniswapV2Executor", args: [ + "0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6", + "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f", + 30 + ] + }, + // SUSHISWAP V2 - Args: Factory, Pool Init Code Hash, Fee BPS + { + exchange: "UniswapV2Executor", args: [ + "0x71524B4f93c58fcbF659783284E38825f0622859", + "0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303", + 30 + ] + }, + // PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash, Fee BPS { exchange: "UniswapV2Executor", args: [ "0x1097053Fd2ea711dad45caCcc45EfF7548fCB362", "0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d", - "0x000000000022D473030F116dDEE9F6B43aC78BA3", 25 ] }, - // // USV3 - Args: Factory, Pool Init Code Hash, Permit2 - // { - // exchange: "UniswapV3Executor", args: [ - // "0x33128a8fC17869897dcE68Ed026d694621f6FDfD", - // "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54", - // "0x000000000022D473030F116dDEE9F6B43aC78BA3" - // ] - // }, - // // PANCAKESWAP V3 - Args: Deployer, Pool Init Code Hash, Permit2 - // { - // exchange: "UniswapV3Executor", args: [ - // "0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9", - // "0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2", - // "0x000000000022D473030F116dDEE9F6B43aC78BA3" - // ] - // }, - // // Args: Pool manager - // {exchange: "UniswapV4Executor", args: ["0x498581ff718922c3f8e6a244956af099b2652b2b"]}, - // {exchange: "BalancerV2Executor", args: []}, + // USV3 - Args: Factory, Pool Init Code Hash, Permit2 + { + exchange: "UniswapV3Executor", args: [ + "0x33128a8fC17869897dcE68Ed026d694621f6FDfD", + "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54", + "0x000000000022D473030F116dDEE9F6B43aC78BA3" + ] + }, + // PANCAKESWAP V3 - Args: Deployer, Pool Init Code Hash, Permit2 + { + exchange: "UniswapV3Executor", args: [ + "0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9", + "0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2", + "0x000000000022D473030F116dDEE9F6B43aC78BA3" + ] + }, + // Args: Pool manager + {exchange: "UniswapV4Executor", args: ["0x498581ff718922c3f8e6a244956af099b2652b2b"]}, + {exchange: "BalancerV2Executor", args: []}, ], "unichain": [ - // Args: Factory, Pool Init Code Hash, Permit2, Fee BPS + // Args: Factory, Pool Init Code Hash, Fee BPS { exchange: "UniswapV2Executor", args: [ "0x1f98400000000000000000000000000000000002", "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f", - "0x000000000022D473030F116dDEE9F6B43aC78BA3", 30 ] }, diff --git a/foundry/src/executors/BalancerV2Executor.sol b/foundry/src/executors/BalancerV2Executor.sol index 016163b..0968cb3 100644 --- a/foundry/src/executors/BalancerV2Executor.sol +++ b/foundry/src/executors/BalancerV2Executor.sol @@ -18,8 +18,6 @@ contract BalancerV2Executor is IExecutor { address private constant VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; - constructor(address _permit2) {} - // slither-disable-next-line locked-ether function swap(uint256 givenAmount, bytes calldata data) external diff --git a/foundry/src/executors/CurveExecutor.sol b/foundry/src/executors/CurveExecutor.sol index f953a63..8bef070 100644 --- a/foundry/src/executors/CurveExecutor.sol +++ b/foundry/src/executors/CurveExecutor.sol @@ -39,7 +39,7 @@ contract CurveExecutor is IExecutor { address public immutable nativeToken; - constructor(address _nativeToken, address _permit2) { + constructor(address _nativeToken) { if (_nativeToken == address(0)) { revert CurveExecutor__AddressZero(); } diff --git a/foundry/src/executors/MaverickV2Executor.sol b/foundry/src/executors/MaverickV2Executor.sol index 24dcd00..f8acbb1 100644 --- a/foundry/src/executors/MaverickV2Executor.sol +++ b/foundry/src/executors/MaverickV2Executor.sol @@ -13,7 +13,7 @@ contract MaverickV2Executor is IExecutor { address public immutable factory; - constructor(address _factory, address _permit2) { + constructor(address _factory) { if (_factory == address(0)) { revert MaverickV2Executor__InvalidFactory(); } diff --git a/foundry/src/executors/UniswapV2Executor.sol b/foundry/src/executors/UniswapV2Executor.sol index d5b1831..753ecef 100644 --- a/foundry/src/executors/UniswapV2Executor.sol +++ b/foundry/src/executors/UniswapV2Executor.sol @@ -19,12 +19,7 @@ contract UniswapV2Executor is IExecutor { address private immutable self; uint256 public immutable feeBps; - constructor( - address _factory, - bytes32 _initCode, - address _permit2, - uint256 _feeBps - ) { + constructor(address _factory, bytes32 _initCode, uint256 _feeBps) { if (_factory == address(0)) { revert UniswapV2Executor__InvalidFactory(); } diff --git a/foundry/test/TychoRouterTestSetup.sol b/foundry/test/TychoRouterTestSetup.sol index 31dd507..8c40ef3 100644 --- a/foundry/test/TychoRouterTestSetup.sol +++ b/foundry/test/TychoRouterTestSetup.sol @@ -101,19 +101,17 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { address ekuboCore = 0xe0e0e08A6A4b9Dc7bD67BCB7aadE5cF48157d444; IPoolManager poolManager = IPoolManager(poolManagerAddress); - usv2Executor = - new UniswapV2Executor(factoryV2, initCodeV2, PERMIT2_ADDRESS, 30); + usv2Executor = new UniswapV2Executor(factoryV2, initCodeV2, 30); usv3Executor = new UniswapV3Executor(factoryV3, initCodeV3, PERMIT2_ADDRESS); usv4Executor = new UniswapV4Executor(poolManager, PERMIT2_ADDRESS); pancakev3Executor = new UniswapV3Executor( factoryPancakeV3, initCodePancakeV3, PERMIT2_ADDRESS ); - balancerv2Executor = new BalancerV2Executor(PERMIT2_ADDRESS); + balancerv2Executor = new BalancerV2Executor(); ekuboExecutor = new EkuboExecutor(ekuboCore, PERMIT2_ADDRESS); - curveExecutor = new CurveExecutor(ETH_ADDR_FOR_CURVE, PERMIT2_ADDRESS); - maverickv2Executor = - new MaverickV2Executor(MAVERICK_V2_FACTORY, PERMIT2_ADDRESS); + curveExecutor = new CurveExecutor(ETH_ADDR_FOR_CURVE); + maverickv2Executor = new MaverickV2Executor(MAVERICK_V2_FACTORY); address[] memory executors = new address[](8); executors[0] = address(usv2Executor); diff --git a/foundry/test/executors/BalancerV2Executor.t.sol b/foundry/test/executors/BalancerV2Executor.t.sol index 10cf988..6b33327 100644 --- a/foundry/test/executors/BalancerV2Executor.t.sol +++ b/foundry/test/executors/BalancerV2Executor.t.sol @@ -6,8 +6,6 @@ import "@src/executors/BalancerV2Executor.sol"; import {Constants} from "../Constants.sol"; contract BalancerV2ExecutorExposed is BalancerV2Executor { - constructor(address _permit2) BalancerV2Executor(_permit2) {} - function decodeParams(bytes calldata data) external pure @@ -36,7 +34,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { function setUp() public { uint256 forkBlock = 17323404; vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock); - balancerV2Exposed = new BalancerV2ExecutorExposed(PERMIT2_ADDRESS); + balancerV2Exposed = new BalancerV2ExecutorExposed(); } function testDecodeParams() public view { diff --git a/foundry/test/executors/CurveExecutor.t.sol b/foundry/test/executors/CurveExecutor.t.sol index 3d61d60..0b7e1b7 100644 --- a/foundry/test/executors/CurveExecutor.t.sol +++ b/foundry/test/executors/CurveExecutor.t.sol @@ -22,9 +22,7 @@ interface MetaRegistry { } contract CurveExecutorExposed is CurveExecutor { - constructor(address _nativeToken, address _permit2) - CurveExecutor(_nativeToken, _permit2) - {} + constructor(address _nativeToken) CurveExecutor(_nativeToken) {} function decodeData(bytes calldata data) external @@ -54,8 +52,7 @@ contract CurveExecutorTest is Test, Constants { function setUp() public { uint256 forkBlock = 22031795; vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock); - curveExecutorExposed = - new CurveExecutorExposed(ETH_ADDR_FOR_CURVE, PERMIT2_ADDRESS); + curveExecutorExposed = new CurveExecutorExposed(ETH_ADDR_FOR_CURVE); metaRegistry = MetaRegistry(CURVE_META_REGISTRY); } diff --git a/foundry/test/executors/MaverickV2Executor.t.sol b/foundry/test/executors/MaverickV2Executor.t.sol index 241d265..be7d99e 100644 --- a/foundry/test/executors/MaverickV2Executor.t.sol +++ b/foundry/test/executors/MaverickV2Executor.t.sol @@ -6,9 +6,7 @@ import {Constants} from "../Constants.sol"; import "../TestUtils.sol"; contract MaverickV2ExecutorExposed is MaverickV2Executor { - constructor(address _factory, address _permit2) - MaverickV2Executor(_factory, _permit2) - {} + constructor(address _factory) MaverickV2Executor(_factory) {} function decodeParams(bytes calldata data) external @@ -34,8 +32,7 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { function setUp() public { uint256 forkBlock = 22096000; vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock); - maverickV2Exposed = - new MaverickV2ExecutorExposed(MAVERICK_V2_FACTORY, PERMIT2_ADDRESS); + maverickV2Exposed = new MaverickV2ExecutorExposed(MAVERICK_V2_FACTORY); } function testDecodeParams() public view { diff --git a/foundry/test/executors/UniswapV2Executor.t.sol b/foundry/test/executors/UniswapV2Executor.t.sol index a6a34bd..ef29637 100644 --- a/foundry/test/executors/UniswapV2Executor.t.sol +++ b/foundry/test/executors/UniswapV2Executor.t.sol @@ -8,12 +8,9 @@ import {Permit2TestHelper} from "../Permit2TestHelper.sol"; import {Test} from "../../lib/forge-std/src/Test.sol"; contract UniswapV2ExecutorExposed is UniswapV2Executor { - constructor( - address _factory, - bytes32 _initCode, - address _permit2, - uint256 _feeBps - ) UniswapV2Executor(_factory, _initCode, _permit2, _feeBps) {} + constructor(address _factory, bytes32 _initCode, uint256 _feeBps) + UniswapV2Executor(_factory, _initCode, _feeBps) + {} function decodeParams(bytes calldata data) external @@ -65,19 +62,13 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { uint256 forkBlock = 17323404; vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock); uniswapV2Exposed = new UniswapV2ExecutorExposed( - USV2_FACTORY_ETHEREUM, USV2_POOL_CODE_INIT_HASH, PERMIT2_ADDRESS, 30 + USV2_FACTORY_ETHEREUM, USV2_POOL_CODE_INIT_HASH, 30 ); sushiswapV2Exposed = new UniswapV2ExecutorExposed( - SUSHISWAPV2_FACTORY_ETHEREUM, - SUSHIV2_POOL_CODE_INIT_HASH, - PERMIT2_ADDRESS, - 30 + SUSHISWAPV2_FACTORY_ETHEREUM, SUSHIV2_POOL_CODE_INIT_HASH, 30 ); pancakeswapV2Exposed = new UniswapV2ExecutorExposed( - PANCAKESWAPV2_FACTORY_ETHEREUM, - PANCAKEV2_POOL_CODE_INIT_HASH, - PERMIT2_ADDRESS, - 25 + PANCAKESWAPV2_FACTORY_ETHEREUM, PANCAKEV2_POOL_CODE_INIT_HASH, 25 ); } From 4a0533b8ea261e3c66d09d86ff2c6baec783cf96 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Thu, 15 May 2025 09:15:32 -0400 Subject: [PATCH 06/22] chore: Remove transfer flag from curve + balancer we will never perform a manual transfer into these protocols, as they require the tokens to be in the router contract in order to perform a transferFrom. --- foundry/src/executors/BalancerV2Executor.sol | 9 ++--- foundry/src/executors/CurveExecutor.sol | 7 ++-- foundry/test/assets/calldata.txt | 34 +++++++++---------- .../test/executors/BalancerV2Executor.t.sol | 16 ++++----- foundry/test/executors/CurveExecutor.t.sol | 4 --- .../evm/swap_encoder/swap_encoders.rs | 12 +------ 6 files changed, 29 insertions(+), 53 deletions(-) diff --git a/foundry/src/executors/BalancerV2Executor.sol b/foundry/src/executors/BalancerV2Executor.sol index 0968cb3..fdcbf3f 100644 --- a/foundry/src/executors/BalancerV2Executor.sol +++ b/foundry/src/executors/BalancerV2Executor.sol @@ -29,8 +29,7 @@ contract BalancerV2Executor is IExecutor { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval, - bool transferNeeded + bool needsApproval ) = _decodeData(data); if (needsApproval) { @@ -68,11 +67,10 @@ contract BalancerV2Executor is IExecutor { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval, - bool transferNeeded + bool needsApproval ) { - if (data.length != 94) { + if (data.length != 93) { revert BalancerV2Executor__InvalidDataLength(); } @@ -81,6 +79,5 @@ contract BalancerV2Executor is IExecutor { poolId = bytes32(data[40:72]); receiver = address(bytes20(data[72:92])); needsApproval = uint8(data[92]) > 0; - transferNeeded = uint8(data[93]) > 0; } } diff --git a/foundry/src/executors/CurveExecutor.sol b/foundry/src/executors/CurveExecutor.sol index 8bef070..811abab 100644 --- a/foundry/src/executors/CurveExecutor.sol +++ b/foundry/src/executors/CurveExecutor.sol @@ -52,7 +52,7 @@ contract CurveExecutor is IExecutor { payable returns (uint256) { - if (data.length != 85) revert CurveExecutor__InvalidDataLength(); + if (data.length != 84) revert CurveExecutor__InvalidDataLength(); ( address tokenIn, @@ -62,7 +62,6 @@ contract CurveExecutor is IExecutor { int128 i, int128 j, bool tokenApprovalNeeded, - bool transferNeeded, // TODO remove this with the encoding address receiver ) = _decodeData(data); @@ -121,7 +120,6 @@ contract CurveExecutor is IExecutor { int128 i, int128 j, bool tokenApprovalNeeded, - bool transferNeeded, address receiver ) { @@ -132,8 +130,7 @@ contract CurveExecutor is IExecutor { i = int128(uint128(uint8(data[61]))); j = int128(uint128(uint8(data[62]))); tokenApprovalNeeded = data[63] != 0; - transferNeeded = data[64] != 0; - receiver = address(bytes20(data[65:85])); + receiver = address(bytes20(data[64:84])); } /** diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index bd7751b..61e6bf1 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -1,26 +1,26 @@ test_uniswap_v3_uniswap_v2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c0006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100 test_single_encoding_strategy_ekubo:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000072a0cb889707d426a7a386870a03bc70d1b06975980000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c0000000000000000000000000000000000000000000000000000 test_uniswap_v3_uniswap_v3:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100006a2e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc350100010000000000000000 -test_balancer_v2_uniswap_v2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 +test_balancer_v2_uniswap_v2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c70071c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a4160100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010000000000000000000000000000000000000000000000000000 test_sequential_swap_strategy_encoder_no_permit2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_grouped_swap:a93aabdf000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041d36eb2be80356e97c2d0e7726d39deee88a0783625003cd5798d6bcabc0caac13a3d993f6b54b919a882d87d21610bef3538f2129297e1511a42bbdb2ee92ce61b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d2311933000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_out:308f3ce000000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041b667ad8daec1244238531f2a04241abe60ec826e6df8497f38deeab4a9dac8d27feffca7c9fd592314a6e5b439e583e3d698ebf2cedf4bab314158516d8ef2db1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007400720001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 -test_sequential_swap_strategy_encoder:740bae0c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041352d42752c363d0b5bf0bdfc57e7fbfe7a4e96bddb9f647ab8a477d8c4b04b1633e1de502b4b5ae1e6bf2a234d82c14531b3e87ee8a186605b55cac47f0c86b41c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_grouped_swap:a93aabdf000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000684d72ce00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd6000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000415c18790d36a0420f1cac0df3d0ba29b0d572f0c8f55f569da1e5450b8652bd6842566245e444bcb83ee3317033b444b926d83ce8e8c4e377b995d09af3b5d6db1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d2311933000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_out:308f3ce000000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000684d72ce00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd6000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041d90f0c317d617887369cf71660adf8956d78445e7630b50bc34e7eb13347a44e7618d3c793a06845e4c8d6885d55cea9604748f880b48ddd8c72d660d17ebf011c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007400720001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_sequential_swap_strategy_encoder:740bae0c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041835a42c4483afdfc2bc6cf9f8f6188d3dcb3ae59eb79d7c3143903caac1ea2813f0c443081232c8e5fd1db933571ea0ff18a5bfc977b8501ebe86bb12e6be7561c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 test_single_swap_strategy_encoder_no_permit2:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_single_swap_strategy_encoder_no_transfer_in:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_in:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000414c26afe0fc34a28fd007dd207df3f51839c6c3c7dd4a08676529b3b626df298b3463221a1258f90456b01931559dfda4b644d5cac5f40fc25aaab9aee5b186041b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006df62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000 -test_sequential_strategy_cyclic_swap:740bae0c0000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041dcc698726b46ad05d893791221c8e262d6c36e3acefe39533df3322a5d23061b442569bdd6513fab360cc62f52862325388a4b202e1071e7bad49e276b4977681b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010100006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000000000 -test_single_encoding_strategy_curve_st_eth:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041352d42752c363d0b5bf0bdfc57e7fbfe7a4e96bddb9f647ab8a477d8c4b04b1633e1de502b4b5ae1e6bf2a234d82c14531b3e87ee8a186605b55cac47f0c86b41c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_single_encoding_strategy_curve:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_unwrap:a93aabdf0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000684d62e200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dcea000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041d4fab3c0f4fd5dc04d1ea95d8f285aef506e5cc64782c2d0ad5f6da3716f1901143b809583220cc27df671bfaccb82911ef7cf90dbd6d534bff0760199085bf61c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 -test_single_swap_strategy_encoder_wrap:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d62e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dceb000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041e035f3359c2b112767b3eae4455a14431e1e5931822cd343989b09529109f280049a9cb9f86e91308bcc37ce189b1d70d5e8e93d10ac13edcf40b93d20f7e04a1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_split_output_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d62e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dceb000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041efb94240d1526a6eeec0fe8b8e6afb3d88a67986fe718693b05030942d55a460339293f146d30223ea99f691ec5ca2ad39cf838c60caed0d98b534bd4b1077dd1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950101006f01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f5640000001006f01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000 -test_split_input_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d62e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dceb000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041efb94240d1526a6eeec0fe8b8e6afb3d88a67986fe718693b05030942d55a460339293f146d30223ea99f691ec5ca2ad39cf838c60caed0d98b534bd4b1077dd1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b006f00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010001006f00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8010001005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000 -test_split_swap_strategy_encoder:308f3ce00000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d62e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dceb000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004105e7ae02a577a9429e46a62b9fdb773227b25dcd25b75f0b6fecc367c315d9f124c90acac65f984544dc2b115f1fd5fb9edb600370af335cdb8548f31efbc2031b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950001005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950001005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 -test_uniswap_v3_curve:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d7006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000 -test_multi_protocol:740bae0c00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684d62e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825dceb000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041a4dd23077bc2838b2bc7bdf64e17d9dcdaee7132974b4f9ba15b8e53cdadb89a53cf0e800b6d4d06ae754e213df9929507d3811bff1e9076c9acdedaff9cf8571b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021600525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001003ede3eca2a72b3aecc820e955b36f38437d013950072a0cb889707d426a7a386870a03bc70d1b069759800013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006df62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000 -test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0100 +test_single_encoding_strategy_usv4_eth_in:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d72ce00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd6000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000410bcde812c4515786a4d21ea0de15a584414b911d45c9d568b0f4e819a4ac2d9376cc0e153bb31f27ee4d6853101786edfe94ce39c43bc3a9e3c1fc40d3b8402e1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006df62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000 +test_sequential_strategy_cyclic_swap:740bae0c0000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000419920fd96ec2a45bd4f6d7e9caa631179fb21d9a66d273a2dda475c4951b464f855672e90ca02ac2f5a93370a36461f16671e337632fe4305727e27584cd7cf0a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010100006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000000000 +test_single_encoding_strategy_curve_st_eth:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000681d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f6702201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041835a42c4483afdfc2bc6cf9f8f6188d3dcb3ae59eb79d7c3143903caac1ea2813f0c443081232c8e5fd1db933571ea0ff18a5bfc977b8501ebe86bb12e6be7561c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_encoding_strategy_curve:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000681d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e7102010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_unwrap:a93aabdf0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041aa978c67b9dee690bb4396a72332977cf4f4875d0e9fbd7eb8868dc0704b6756368f5179d2284da226ce7865c0a6075009159efcdebc764e326f78bd2a36569e1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 +test_single_swap_strategy_encoder_wrap:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004172eeb7ad1ac6873c2a80796f868b9cdaf0e620598939d1f6cd1cde10d637a4e10d945a8ac83d7194bc9f7d9cae32476ef8c4293c65aeb6d90723c18462762f351c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_split_output_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000419920fd96ec2a45bd4f6d7e9caa631179fb21d9a66d273a2dda475c4951b464f855672e90ca02ac2f5a93370a36461f16671e337632fe4305727e27584cd7cf0a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950101006f01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f5640000001006f01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000 +test_split_input_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000419920fd96ec2a45bd4f6d7e9caa631179fb21d9a66d273a2dda475c4951b464f855672e90ca02ac2f5a93370a36461f16671e337632fe4305727e27584cd7cf0a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b006f00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010001006f00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8010001005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000 +test_split_swap_strategy_encoder:308f3ce00000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041835a42c4483afdfc2bc6cf9f8f6188d3dcb3ae59eb79d7c3143903caac1ea2813f0c443081232c8e5fd1db933571ea0ff18a5bfc977b8501ebe86bb12e6be7561c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950001005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950001005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 +test_uniswap_v3_curve:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d6006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000681d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000 +test_multi_protocol:740bae0c00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041372127dfcd5df1f6aa85477d32cb8cea63daa2d43c9aecf2685d9a899ec4e85b3b26279b7de9658a90487a111afee8e87adc2bc8a94d0d3b7452419b1436d0dd1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000071c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d013950100681d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae46030100013ede3eca2a72b3aecc820e955b36f38437d013950072a0cb889707d426a7a386870a03bc70d1b069759800013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006df62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e01 test_ekubo_encode_swap_multi:0001ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c599010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c test_encode_uniswap_v4_simple_swap:4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec7010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001 diff --git a/foundry/test/executors/BalancerV2Executor.t.sol b/foundry/test/executors/BalancerV2Executor.t.sol index 6b33327..3e86df6 100644 --- a/foundry/test/executors/BalancerV2Executor.t.sol +++ b/foundry/test/executors/BalancerV2Executor.t.sol @@ -14,8 +14,7 @@ contract BalancerV2ExecutorExposed is BalancerV2Executor { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval, - bool transferNeeded + bool needsApproval ) { return _decodeData(data); @@ -39,7 +38,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { function testDecodeParams() public view { bytes memory params = abi.encodePacked( - WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, address(2), true, false + WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, address(2), true ); ( @@ -47,8 +46,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval, - bool transferNeeded + bool needsApproval ) = balancerV2Exposed.decodeParams(params); assertEq(address(tokenIn), WETH_ADDR); @@ -68,9 +66,8 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { function testSwap() public { uint256 amountIn = 10 ** 18; - bytes memory protocolData = abi.encodePacked( - WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, BOB, true, false - ); + bytes memory protocolData = + abi.encodePacked(WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, BOB, true); deal(WETH_ADDR, address(balancerV2Exposed), amountIn); uint256 balanceBefore = BAL.balanceOf(BOB); @@ -90,8 +87,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval, - bool transferNeeded + bool needsApproval ) = balancerV2Exposed.decodeParams(protocolData); assertEq(address(tokenIn), WETH_ADDR); diff --git a/foundry/test/executors/CurveExecutor.t.sol b/foundry/test/executors/CurveExecutor.t.sol index 0b7e1b7..b270958 100644 --- a/foundry/test/executors/CurveExecutor.t.sol +++ b/foundry/test/executors/CurveExecutor.t.sol @@ -35,7 +35,6 @@ contract CurveExecutorExposed is CurveExecutor { int128 i, int128 j, bool tokenApprovalNeeded, - bool transferNeeded, address receiver ) { @@ -65,7 +64,6 @@ contract CurveExecutorTest is Test, Constants { uint8(2), uint8(0), true, - false, ALICE ); @@ -77,7 +75,6 @@ contract CurveExecutorTest is Test, Constants { int128 i, int128 j, bool tokenApprovalNeeded, - bool transferNeeded, address receiver ) = curveExecutorExposed.decodeData(data); @@ -291,7 +288,6 @@ contract CurveExecutorTest is Test, Constants { uint8(uint256(uint128(i))), uint8(uint256(uint128(j))), true, - false, receiver ); } diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index 7c1b8f8..c090261 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -284,7 +284,6 @@ impl SwapEncoder for BalancerV2SwapEncoder { component_id, bytes_to_address(&encoding_context.receiver)?, approval_needed, - encoding_context.transfer, ); Ok(args.abi_encode_packed()) } @@ -578,7 +577,6 @@ impl SwapEncoder for CurveSwapEncoder { i.to_be_bytes::<1>(), j.to_be_bytes::<1>(), approval_needed, - encoding_context.transfer, bytes_to_address(&encoding_context.receiver)?, ); @@ -827,9 +825,7 @@ mod tests { // receiver "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // approval needed - "01", - // transfer false - "00", + "01" )) ); write_calldata_to_file("test_encode_balancer_v2", hex_swap.as_str()); @@ -1408,8 +1404,6 @@ mod tests { "01", // approval needed "01", - // transfer false - "00", // receiver, "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" )) @@ -1479,8 +1473,6 @@ mod tests { "00", // approval needed "01", - // transfer false - "00", // receiver "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" )) @@ -1560,8 +1552,6 @@ mod tests { "01", // approval needed "01", - // transfer false - "00", // receiver "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" )) From 09ff7691f8445eb6430957e3d6bc424df6fc76b4 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Thu, 15 May 2025 14:52:43 +0100 Subject: [PATCH 07/22] chore: Make naming consistent: transfer_needed, approval_needed, etc Took 46 minutes --- foundry/src/TychoRouter.sol | 44 ++++++------- foundry/src/executors/BalancerV2Executor.sol | 8 +-- foundry/src/executors/CurveExecutor.sol | 8 +-- foundry/test/assets/calldata.txt | 24 +++---- .../evm/strategy_encoder/strategy_encoders.rs | 62 +++++++++--------- .../transfer_optimizations.rs | 6 +- .../evm/swap_encoder/swap_encoders.rs | 64 +++++++++---------- src/encoding/evm/tycho_encoders.rs | 4 +- src/encoding/models.rs | 9 +-- 9 files changed, 117 insertions(+), 112 deletions(-) diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index ffd6420..d80acb9 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -122,7 +122,7 @@ contract TychoRouter is * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. - * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -136,11 +136,11 @@ contract TychoRouter is bool unwrapEth, uint256 nTokens, address receiver, - bool transferFromRequired, + bool transferFromNeeded, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); - if (transferFromRequired) { + if (transferFromNeeded) { _transfer(address(this)); } return _splitSwapChecked( @@ -176,7 +176,7 @@ contract TychoRouter is * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. - * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swaps Encoded swap graph data containing details of each swap. @@ -192,7 +192,7 @@ contract TychoRouter is bool unwrapEth, uint256 nTokens, address receiver, - bool transferFromRequired, + bool transferFromNeeded, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, bytes calldata swaps @@ -202,7 +202,7 @@ contract TychoRouter is permit2.permit(msg.sender, permitSingle, signature); } tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); - if (transferFromRequired) { + if (transferFromNeeded) { _transfer(address(this)); } @@ -237,8 +237,8 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. - * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -251,12 +251,12 @@ contract TychoRouter is bool wrapEth, bool unwrapEth, address receiver, - bool transferFromRequired, + bool transferFromNeeded, address tokenInReceiver, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); - if (transferFromRequired) { + if (transferFromNeeded) { _transfer(tokenInReceiver); } return _sequentialSwapChecked( @@ -289,8 +289,8 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. - * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swaps Encoded swap graph data containing details of each swap. @@ -305,7 +305,7 @@ contract TychoRouter is bool wrapEth, bool unwrapEth, address receiver, - bool transferFromRequired, + bool transferFromNeeded, address tokenInReceiver, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, @@ -317,7 +317,7 @@ contract TychoRouter is } tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); - if (transferFromRequired) { + if (transferFromNeeded) { _transfer(tokenInReceiver); } return _sequentialSwapChecked( @@ -348,8 +348,8 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. - * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param swapData Encoded swap details. * * @return amountOut The total amount of the output token received by the receiver. @@ -362,12 +362,12 @@ contract TychoRouter is bool wrapEth, bool unwrapEth, address receiver, - bool transferFromRequired, + bool transferFromNeeded, address tokenInReceiver, bytes calldata swapData ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); - if (transferFromRequired) { + if (transferFromNeeded) { _transfer(tokenInReceiver); } return _singleSwap( @@ -400,8 +400,8 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. - * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swapData Encoded swap details. @@ -416,7 +416,7 @@ contract TychoRouter is bool wrapEth, bool unwrapEth, address receiver, - bool transferFromRequired, + bool transferFromNeeded, address tokenInReceiver, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, @@ -427,7 +427,7 @@ contract TychoRouter is permit2.permit(msg.sender, permitSingle, signature); } tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); - if (transferFromRequired) { + if (transferFromNeeded) { _transfer(tokenInReceiver); } return _singleSwap( diff --git a/foundry/src/executors/BalancerV2Executor.sol b/foundry/src/executors/BalancerV2Executor.sol index fdcbf3f..b0a6670 100644 --- a/foundry/src/executors/BalancerV2Executor.sol +++ b/foundry/src/executors/BalancerV2Executor.sol @@ -29,10 +29,10 @@ contract BalancerV2Executor is IExecutor { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval + bool approvalNeeded ) = _decodeData(data); - if (needsApproval) { + if (approvalNeeded) { // slither-disable-next-line unused-return tokenIn.forceApprove(VAULT, type(uint256).max); } @@ -67,7 +67,7 @@ contract BalancerV2Executor is IExecutor { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval + bool approvalNeeded ) { if (data.length != 93) { @@ -78,6 +78,6 @@ contract BalancerV2Executor is IExecutor { tokenOut = IERC20(address(bytes20(data[20:40]))); poolId = bytes32(data[40:72]); receiver = address(bytes20(data[72:92])); - needsApproval = uint8(data[92]) > 0; + approvalNeeded = uint8(data[92]) > 0; } } diff --git a/foundry/src/executors/CurveExecutor.sol b/foundry/src/executors/CurveExecutor.sol index 811abab..2304f69 100644 --- a/foundry/src/executors/CurveExecutor.sol +++ b/foundry/src/executors/CurveExecutor.sol @@ -61,11 +61,11 @@ contract CurveExecutor is IExecutor { uint8 poolType, int128 i, int128 j, - bool tokenApprovalNeeded, + bool approvalNeeded, address receiver ) = _decodeData(data); - if (tokenApprovalNeeded && tokenIn != nativeToken) { + if (approvalNeeded && tokenIn != nativeToken) { // slither-disable-next-line unused-return IERC20(tokenIn).forceApprove(address(pool), type(uint256).max); } @@ -119,7 +119,7 @@ contract CurveExecutor is IExecutor { uint8 poolType, int128 i, int128 j, - bool tokenApprovalNeeded, + bool approvalNeeded, address receiver ) { @@ -129,7 +129,7 @@ contract CurveExecutor is IExecutor { poolType = uint8(data[60]); i = int128(uint128(uint8(data[61]))); j = int128(uint128(uint8(data[62]))); - tokenApprovalNeeded = data[63] != 0; + approvalNeeded = data[63] != 0; receiver = address(bytes20(data[64:84])); } diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index 61e6bf1..4403caa 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -3,23 +3,23 @@ test_single_encoding_strategy_ekubo:cc60c623000000000000000000000000000000000000 test_uniswap_v3_uniswap_v3:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100006a2e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc350100010000000000000000 test_balancer_v2_uniswap_v2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c70071c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a4160100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010000000000000000000000000000000000000000000000000000 test_sequential_swap_strategy_encoder_no_permit2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_grouped_swap:a93aabdf000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000684d72ce00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd6000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000415c18790d36a0420f1cac0df3d0ba29b0d572f0c8f55f569da1e5450b8652bd6842566245e444bcb83ee3317033b444b926d83ce8e8c4e377b995d09af3b5d6db1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d2311933000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_out:308f3ce000000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000684d72ce00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd6000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041d90f0c317d617887369cf71660adf8956d78445e7630b50bc34e7eb13347a44e7618d3c793a06845e4c8d6885d55cea9604748f880b48ddd8c72d660d17ebf011c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007400720001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 -test_sequential_swap_strategy_encoder:740bae0c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041835a42c4483afdfc2bc6cf9f8f6188d3dcb3ae59eb79d7c3143903caac1ea2813f0c443081232c8e5fd1db933571ea0ff18a5bfc977b8501ebe86bb12e6be7561c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_grouped_swap:a93aabdf000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000684d7e5a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f862000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041dca332cf6bf055844312c26de68cf6c13c623e3075d5146a8bd16ecbd9bf04777c860b348ed95a00dcde7101ba2529716ec1a4181ea2d12f19f4303070fa0d8c1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d2311933000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_out:308f3ce000000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000684d7e5a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f862000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041df141aa6b1e7114b4759f64a7caf0fa98abe3e888bf5bba627e6164a74fed18f54d937a3c481aa1d20102f43af4eddc2335799c4c364857c9c67a92c4aad96731b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007400720001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_sequential_swap_strategy_encoder:740bae0c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041b796d9bcd8b1eac1ae64d47ed6761f0155efe363064a86f6b14276d9b5bec20f321e2b45e6e849ea77da6c9217d5c97f9ed99ac117e421ae4355feda62f610181b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 test_single_swap_strategy_encoder_no_permit2:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_single_swap_strategy_encoder_no_transfer_in:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_in:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d72ce00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd6000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000410bcde812c4515786a4d21ea0de15a584414b911d45c9d568b0f4e819a4ac2d9376cc0e153bb31f27ee4d6853101786edfe94ce39c43bc3a9e3c1fc40d3b8402e1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006df62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000 -test_sequential_strategy_cyclic_swap:740bae0c0000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000419920fd96ec2a45bd4f6d7e9caa631179fb21d9a66d273a2dda475c4951b464f855672e90ca02ac2f5a93370a36461f16671e337632fe4305727e27584cd7cf0a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010100006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000000000 +test_single_encoding_strategy_usv4_eth_in:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d7e5a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f862000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041858aedce4f7702229e93d1b5af9511ca0fa7e51bf766f04810ce14cbeffaec823cd4295b467eea641536412f84b2f8f3118197dd719bb83494185fcbbc6925541b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006df62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000 +test_sequential_strategy_cyclic_swap:740bae0c0000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041c5fde4fbb5914f434f5165ec8914873e635ecd74fec6eff68a4fb23c9231e33e5c505a6582e0835cd325c84f77d9c7fe0610c347714ba0c33b631e7b8633feed1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010100006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000000000 test_single_encoding_strategy_curve_st_eth:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000681d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f6702201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041835a42c4483afdfc2bc6cf9f8f6188d3dcb3ae59eb79d7c3143903caac1ea2813f0c443081232c8e5fd1db933571ea0ff18a5bfc977b8501ebe86bb12e6be7561c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_swap_strategy_encoder:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041b796d9bcd8b1eac1ae64d47ed6761f0155efe363064a86f6b14276d9b5bec20f321e2b45e6e849ea77da6c9217d5c97f9ed99ac117e421ae4355feda62f610181b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_single_encoding_strategy_curve:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000681d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e7102010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_unwrap:a93aabdf0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041aa978c67b9dee690bb4396a72332977cf4f4875d0e9fbd7eb8868dc0704b6756368f5179d2284da226ce7865c0a6075009159efcdebc764e326f78bd2a36569e1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 -test_single_swap_strategy_encoder_wrap:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004172eeb7ad1ac6873c2a80796f868b9cdaf0e620598939d1f6cd1cde10d637a4e10d945a8ac83d7194bc9f7d9cae32476ef8c4293c65aeb6d90723c18462762f351c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_split_output_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000419920fd96ec2a45bd4f6d7e9caa631179fb21d9a66d273a2dda475c4951b464f855672e90ca02ac2f5a93370a36461f16671e337632fe4305727e27584cd7cf0a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950101006f01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f5640000001006f01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000 -test_split_input_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000419920fd96ec2a45bd4f6d7e9caa631179fb21d9a66d273a2dda475c4951b464f855672e90ca02ac2f5a93370a36461f16671e337632fe4305727e27584cd7cf0a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b006f00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010001006f00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8010001005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000 -test_split_swap_strategy_encoder:308f3ce00000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041835a42c4483afdfc2bc6cf9f8f6188d3dcb3ae59eb79d7c3143903caac1ea2813f0c443081232c8e5fd1db933571ea0ff18a5bfc977b8501ebe86bb12e6be7561c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950001005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950001005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_unwrap:a93aabdf0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041a6dbc15148f2822173b5ca2070656da74ccc296371af94a2a43aebcb31877a702f07a5d8367939ee89c68b21a2345ab263df1dbadba4fba38614cba9caaea2e01c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 +test_single_swap_strategy_encoder_wrap:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041e841b50cf915823a9e2cf908c12a570318ff52573bc1aec4194e4b1d50b2e2da377fab53e5d3bfabd06a2c9966405f094e27f41d23fe975a8fdf90ac581f990e1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_split_output_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041c5fde4fbb5914f434f5165ec8914873e635ecd74fec6eff68a4fb23c9231e33e5c505a6582e0835cd325c84f77d9c7fe0610c347714ba0c33b631e7b8633feed1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950101006f01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f5640000001006f01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000 +test_split_input_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041c5fde4fbb5914f434f5165ec8914873e635ecd74fec6eff68a4fb23c9231e33e5c505a6582e0835cd325c84f77d9c7fe0610c347714ba0c33b631e7b8633feed1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b006f00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010001006f00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8010001005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000 +test_split_swap_strategy_encoder:308f3ce00000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041b796d9bcd8b1eac1ae64d47ed6761f0155efe363064a86f6b14276d9b5bec20f321e2b45e6e849ea77da6c9217d5c97f9ed99ac117e421ae4355feda62f610181b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950001005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950001005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 test_uniswap_v3_curve:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d6006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000681d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000 -test_multi_protocol:740bae0c00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684d72cf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825ecd7000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041372127dfcd5df1f6aa85477d32cb8cea63daa2d43c9aecf2685d9a899ec4e85b3b26279b7de9658a90487a111afee8e87adc2bc8a94d0d3b7452419b1436d0dd1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000071c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d013950100681d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae46030100013ede3eca2a72b3aecc820e955b36f38437d013950072a0cb889707d426a7a386870a03bc70d1b069759800013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006df62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_multi_protocol:740bae0c00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684d7e5c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f864000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041feb3be192e9ce02a58daeb6787e0f5a4069e44b8683e31de9eb7cdcf809adb6e667f573e1aaab6b091ab1bf5b64adc8b9df6a5193b98768de8dd93a77ee5ae181c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000071c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d013950100681d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae46030100013ede3eca2a72b3aecc820e955b36f38437d013950072a0cb889707d426a7a386870a03bc70d1b069759800013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006df62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e01 test_ekubo_encode_swap_multi:0001ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c599010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 815fae8..cfdc1b7 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -125,7 +125,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { let swap_receiver = if !unwrap { solution.receiver.clone() } else { self.router_address.clone() }; - let (mut transfer_from, mut funds_receiver, transfer) = self + let (mut transfer_from_needed, mut token_in_receiver, transfer_needed) = self .transfer_optimization .get_transfers(grouped_swap.clone(), wrap); let encoding_context = EncodingContext { @@ -134,8 +134,8 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer_from, - transfer, + transfer_from_needed, + transfer_needed, }; let mut grouped_protocol_data: Vec = vec![]; @@ -156,11 +156,13 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { ) { // The first swap is from a callback constrained protocol. This means that the in // transfer needs to happen at callback time and not before. - transfer_from = false; - funds_receiver = Address::ZERO.to_string(); + transfer_from_needed = false; + token_in_receiver = Address::ZERO.to_string(); } - let funds_receiver = Address::from_str(&funds_receiver).map_err(|_| { - EncodingError::FatalError(format!("Invalid funds receiver address: {funds_receiver}")) + let token_in_receiver = Address::from_str(&token_in_receiver).map_err(|_| { + EncodingError::FatalError(format!( + "Invalid funds receiver address: {token_in_receiver}" + )) })?; let method_calldata = if let Some(permit2) = self.permit2.clone() { let (permit, signature) = permit2.get_permit( @@ -177,8 +179,8 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, - transfer_from, - funds_receiver, + transfer_from_needed, + token_in_receiver, permit, signature.as_bytes().to_vec(), swap_data, @@ -193,8 +195,8 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, - transfer_from, - funds_receiver, + transfer_from_needed, + token_in_receiver, swap_data, ) .abi_encode() @@ -307,7 +309,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { NativeAction::Unwrap => unwrap = true, } } - let (mut transfer_from, mut funds_receiver, transfer) = self + let (mut transfer_from_needed, mut token_in_receiver, transfer_needed) = self .transfer_optimization .get_transfers(grouped_swaps[0].clone(), wrap); @@ -331,7 +333,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { next_in_between_swap_optimization_allowed = next_swap_optimization; let in_between_transfer = if i == 0 { - transfer + transfer_needed } else { self.transfer_optimization .get_in_between_transfer(&protocol, in_between_swap_optimization_allowed) @@ -342,8 +344,8 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer_from: if i == 0 { transfer_from } else { false }, - transfer: in_between_transfer, + transfer_from_needed: if i == 0 { transfer_from_needed } else { false }, + transfer_needed: in_between_transfer, }; let mut grouped_protocol_data: Vec = vec![]; @@ -369,11 +371,13 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { ) { // The first swap is from a callback constrained protocol. This means that the in // transfer needs to happen at callback time and not before. - transfer_from = false; - funds_receiver = Address::ZERO.to_string(); + transfer_from_needed = false; + token_in_receiver = Address::ZERO.to_string(); } - let funds_receiver = Address::from_str(&funds_receiver).map_err(|_| { - EncodingError::FatalError(format!("Invalid funds receiver address: {funds_receiver}")) + let token_in_receiver = Address::from_str(&token_in_receiver).map_err(|_| { + EncodingError::FatalError(format!( + "Invalid funds receiver address: {token_in_receiver}" + )) })?; let encoded_swaps = ple_encode(swaps); let method_calldata = if let Some(permit2) = self.permit2.clone() { @@ -391,8 +395,8 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, - transfer_from, - funds_receiver, + transfer_from_needed, + token_in_receiver, permit, signature.as_bytes().to_vec(), encoded_swaps, @@ -407,8 +411,8 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, - transfer_from, - funds_receiver, + transfer_from_needed, + token_in_receiver, encoded_swaps, ) .abi_encode() @@ -570,7 +574,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { tokens.push(solution.checked_token.clone()); } - let (transfer_from, _funds_receiver, _transfer) = self + let (transfer_from_needed, _token_in_receiver, _transfer_needed) = self .transfer_optimization .get_transfers(grouped_swaps[0].clone(), wrap); let mut swaps = vec![]; @@ -589,7 +593,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { } else { self.router_address.clone() }; - let transfer = self + let transfer_needed = self .transfer_optimization .get_in_between_transfer(&protocol, false); let encoding_context = EncodingContext { @@ -598,8 +602,8 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer_from: false, - transfer, + transfer_from_needed: false, + transfer_needed, }; let mut grouped_protocol_data: Vec = vec![]; @@ -643,7 +647,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { unwrap, U256::from(tokens_len), bytes_to_address(&solution.receiver)?, - transfer_from, + transfer_from_needed, permit, signature.as_bytes().to_vec(), encoded_swaps, @@ -659,7 +663,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { unwrap, U256::from(tokens_len), bytes_to_address(&solution.receiver)?, - transfer_from, + transfer_from_needed, encoded_swaps, ) .abi_encode() diff --git a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs index 986e335..eeac6af 100644 --- a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs +++ b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs @@ -60,10 +60,10 @@ impl TransferOptimization { // Transfer from swapper to pool (true, swap.swaps[0].component.id.clone(), false) } - // in transfer is not necessary for these protocols. Only make a transfer if the - // tokens are not already in the router + // in transfer is not necessary for these protocols. Only make a transfer from the swapper + // to the router if the tokens are not already in the router } else if !self.token_in_already_in_router { - // Transfer from swapper to router using permit2. + // Transfer from swapper to router using. (true, self.router_address.to_string(), false) } else { (false, zero_address, false) diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index c090261..cd3c421 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -66,7 +66,7 @@ impl SwapEncoder for UniswapV2SwapEncoder { component_id, bytes_to_address(&encoding_context.receiver)?, zero_to_one, - encoding_context.transfer, + encoding_context.transfer_needed, ); Ok(args.abi_encode_packed()) @@ -129,8 +129,8 @@ impl SwapEncoder for UniswapV3SwapEncoder { bytes_to_address(&encoding_context.receiver)?, component_id, zero_to_one, - encoding_context.transfer_from, - encoding_context.transfer, + encoding_context.transfer_from_needed, + encoding_context.transfer_needed, ); Ok(args.abi_encode_packed()) @@ -207,8 +207,8 @@ impl SwapEncoder for UniswapV4SwapEncoder { group_token_in_address, group_token_out_address, zero_to_one, - encoding_context.transfer_from, - encoding_context.transfer, + encoding_context.transfer_from_needed, + encoding_context.transfer_needed, bytes_to_address(&encoding_context.receiver)?, pool_params, ); @@ -345,8 +345,8 @@ impl SwapEncoder for EkuboSwapEncoder { let mut encoded = vec![]; if encoding_context.group_token_in == swap.token_in { - encoded.extend((encoding_context.transfer_from as u8).to_be_bytes()); - encoded.extend((encoding_context.transfer as u8).to_be_bytes()); + encoded.extend((encoding_context.transfer_from_needed as u8).to_be_bytes()); + encoded.extend((encoding_context.transfer_needed as u8).to_be_bytes()); encoded.extend(bytes_to_address(&encoding_context.receiver)?); encoded.extend(bytes_to_address(&swap.token_in)?); } @@ -621,7 +621,7 @@ impl SwapEncoder for MaverickV2SwapEncoder { bytes_to_address(&swap.token_in)?, component_id, bytes_to_address(&encoding_context.receiver)?, - encoding_context.transfer, + encoding_context.transfer_needed, ); Ok(args.abi_encode_packed()) } @@ -671,8 +671,8 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: true, - transfer_from: false, + transfer_needed: true, + transfer_from_needed: false, }; let encoder = UniswapV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -731,8 +731,8 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: true, - transfer_from: false, + transfer_needed: true, + transfer_from_needed: false, }; let encoder = UniswapV3SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -796,8 +796,8 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: false, - transfer_from: false, + transfer_needed: false, + transfer_from_needed: false, }; let encoder = BalancerV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -869,8 +869,8 @@ mod tests { group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: true, - transfer_from: false, + transfer_needed: true, + transfer_from_needed: false, }; let encoder = UniswapV4SwapEncoder::new( String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"), @@ -943,8 +943,8 @@ mod tests { group_token_in: group_token_in.clone(), // Token out is the same as the group token out group_token_out: token_out.clone(), - transfer: true, - transfer_from: false, + transfer_needed: true, + transfer_from_needed: false, }; let encoder = UniswapV4SwapEncoder::new( @@ -987,8 +987,8 @@ mod tests { router_address: Some(router_address.clone()), group_token_in: usde_address.clone(), group_token_out: wbtc_address.clone(), - transfer: true, - transfer_from: false, + transfer_needed: true, + transfer_from_needed: false, }; // Setup - First sequence: USDE -> USDT @@ -1125,8 +1125,8 @@ mod tests { group_token_out: token_out.clone(), exact_out: false, router_address: Some(Bytes::default()), - transfer: true, - transfer_from: false, + transfer_needed: true, + transfer_from_needed: false, }; let encoder = @@ -1174,8 +1174,8 @@ mod tests { group_token_out: group_token_out.clone(), exact_out: false, router_address: Some(Bytes::default()), - transfer: true, - transfer_from: false, + transfer_needed: true, + transfer_from_needed: false, }; let first_swap = Swap { @@ -1373,8 +1373,8 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: false, - transfer_from: false, + transfer_needed: false, + transfer_from_needed: false, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1442,8 +1442,8 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: false, - transfer_from: false, + transfer_needed: false, + transfer_from_needed: false, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1512,8 +1512,8 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: false, - transfer_from: false, + transfer_needed: false, + transfer_from_needed: false, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1582,8 +1582,8 @@ mod tests { router_address: Some(Bytes::default()), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: true, - transfer_from: false, + transfer_needed: true, + transfer_from_needed: false, }; let encoder = MaverickV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), diff --git a/src/encoding/evm/tycho_encoders.rs b/src/encoding/evm/tycho_encoders.rs index 9dddecf..e3e41eb 100644 --- a/src/encoding/evm/tycho_encoders.rs +++ b/src/encoding/evm/tycho_encoders.rs @@ -279,8 +279,8 @@ impl TychoExecutorEncoder { router_address: None, group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer: true, - transfer_from: false, + transfer_needed: true, + transfer_from_needed: false, }; let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?; grouped_protocol_data.extend(protocol_data); diff --git a/src/encoding/models.rs b/src/encoding/models.rs index d85ed63..961029d 100644 --- a/src/encoding/models.rs +++ b/src/encoding/models.rs @@ -106,8 +106,9 @@ pub struct Transaction { /// solution does not require router address. /// * `group_token_in`: Token to be used as the input for the group swap. /// * `group_token_out`: Token to be used as the output for the group swap. -/// * `transfer_from`: true if the solution requires a transfer from the user to the router or pool. -/// * `transfer`: true if the solution requires a transfer from the router to the pool. +/// * `transfer_from_needed`: true if the solution requires a transfer from the user to the router +/// or pool. +/// * `transfer_needed`: true if the solution requires a transfer from the router to the pool. #[derive(Clone, Debug)] pub struct EncodingContext { pub receiver: Bytes, @@ -115,8 +116,8 @@ pub struct EncodingContext { pub router_address: Option, pub group_token_in: Bytes, pub group_token_out: Bytes, - pub transfer_from: bool, - pub transfer: bool, + pub transfer_from_needed: bool, + pub transfer_needed: bool, } #[derive(Clone, PartialEq, Eq, Hash)] From 69c8325a1d6b0eb2e584215f084b4eac3d016ec8 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Thu, 15 May 2025 10:08:33 -0400 Subject: [PATCH 08/22] chore: OneTransferFromOnly docs + proper slots Also revert instead of returning if multiple `transferFrom`s are attempted - as this signals that encoding is incorrect or has been messed with. --- foundry/src/OneTransferFromOnly.sol | 42 ++++++++++++++++++++--------- foundry/src/TychoRouter.sol | 1 - 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/foundry/src/OneTransferFromOnly.sol b/foundry/src/OneTransferFromOnly.sol index 072ac48..1a92344 100644 --- a/foundry/src/OneTransferFromOnly.sol +++ b/foundry/src/OneTransferFromOnly.sol @@ -5,24 +5,42 @@ import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@permit2/src/interfaces/IAllowanceTransfer.sol"; -error TokenTransfer__AddressZero(); +error OneTransferFromOnly__AddressZero(); +error OneTransferFromOnly__MultipleTransferFrom(); +/** + * @title OneTransferFromOnly - Restrict to one transferFrom on approved params per swap + * @author PropellerHeads Devs + * @dev Restricts to one `transferFrom` (using `permit2` or regular `transferFrom`) + * per swap, while ensuring that the `transferFrom` is only performed on the input + * token and the input amount, from the msg.sender's wallet that calls the main swap + * method. Reverts if multiple `transferFrom`s are attempted. + */ contract OneTransferFromOnly { using SafeERC20 for IERC20; - // this is a stupid name but the compiler was complaining that we already had a permit2 variable in TychoRouter - IAllowanceTransfer public immutable permit2lal; - uint256 private constant _TOKEN_IN_SLOT = 123; - uint256 private constant _AMOUNT_IN_SLOT = 124; - uint256 private constant _IS_PERMIT2_SLOT = 125; - uint256 private constant _SENDER_SLOT = 126; - uint256 private constant _IS_TRANSFER_EXECUTED_SLOT = 127; + IAllowanceTransfer public immutable permit2; + // keccak256("Dispatcher#TOKEN_IN_SLOT") + uint256 private constant _TOKEN_IN_SLOT = + 0x66f353cfe8e3cbe0d03292348fbf0fca32e6e07fa0c2a52b4aac22193ac3b894; + // keccak256("Dispatcher#AMOUNT_IN_SLOT") + uint256 private constant _AMOUNT_IN_SLOT = + 0x1f40aa2d23d66d03722685ce02e5d3a95545dfc8e7c56d1026790aa30be48937; + // keccak256("Dispatcher#IS_PERMIT2_SLOT") + uint256 private constant _IS_PERMIT2_SLOT = + 0x3162c9d1175ca0ca7441f87984fdac41bbfdb13246f42c8bb4414d345da39e2a; + // keccak256("Dispatcher#SENDER_SLOT") + uint256 private constant _SENDER_SLOT = + 0x5dcc7974be5cb30f183f878073999aaa6620995b9e052ab5a713071ff60ae9b5; + // keccak256("Dispatcher#IS_TRANSFER_EXECUTED_SLOT") + uint256 private constant _IS_TRANSFER_EXECUTED_SLOT = + 0x1c64085c839fc2ff0f0aad20613eb6d056a1024e5990211e9eb30824dcd128c2; constructor(address _permit2) { if (_permit2 == address(0)) { - revert TokenTransfer__AddressZero(); + revert OneTransferFromOnly__AddressZero(); } - permit2lal = IAllowanceTransfer(_permit2); + permit2 = IAllowanceTransfer(_permit2); } // slither-disable-next-line assembly @@ -56,12 +74,12 @@ contract OneTransferFromOnly { isTransferExecuted := tload(_IS_TRANSFER_EXECUTED_SLOT) } if (isTransferExecuted) { - return; // or revert? + revert OneTransferFromOnly__MultipleTransferFrom(); } if (isPermit2) { // Permit2.permit is already called from the TychoRouter - permit2lal.transferFrom(sender, receiver, uint160(amount), tokenIn); + permit2.transferFrom(sender, receiver, uint160(amount), tokenIn); assembly { tstore(_IS_TRANSFER_EXECUTED_SLOT, true) } diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 538cc43..773e235 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -73,7 +73,6 @@ contract TychoRouter is ReentrancyGuard, OneTransferFromOnly { - IAllowanceTransfer public immutable permit2; IWETH private immutable _weth; using SafeERC20 for IERC20; From e72657111459dec5e0f50fa7310c4c0a87694627 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Thu, 15 May 2025 15:15:52 +0100 Subject: [PATCH 09/22] ci: Update lint CI Took 8 minutes Took 5 seconds Took 11 seconds Took 11 seconds --- .../workflows/tests-and-lints-template.yaml | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/.github/workflows/tests-and-lints-template.yaml b/.github/workflows/tests-and-lints-template.yaml index 64665c4..6f85b08 100644 --- a/.github/workflows/tests-and-lints-template.yaml +++ b/.github/workflows/tests-and-lints-template.yaml @@ -59,9 +59,12 @@ jobs: git config --global url."https://x-access-token:${{ steps.generate-token.outputs.token }}@github.com".insteadOf ssh://github.com - name: Setup toolchain - uses: dtolnay/rust-toolchain@888c2e1ea69ab0d4330cbf0af1ecc7b68f368cc1 + id: toolchain + uses: actions-rs/toolchain@v1 with: - toolchain: ${{ matrix.toolchain }} + toolchain: nightly + components: rustfmt, clippy + override: true - name: Setup Rust Cache uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 @@ -100,28 +103,20 @@ jobs: echo "https://${{ steps.generate-token.outputs.token }}@github.com" > ~/.git-credentials git config --global url."https://x-access-token:${{ steps.generate-token.outputs.token }}@github.com".insteadOf ssh://github.com - - name: Setup clippy toolchain - stable - uses: dtolnay/rust-toolchain@888c2e1ea69ab0d4330cbf0af1ecc7b68f368cc1 + - name: Setup toolchain + id: toolchain + uses: actions-rs/toolchain@v1 with: - toolchain: stable - components: clippy - + toolchain: nightly + components: rustfmt, clippy + override: true - name: Setup Rust Cache - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - - run: cargo +nightly clippy --workspace --lib --all-targets --all-features -- -D clippy::dbg-macro - env: - RUSTFLAGS: -Dwarnings + - name: Clippy + run: cargo clippy --workspace --all-targets --all-features - - run: cargo check --no-default-features - env: - RUSTFLAGS: -Dwarnings - - - name: Setup rustfmt toolchain - nightly - uses: dtolnay/rust-toolchain@a02741459ec5e501b9843ed30b535ca0a0376ae4 - with: - components: rustfmt - - - run: cargo +nightly fmt --all --check + - name: Rustfmt + run: cargo fmt --all --check From 046775b7aee774a5e31d08575d8e779f6f883555 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Thu, 15 May 2025 16:19:31 +0100 Subject: [PATCH 10/22] feat: Loosen version constrain on tycho-common Took 14 minutes --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34133d7..0a02438 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4445,9 +4445,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tycho-common" -version = "0.66.4" +version = "0.70.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5131fdb21cbd754822b0947fc6c763494531837ba8bb34123f6c7f4f89cb69f7" +checksum = "5237d0e4ab6979a1ca9cdb749a2a97240ca6dc716c0da6f42543960d3141255a" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 9cc28e3..8877db5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ clap = { version = "4.5.3", features = ["derive"] } alloy = { version = "0.9.2", features = ["providers", "rpc-types-eth", "eip712", "signer-local"], optional = true } alloy-sol-types = { version = "0.8.14", optional = true } alloy-primitives = { version = "0.8.9", optional = true } -tycho-common = "^0.66.4" +tycho-common = ">0.66.4" once_cell = "1.20.2" [dev-dependencies] From d21ae45a499d04acd57520b76102e5dfd228496e Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Thu, 15 May 2025 12:52:00 -0400 Subject: [PATCH 11/22] chore: remove unnecessary sender encoding in USV3 --- foundry/src/executors/UniswapV3Executor.sol | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index 9d4e1e1..cc36e11 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -101,7 +101,6 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { bool transferFromNeeded = msgData[175] != 0; bool transferNeeded = msgData[176] != 0; - address sender = address(bytes20(msgData[176:196])); verifyCallback(msgData[132:]); @@ -172,12 +171,7 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { bool transferNeeded ) internal view returns (bytes memory) { return abi.encodePacked( - tokenIn, - tokenOut, - fee, - transferFromNeeded, - transferNeeded, - msg.sender + tokenIn, tokenOut, fee, transferFromNeeded, transferNeeded ); } From 7fd9f611e51ae4bcaa87f11c25e992d220542446 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Thu, 15 May 2025 12:57:53 -0400 Subject: [PATCH 12/22] fix: Initial balance for cyclic swaps This needs to be calculated before we perform a transferFrom in the router! This worked before since we were doing the transferFroms always from inside the executors. --- foundry/src/TychoRouter.sol | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 773e235..e07831a 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -138,6 +138,7 @@ contract TychoRouter is bool transferFromNeeded, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { + uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); if (transferFromNeeded) { _transfer(address(this)); @@ -147,6 +148,7 @@ contract TychoRouter is tokenIn, tokenOut, minAmountOut, + initialBalanceTokenOut, wrapEth, unwrapEth, nTokens, @@ -196,6 +198,7 @@ contract TychoRouter is bytes calldata signature, bytes calldata swaps ) external payable whenNotPaused nonReentrant returns (uint256 amountOut) { + uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); // For native ETH, assume funds already in our router. Else, handle approval. if (tokenIn != address(0)) { permit2.permit(msg.sender, permitSingle, signature); @@ -210,6 +213,7 @@ contract TychoRouter is tokenIn, tokenOut, minAmountOut, + initialBalanceTokenOut, wrapEth, unwrapEth, nTokens, @@ -254,6 +258,7 @@ contract TychoRouter is address tokenInReceiver, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { + uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); if (transferFromNeeded) { _transfer(tokenInReceiver); @@ -263,6 +268,7 @@ contract TychoRouter is tokenIn, tokenOut, minAmountOut, + initialBalanceTokenOut, wrapEth, unwrapEth, receiver, @@ -310,6 +316,7 @@ contract TychoRouter is bytes calldata signature, bytes calldata swaps ) external payable whenNotPaused nonReentrant returns (uint256 amountOut) { + uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); // For native ETH, assume funds already in our router. Else, handle approval. if (tokenIn != address(0)) { permit2.permit(msg.sender, permitSingle, signature); @@ -324,6 +331,7 @@ contract TychoRouter is tokenIn, tokenOut, minAmountOut, + initialBalanceTokenOut, wrapEth, unwrapEth, receiver, @@ -365,6 +373,7 @@ contract TychoRouter is address tokenInReceiver, bytes calldata swapData ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { + uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); if (transferFromNeeded) { _transfer(tokenInReceiver); @@ -374,6 +383,7 @@ contract TychoRouter is tokenIn, tokenOut, minAmountOut, + initialBalanceTokenOut, wrapEth, unwrapEth, receiver, @@ -421,6 +431,7 @@ contract TychoRouter is bytes calldata signature, bytes calldata swapData ) external payable whenNotPaused nonReentrant returns (uint256 amountOut) { + uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); // For native ETH, assume funds already in our router. Else, handle approval. if (tokenIn != address(0)) { permit2.permit(msg.sender, permitSingle, signature); @@ -434,6 +445,7 @@ contract TychoRouter is tokenIn, tokenOut, minAmountOut, + initialBalanceTokenOut, wrapEth, unwrapEth, receiver, @@ -454,6 +466,7 @@ contract TychoRouter is address tokenIn, address tokenOut, uint256 minAmountOut, + uint256 initialBalanceTokenOut, bool wrapEth, bool unwrapEth, uint256 nTokens, @@ -473,7 +486,6 @@ contract TychoRouter is tokenIn = address(_weth); } - uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); amountOut = _splitSwap(amountIn, nTokens, swaps); if (amountOut < minAmountOut) { @@ -508,6 +520,7 @@ contract TychoRouter is address tokenIn, address tokenOut, uint256 minAmountOut, + uint256 initialBalanceTokenOut, bool wrapEth, bool unwrapEth, address receiver, @@ -529,7 +542,6 @@ contract TychoRouter is (address executor, bytes calldata protocolData) = swap_.decodeSingleSwap(); - uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); amountOut = _callSwapOnExecutor(executor, amountIn, protocolData); if (amountOut < minAmountOut) { @@ -564,6 +576,7 @@ contract TychoRouter is address tokenIn, address tokenOut, uint256 minAmountOut, + uint256 initialBalanceTokenOut, bool wrapEth, bool unwrapEth, address receiver, @@ -582,7 +595,6 @@ contract TychoRouter is tokenIn = address(_weth); } - uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); amountOut = _sequentialSwap(amountIn, swaps); if (amountOut < minAmountOut) { From 0b5233ead48288b6f15471b1c0271d597bd178fc Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Thu, 15 May 2025 18:01:27 +0100 Subject: [PATCH 13/22] chore: Improve docstrings and decode bools always the same way Took 26 minutes --- foundry/src/TychoRouter.sol | 21 +++++++++++--------- foundry/src/executors/BalancerV2Executor.sol | 2 +- foundry/src/executors/UniswapV3Executor.sol | 4 ++-- foundry/src/executors/UniswapV4Executor.sol | 6 +++--- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index e07831a..9bfad5a 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -121,7 +121,8 @@ contract TychoRouter is * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the router. + * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -177,7 +178,8 @@ contract TychoRouter is * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the router. + * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swaps Encoded swap graph data containing details of each swap. @@ -240,7 +242,8 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. + * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param swaps Encoded swap graph data containing details of each swap. * @@ -294,8 +297,8 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. - * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. + * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swaps Encoded swap graph data containing details of each swap. @@ -355,8 +358,8 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. - * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. + * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param swapData Encoded swap details. * * @return amountOut The total amount of the output token received by the receiver. @@ -409,8 +412,8 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router. - * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. + * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. + * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swapData Encoded swap details. diff --git a/foundry/src/executors/BalancerV2Executor.sol b/foundry/src/executors/BalancerV2Executor.sol index b0a6670..54958e1 100644 --- a/foundry/src/executors/BalancerV2Executor.sol +++ b/foundry/src/executors/BalancerV2Executor.sol @@ -78,6 +78,6 @@ contract BalancerV2Executor is IExecutor { tokenOut = IERC20(address(bytes20(data[20:40]))); poolId = bytes32(data[40:72]); receiver = address(bytes20(data[72:92])); - approvalNeeded = uint8(data[92]) > 0; + approvalNeeded = data[92] != 0; } } diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index cc36e11..4f0a68a 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -159,8 +159,8 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { receiver = address(bytes20(data[43:63])); target = address(bytes20(data[63:83])); zeroForOne = uint8(data[83]) > 0; - transferFromNeeded = uint8(data[84]) > 0; - transferNeeded = uint8(data[85]) > 0; + transferFromNeeded = data[84] != 0; + transferNeeded = data[85] != 0; } function _makeV3CallbackData( diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index 1867a6e..7b30926 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -155,9 +155,9 @@ contract UniswapV4Executor is tokenIn = address(bytes20(data[0:20])); tokenOut = address(bytes20(data[20:40])); - zeroForOne = (data[40] != 0); - transferFromNeeded = (data[41] != 0); - transferNeeded = (data[42] != 0); + zeroForOne = data[40] != 0; + transferFromNeeded = data[41] != 0; + transferNeeded = data[42] != 0; receiver = address(bytes20(data[43:63])); uint256 poolsLength = (data.length - 63) / 26; // 26 bytes per pool object From 7c26e56a852ce13ad108030a66ab8ac6c2cff214 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Thu, 15 May 2025 13:36:25 -0400 Subject: [PATCH 14/22] test: Ensure revert when attempting two transferFroms --- foundry/test/TychoRouterSplitSwap.t.sol | 70 +++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/foundry/test/TychoRouterSplitSwap.t.sol b/foundry/test/TychoRouterSplitSwap.t.sol index b259b0a..582490c 100644 --- a/foundry/test/TychoRouterSplitSwap.t.sol +++ b/foundry/test/TychoRouterSplitSwap.t.sol @@ -401,6 +401,76 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99654537); } + function testSplitInputIllegalTransfers() public { + // This test attempts to perform multiple `transferFrom`s - which is not + // permitted by the TychoRouter. + // + // The flow is: + // ┌─ (USV3, 60% split) ───┐ + // │ │ + // USDC ──────┤ ├────> WETH + // │ │ + // └─ (USV3, 40% split) ───┘ + uint256 amountIn = 100 * 10 ** 6; + + // Assume funds have already been transferred to tychoRouter + deal(USDC_ADDR, ALICE, amountIn); + vm.startPrank(ALICE); + IERC20(USDC_ADDR).approve(tychoRouterAddr, amountIn); + + bytes memory usdcWethV3Pool1ZeroOneData = encodeUniswapV3Swap( + USDC_ADDR, + WETH_ADDR, + tychoRouterAddr, + USDC_WETH_USV3, + true, + true, // transferFrom swapper required + false // transfer from tycho router to protocol + ); + + bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap( + USDC_ADDR, + WETH_ADDR, + tychoRouterAddr, + USDC_WETH_USV3_2, + true, + true, // transferFrom swapper required + false // transfer from tycho router to protocol + ); + + bytes[] memory swaps = new bytes[](2); + // USDC -> WETH (60% split) + swaps[0] = encodeSplitSwap( + uint8(0), + uint8(1), + (0xffffff * 60) / 100, // 60% + address(usv3Executor), + usdcWethV3Pool1ZeroOneData + ); + // USDC -> WETH (40% remainder) + swaps[1] = encodeSplitSwap( + uint8(0), + uint8(1), + uint24(0), + address(usv3Executor), + usdcWethV3Pool2ZeroOneData + ); + vm.expectRevert(); + tychoRouter.splitSwap( + amountIn, + USDC_ADDR, + WETH_ADDR, + 1, + false, + false, + 2, + ALICE, + false, + pleEncode(swaps) + ); + vm.stopPrank(); + } + function testSplitOutputCyclicSwapInternalMethod() public { // This test has start and end tokens that are the same // The flow is: From ec3d04d565bf042a00937f10b03552736e28fb28 Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Thu, 15 May 2025 13:44:51 -0400 Subject: [PATCH 15/22] chore: remove author from docs --- foundry/src/Dispatcher.sol | 1 - foundry/src/OneTransferFromOnly.sol | 1 - 2 files changed, 2 deletions(-) diff --git a/foundry/src/Dispatcher.sol b/foundry/src/Dispatcher.sol index dcbd1b4..6e5c582 100644 --- a/foundry/src/Dispatcher.sol +++ b/foundry/src/Dispatcher.sol @@ -10,7 +10,6 @@ error Dispatcher__InvalidDataLength(); /** * @title Dispatcher - Dispatch execution to external contracts - * @author PropellerHeads Devs * @dev Provides the ability to delegate execution of swaps to external * contracts. This allows dynamically adding new supported protocols * without needing to upgrade any contracts. External contracts will diff --git a/foundry/src/OneTransferFromOnly.sol b/foundry/src/OneTransferFromOnly.sol index 1a92344..83731c2 100644 --- a/foundry/src/OneTransferFromOnly.sol +++ b/foundry/src/OneTransferFromOnly.sol @@ -10,7 +10,6 @@ error OneTransferFromOnly__MultipleTransferFrom(); /** * @title OneTransferFromOnly - Restrict to one transferFrom on approved params per swap - * @author PropellerHeads Devs * @dev Restricts to one `transferFrom` (using `permit2` or regular `transferFrom`) * per swap, while ensuring that the `transferFrom` is only performed on the input * token and the input amount, from the msg.sender's wallet that calls the main swap From fcd85c047f0de8765ba86f9041cd57ebfd030d3d Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Fri, 16 May 2025 10:49:49 +0100 Subject: [PATCH 16/22] chore: Misc improvements: - Don't use payable(receiver).transfer(amount) and use OpenZeppelin's Address.sendValue instead - In Univ4Executor send funds to the poolManager and not msg.sender - In OneTransferFromOnly: - rename method name - don't pass the sender but hardcode it to caller() (msg.sender) - Move marking the transfer as done up (before we actually transfer) to prevent reentrancy attacks Took 18 minutes --- foundry/src/OneTransferFromOnly.sol | 17 ++++++----------- foundry/src/TychoRouter.sol | 12 ++++++------ foundry/src/executors/EkuboExecutor.sol | 7 ++----- foundry/src/executors/MaverickV2Executor.sol | 4 ++-- foundry/src/executors/UniswapV3Executor.sol | 5 +++-- foundry/src/executors/UniswapV4Executor.sol | 7 ++++--- 6 files changed, 23 insertions(+), 29 deletions(-) diff --git a/foundry/src/OneTransferFromOnly.sol b/foundry/src/OneTransferFromOnly.sol index 83731c2..32bcc70 100644 --- a/foundry/src/OneTransferFromOnly.sol +++ b/foundry/src/OneTransferFromOnly.sol @@ -43,17 +43,16 @@ contract OneTransferFromOnly { } // slither-disable-next-line assembly - function tstoreTransferFromInfo( + function _tstoreTransferFromInfo( address tokenIn, uint256 amountIn, - bool isPermit2, - address sender + bool isPermit2 ) internal { assembly { tstore(_TOKEN_IN_SLOT, tokenIn) tstore(_AMOUNT_IN_SLOT, amountIn) tstore(_IS_PERMIT2_SLOT, isPermit2) - tstore(_SENDER_SLOT, sender) + tstore(_SENDER_SLOT, caller()) tstore(_IS_TRANSFER_EXECUTED_SLOT, false) } } @@ -75,19 +74,15 @@ contract OneTransferFromOnly { if (isTransferExecuted) { revert OneTransferFromOnly__MultipleTransferFrom(); } - + assembly { + tstore(_IS_TRANSFER_EXECUTED_SLOT, true) + } if (isPermit2) { // Permit2.permit is already called from the TychoRouter permit2.transferFrom(sender, receiver, uint160(amount), tokenIn); - assembly { - tstore(_IS_TRANSFER_EXECUTED_SLOT, true) - } } else { // slither-disable-next-line arbitrary-send-erc20 IERC20(tokenIn).safeTransferFrom(sender, receiver, amount); - assembly { - tstore(_IS_TRANSFER_EXECUTED_SLOT, true) - } } } } diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 9bfad5a..06213a2 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -140,7 +140,7 @@ contract TychoRouter is bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); - tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); + _tstoreTransferFromInfo(tokenIn, amountIn, false); if (transferFromNeeded) { _transfer(address(this)); } @@ -205,7 +205,7 @@ contract TychoRouter is if (tokenIn != address(0)) { permit2.permit(msg.sender, permitSingle, signature); } - tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); + _tstoreTransferFromInfo(tokenIn, amountIn, true); if (transferFromNeeded) { _transfer(address(this)); } @@ -262,7 +262,7 @@ contract TychoRouter is bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); - tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); + _tstoreTransferFromInfo(tokenIn, amountIn, false); if (transferFromNeeded) { _transfer(tokenInReceiver); } @@ -325,7 +325,7 @@ contract TychoRouter is permit2.permit(msg.sender, permitSingle, signature); } - tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); + _tstoreTransferFromInfo(tokenIn, amountIn, true); if (transferFromNeeded) { _transfer(tokenInReceiver); } @@ -377,7 +377,7 @@ contract TychoRouter is bytes calldata swapData ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); - tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender); + _tstoreTransferFromInfo(tokenIn, amountIn, false); if (transferFromNeeded) { _transfer(tokenInReceiver); } @@ -439,7 +439,7 @@ contract TychoRouter is if (tokenIn != address(0)) { permit2.permit(msg.sender, permitSingle, signature); } - tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender); + _tstoreTransferFromInfo(tokenIn, amountIn, true); if (transferFromNeeded) { _transfer(tokenInReceiver); } diff --git a/foundry/src/executors/EkuboExecutor.sol b/foundry/src/executors/EkuboExecutor.sol index 90ee2f5..6c556f6 100644 --- a/foundry/src/executors/EkuboExecutor.sol +++ b/foundry/src/executors/EkuboExecutor.sol @@ -12,6 +12,7 @@ import {LibBytes} from "@solady/utils/LibBytes.sol"; import {Config, EkuboPoolKey} from "@ekubo/types/poolKey.sol"; import {MAX_SQRT_RATIO, MIN_SQRT_RATIO} from "@ekubo/types/sqrtRatio.sol"; import "../OneTransferFromOnly.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; contract EkuboExecutor is IExecutor, @@ -204,11 +205,7 @@ contract EkuboExecutor is if (transferFromNeeded) { _transfer(msg.sender); } else if (transferNeeded) { - if (token == address(0)) { - payable(msg.sender).transfer(amount); - } else { - IERC20(token).safeTransfer(msg.sender, amount); - } + IERC20(token).safeTransfer(msg.sender, amount); } } diff --git a/foundry/src/executors/MaverickV2Executor.sol b/foundry/src/executors/MaverickV2Executor.sol index f8acbb1..fab7dc8 100644 --- a/foundry/src/executors/MaverickV2Executor.sol +++ b/foundry/src/executors/MaverickV2Executor.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.26; import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; error MaverickV2Executor__InvalidDataLength(); error MaverickV2Executor__InvalidTarget(); @@ -48,8 +49,7 @@ contract MaverickV2Executor is IExecutor { if (transferNeeded) { if (address(tokenIn) == address(0)) { - // slither-disable-next-line arbitrary-send-eth - payable(target).transfer(givenAmount); + Address.sendValue(payable(target), givenAmount); } else { // slither-disable-next-line arbitrary-send-erc20 tokenIn.safeTransfer(target, givenAmount); diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index 4f0a68a..a8a5d0f 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -6,6 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; import "@interfaces/ICallback.sol"; import {OneTransferFromOnly} from "../OneTransferFromOnly.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; error UniswapV3Executor__InvalidDataLength(); error UniswapV3Executor__InvalidFactory(); @@ -111,7 +112,7 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { _transfer(msg.sender); } else if (transferNeeded) { if (tokenIn == address(0)) { - payable(msg.sender).transfer(amountOwed); + Address.sendValue(payable(msg.sender), amountOwed); } else { IERC20(tokenIn).safeTransfer(msg.sender, amountOwed); } @@ -169,7 +170,7 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { uint24 fee, bool transferFromNeeded, bool transferNeeded - ) internal view returns (bytes memory) { + ) internal pure returns (bytes memory) { return abi.encodePacked( tokenIn, tokenOut, fee, transferFromNeeded, transferNeeded ); diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index 7b30926..52a1910 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -23,6 +23,7 @@ import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol"; import "../OneTransferFromOnly.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; error UniswapV4Executor__InvalidDataLength(); error UniswapV4Executor__NotPoolManager(); @@ -410,14 +411,14 @@ contract UniswapV4Executor is } else { if (transferFromNeeded) { // transferFrom swapper's wallet into the core contract - _transfer(msg.sender); + _transfer(address(poolManager)); } else if (transferNeeded) { address tokenIn = Currency.unwrap(currency); // transfer from router contract into the core contract if (tokenIn == address(0)) { - payable(msg.sender).transfer(amount); + Address.sendValue(payable(address(poolManager)), amount); } else { - IERC20(tokenIn).safeTransfer(msg.sender, amount); + IERC20(tokenIn).safeTransfer(address(poolManager), amount); } } // slither-disable-next-line unused-return From 9b59b8b434d76626ae0ce038082c5ac369fdc01e Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Fri, 16 May 2025 11:23:43 -0400 Subject: [PATCH 17/22] Revert "chore: Remove permit2 from executor constructor..." This reverts commit b0b98c5e5de7d248f2f98734a8fca3897946861d. --- foundry/scripts/deploy-executors.js | 96 ++++++++++--------- foundry/src/executors/BalancerV2Executor.sol | 2 + foundry/src/executors/CurveExecutor.sol | 2 +- foundry/src/executors/MaverickV2Executor.sol | 2 +- foundry/src/executors/UniswapV2Executor.sol | 7 +- foundry/test/TychoRouterTestSetup.sol | 10 +- .../test/executors/BalancerV2Executor.t.sol | 4 +- foundry/test/executors/CurveExecutor.t.sol | 7 +- .../test/executors/MaverickV2Executor.t.sol | 7 +- .../test/executors/UniswapV2Executor.t.sol | 21 ++-- 10 files changed, 96 insertions(+), 62 deletions(-) diff --git a/foundry/scripts/deploy-executors.js b/foundry/scripts/deploy-executors.js index 9192e1c..f6a6364 100644 --- a/foundry/scripts/deploy-executors.js +++ b/foundry/scripts/deploy-executors.js @@ -5,27 +5,30 @@ const hre = require("hardhat"); // Comment out the executors you don't want to deploy const executors_to_deploy = { "ethereum": [ - // USV2 - Args: Factory, Pool Init Code Hash, Fee BPS + // USV2 - Args: Factory, Pool Init Code Hash, Permit2, Fee BPS { exchange: "UniswapV2Executor", args: [ "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f", "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f", + "0x000000000022D473030F116dDEE9F6B43aC78BA3", 30 ] }, - // SUSHISWAP - Args: Factory, Pool Init Code Hash, Fee BPS, Fee BPS + // SUSHISWAP - Args: Factory, Pool Init Code Hash, Fee BPS, Permit2, Fee BPS { exchange: "UniswapV2Executor", args: [ "0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac", "0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303", + "0x000000000022D473030F116dDEE9F6B43aC78BA3", 30 ] }, - // PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash, Fee BPS + // PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash, Permit2, Fee BPS { exchange: "UniswapV2Executor", args: [ "0x1097053Fd2ea711dad45caCcc45EfF7548fCB362", "0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d", + "0x000000000022D473030F116dDEE9F6B43aC78BA3", 25 ] }, @@ -50,8 +53,8 @@ const executors_to_deploy = { "0x000000000004444c5dc75cB358380D2e3dE08A90", "0x000000000022D473030F116dDEE9F6B43aC78BA3" ]}, - // Args: None - {exchange: "BalancerV2Executor", args: []}, + // Args: Permit2 + {exchange: "BalancerV2Executor", args: ["0x000000000022D473030F116dDEE9F6B43aC78BA3"]}, // Args: Ekubo core contract, Permit2 { exchange: "EkuboExecutor", args: [ @@ -59,64 +62,69 @@ const executors_to_deploy = { "0x000000000022D473030F116dDEE9F6B43aC78BA3" ] }, - // Args: ETH address in curve pools + // Args: ETH address in curve pools, Permit2 { exchange: "CurveExecutor", args: [ - "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" + "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", + "0x000000000022D473030F116dDEE9F6B43aC78BA3" ] } ], "base": [ - // Args: Factory, Pool Init Code Hash, Fee BPS - { - exchange: "UniswapV2Executor", args: [ - "0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6", - "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f", - 30 - ] - }, - // SUSHISWAP V2 - Args: Factory, Pool Init Code Hash, Fee BPS - { - exchange: "UniswapV2Executor", args: [ - "0x71524B4f93c58fcbF659783284E38825f0622859", - "0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303", - 30 - ] - }, - // PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash, Fee BPS + // // Args: Factory, Pool Init Code Hash, Permit2, Fee BPS + // { + // exchange: "UniswapV2Executor", args: [ + // "0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6", + // "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f", + // "0x000000000022D473030F116dDEE9F6B43aC78BA3", + // 30 + // ] + // }, + // // SUSHISWAP V2 - Args: Factory, Pool Init Code Hash, Permit2, Fee BPS + // { + // exchange: "UniswapV2Executor", args: [ + // "0x71524B4f93c58fcbF659783284E38825f0622859", + // "0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303", + // "0x000000000022D473030F116dDEE9F6B43aC78BA3", + // 30 + // ] + // }, + // PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash, Permit2, Fee BPS { exchange: "UniswapV2Executor", args: [ "0x1097053Fd2ea711dad45caCcc45EfF7548fCB362", "0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d", + "0x000000000022D473030F116dDEE9F6B43aC78BA3", 25 ] }, - // USV3 - Args: Factory, Pool Init Code Hash, Permit2 - { - exchange: "UniswapV3Executor", args: [ - "0x33128a8fC17869897dcE68Ed026d694621f6FDfD", - "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54", - "0x000000000022D473030F116dDEE9F6B43aC78BA3" - ] - }, - // PANCAKESWAP V3 - Args: Deployer, Pool Init Code Hash, Permit2 - { - exchange: "UniswapV3Executor", args: [ - "0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9", - "0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2", - "0x000000000022D473030F116dDEE9F6B43aC78BA3" - ] - }, - // Args: Pool manager - {exchange: "UniswapV4Executor", args: ["0x498581ff718922c3f8e6a244956af099b2652b2b"]}, - {exchange: "BalancerV2Executor", args: []}, + // // USV3 - Args: Factory, Pool Init Code Hash, Permit2 + // { + // exchange: "UniswapV3Executor", args: [ + // "0x33128a8fC17869897dcE68Ed026d694621f6FDfD", + // "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54", + // "0x000000000022D473030F116dDEE9F6B43aC78BA3" + // ] + // }, + // // PANCAKESWAP V3 - Args: Deployer, Pool Init Code Hash, Permit2 + // { + // exchange: "UniswapV3Executor", args: [ + // "0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9", + // "0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2", + // "0x000000000022D473030F116dDEE9F6B43aC78BA3" + // ] + // }, + // // Args: Pool manager + // {exchange: "UniswapV4Executor", args: ["0x498581ff718922c3f8e6a244956af099b2652b2b"]}, + // {exchange: "BalancerV2Executor", args: []}, ], "unichain": [ - // Args: Factory, Pool Init Code Hash, Fee BPS + // Args: Factory, Pool Init Code Hash, Permit2, Fee BPS { exchange: "UniswapV2Executor", args: [ "0x1f98400000000000000000000000000000000002", "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f", + "0x000000000022D473030F116dDEE9F6B43aC78BA3", 30 ] }, diff --git a/foundry/src/executors/BalancerV2Executor.sol b/foundry/src/executors/BalancerV2Executor.sol index 54958e1..02b272b 100644 --- a/foundry/src/executors/BalancerV2Executor.sol +++ b/foundry/src/executors/BalancerV2Executor.sol @@ -18,6 +18,8 @@ contract BalancerV2Executor is IExecutor { address private constant VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; + constructor(address _permit2) {} + // slither-disable-next-line locked-ether function swap(uint256 givenAmount, bytes calldata data) external diff --git a/foundry/src/executors/CurveExecutor.sol b/foundry/src/executors/CurveExecutor.sol index 2304f69..a3f2030 100644 --- a/foundry/src/executors/CurveExecutor.sol +++ b/foundry/src/executors/CurveExecutor.sol @@ -39,7 +39,7 @@ contract CurveExecutor is IExecutor { address public immutable nativeToken; - constructor(address _nativeToken) { + constructor(address _nativeToken, address _permit2) { if (_nativeToken == address(0)) { revert CurveExecutor__AddressZero(); } diff --git a/foundry/src/executors/MaverickV2Executor.sol b/foundry/src/executors/MaverickV2Executor.sol index fab7dc8..a7c9cee 100644 --- a/foundry/src/executors/MaverickV2Executor.sol +++ b/foundry/src/executors/MaverickV2Executor.sol @@ -14,7 +14,7 @@ contract MaverickV2Executor is IExecutor { address public immutable factory; - constructor(address _factory) { + constructor(address _factory, address _permit2) { if (_factory == address(0)) { revert MaverickV2Executor__InvalidFactory(); } diff --git a/foundry/src/executors/UniswapV2Executor.sol b/foundry/src/executors/UniswapV2Executor.sol index 753ecef..d5b1831 100644 --- a/foundry/src/executors/UniswapV2Executor.sol +++ b/foundry/src/executors/UniswapV2Executor.sol @@ -19,7 +19,12 @@ contract UniswapV2Executor is IExecutor { address private immutable self; uint256 public immutable feeBps; - constructor(address _factory, bytes32 _initCode, uint256 _feeBps) { + constructor( + address _factory, + bytes32 _initCode, + address _permit2, + uint256 _feeBps + ) { if (_factory == address(0)) { revert UniswapV2Executor__InvalidFactory(); } diff --git a/foundry/test/TychoRouterTestSetup.sol b/foundry/test/TychoRouterTestSetup.sol index 8c40ef3..31dd507 100644 --- a/foundry/test/TychoRouterTestSetup.sol +++ b/foundry/test/TychoRouterTestSetup.sol @@ -101,17 +101,19 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { address ekuboCore = 0xe0e0e08A6A4b9Dc7bD67BCB7aadE5cF48157d444; IPoolManager poolManager = IPoolManager(poolManagerAddress); - usv2Executor = new UniswapV2Executor(factoryV2, initCodeV2, 30); + usv2Executor = + new UniswapV2Executor(factoryV2, initCodeV2, PERMIT2_ADDRESS, 30); usv3Executor = new UniswapV3Executor(factoryV3, initCodeV3, PERMIT2_ADDRESS); usv4Executor = new UniswapV4Executor(poolManager, PERMIT2_ADDRESS); pancakev3Executor = new UniswapV3Executor( factoryPancakeV3, initCodePancakeV3, PERMIT2_ADDRESS ); - balancerv2Executor = new BalancerV2Executor(); + balancerv2Executor = new BalancerV2Executor(PERMIT2_ADDRESS); ekuboExecutor = new EkuboExecutor(ekuboCore, PERMIT2_ADDRESS); - curveExecutor = new CurveExecutor(ETH_ADDR_FOR_CURVE); - maverickv2Executor = new MaverickV2Executor(MAVERICK_V2_FACTORY); + curveExecutor = new CurveExecutor(ETH_ADDR_FOR_CURVE, PERMIT2_ADDRESS); + maverickv2Executor = + new MaverickV2Executor(MAVERICK_V2_FACTORY, PERMIT2_ADDRESS); address[] memory executors = new address[](8); executors[0] = address(usv2Executor); diff --git a/foundry/test/executors/BalancerV2Executor.t.sol b/foundry/test/executors/BalancerV2Executor.t.sol index 3e86df6..46b2ffd 100644 --- a/foundry/test/executors/BalancerV2Executor.t.sol +++ b/foundry/test/executors/BalancerV2Executor.t.sol @@ -6,6 +6,8 @@ import "@src/executors/BalancerV2Executor.sol"; import {Constants} from "../Constants.sol"; contract BalancerV2ExecutorExposed is BalancerV2Executor { + constructor(address _permit2) BalancerV2Executor(_permit2) {} + function decodeParams(bytes calldata data) external pure @@ -33,7 +35,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { function setUp() public { uint256 forkBlock = 17323404; vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock); - balancerV2Exposed = new BalancerV2ExecutorExposed(); + balancerV2Exposed = new BalancerV2ExecutorExposed(PERMIT2_ADDRESS); } function testDecodeParams() public view { diff --git a/foundry/test/executors/CurveExecutor.t.sol b/foundry/test/executors/CurveExecutor.t.sol index b270958..3d5621e 100644 --- a/foundry/test/executors/CurveExecutor.t.sol +++ b/foundry/test/executors/CurveExecutor.t.sol @@ -22,7 +22,9 @@ interface MetaRegistry { } contract CurveExecutorExposed is CurveExecutor { - constructor(address _nativeToken) CurveExecutor(_nativeToken) {} + constructor(address _nativeToken, address _permit2) + CurveExecutor(_nativeToken, _permit2) + {} function decodeData(bytes calldata data) external @@ -51,7 +53,8 @@ contract CurveExecutorTest is Test, Constants { function setUp() public { uint256 forkBlock = 22031795; vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock); - curveExecutorExposed = new CurveExecutorExposed(ETH_ADDR_FOR_CURVE); + curveExecutorExposed = + new CurveExecutorExposed(ETH_ADDR_FOR_CURVE, PERMIT2_ADDRESS); metaRegistry = MetaRegistry(CURVE_META_REGISTRY); } diff --git a/foundry/test/executors/MaverickV2Executor.t.sol b/foundry/test/executors/MaverickV2Executor.t.sol index be7d99e..241d265 100644 --- a/foundry/test/executors/MaverickV2Executor.t.sol +++ b/foundry/test/executors/MaverickV2Executor.t.sol @@ -6,7 +6,9 @@ import {Constants} from "../Constants.sol"; import "../TestUtils.sol"; contract MaverickV2ExecutorExposed is MaverickV2Executor { - constructor(address _factory) MaverickV2Executor(_factory) {} + constructor(address _factory, address _permit2) + MaverickV2Executor(_factory, _permit2) + {} function decodeParams(bytes calldata data) external @@ -32,7 +34,8 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { function setUp() public { uint256 forkBlock = 22096000; vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock); - maverickV2Exposed = new MaverickV2ExecutorExposed(MAVERICK_V2_FACTORY); + maverickV2Exposed = + new MaverickV2ExecutorExposed(MAVERICK_V2_FACTORY, PERMIT2_ADDRESS); } function testDecodeParams() public view { diff --git a/foundry/test/executors/UniswapV2Executor.t.sol b/foundry/test/executors/UniswapV2Executor.t.sol index ef29637..a6a34bd 100644 --- a/foundry/test/executors/UniswapV2Executor.t.sol +++ b/foundry/test/executors/UniswapV2Executor.t.sol @@ -8,9 +8,12 @@ import {Permit2TestHelper} from "../Permit2TestHelper.sol"; import {Test} from "../../lib/forge-std/src/Test.sol"; contract UniswapV2ExecutorExposed is UniswapV2Executor { - constructor(address _factory, bytes32 _initCode, uint256 _feeBps) - UniswapV2Executor(_factory, _initCode, _feeBps) - {} + constructor( + address _factory, + bytes32 _initCode, + address _permit2, + uint256 _feeBps + ) UniswapV2Executor(_factory, _initCode, _permit2, _feeBps) {} function decodeParams(bytes calldata data) external @@ -62,13 +65,19 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { uint256 forkBlock = 17323404; vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock); uniswapV2Exposed = new UniswapV2ExecutorExposed( - USV2_FACTORY_ETHEREUM, USV2_POOL_CODE_INIT_HASH, 30 + USV2_FACTORY_ETHEREUM, USV2_POOL_CODE_INIT_HASH, PERMIT2_ADDRESS, 30 ); sushiswapV2Exposed = new UniswapV2ExecutorExposed( - SUSHISWAPV2_FACTORY_ETHEREUM, SUSHIV2_POOL_CODE_INIT_HASH, 30 + SUSHISWAPV2_FACTORY_ETHEREUM, + SUSHIV2_POOL_CODE_INIT_HASH, + PERMIT2_ADDRESS, + 30 ); pancakeswapV2Exposed = new UniswapV2ExecutorExposed( - PANCAKESWAPV2_FACTORY_ETHEREUM, PANCAKEV2_POOL_CODE_INIT_HASH, 25 + PANCAKESWAPV2_FACTORY_ETHEREUM, + PANCAKEV2_POOL_CODE_INIT_HASH, + PERMIT2_ADDRESS, + 25 ); } From 38748925b3fcc9daab1df981ee474c1939a1fadd Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Fri, 16 May 2025 16:59:35 +0100 Subject: [PATCH 18/22] feat: Bring back TransferType and simplify encoding logic Took 1 hour 53 minutes --- foundry/test/assets/calldata.txt | 54 ++--- .../evm/strategy_encoder/strategy_encoders.rs | 213 ++++++------------ .../transfer_optimizations.rs | 135 +++++------ .../evm/swap_encoder/swap_encoders.rs | 91 ++++---- src/encoding/evm/tycho_encoders.rs | 24 +- src/encoding/models.rs | 22 +- 6 files changed, 230 insertions(+), 309 deletions(-) diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index 4403caa..bd2ab1f 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -1,29 +1,29 @@ -test_uniswap_v3_uniswap_v2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c0006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100 -test_single_encoding_strategy_ekubo:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000072a0cb889707d426a7a386870a03bc70d1b06975980000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c0000000000000000000000000000000000000000000000000000 -test_uniswap_v3_uniswap_v3:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100006a2e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc350100010000000000000000 -test_balancer_v2_uniswap_v2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000c70071c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a4160100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010000000000000000000000000000000000000000000000000000 -test_sequential_swap_strategy_encoder_no_permit2:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_grouped_swap:a93aabdf000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000684d7e5a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f862000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041dca332cf6bf055844312c26de68cf6c13c623e3075d5146a8bd16ecbd9bf04777c860b348ed95a00dcde7101ba2529716ec1a4181ea2d12f19f4303070fa0d8c1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d2311933000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_out:308f3ce000000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000684d7e5a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f862000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041df141aa6b1e7114b4759f64a7caf0fa98abe3e888bf5bba627e6164a74fed18f54d937a3c481aa1d20102f43af4eddc2335799c4c364857c9c67a92c4aad96731b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007400720001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 -test_sequential_swap_strategy_encoder:740bae0c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041b796d9bcd8b1eac1ae64d47ed6761f0155efe363064a86f6b14276d9b5bec20f321e2b45e6e849ea77da6c9217d5c97f9ed99ac117e421ae4355feda62f610181b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100000000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_no_permit2:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_single_swap_strategy_encoder_no_transfer_in:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_in:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d7e5a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f862000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041858aedce4f7702229e93d1b5af9511ca0fa7e51bf766f04810ce14cbeffaec823cd4295b467eea641536412f84b2f8f3118197dd719bb83494185fcbbc6925541b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006df62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933010000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000 -test_sequential_strategy_cyclic_swap:740bae0c0000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041c5fde4fbb5914f434f5165ec8914873e635ecd74fec6eff68a4fb23c9231e33e5c505a6582e0835cd325c84f77d9c7fe0610c347714ba0c33b631e7b8633feed1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d8006a2e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010100006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000000000 -test_single_encoding_strategy_curve_st_eth:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000681d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f6702201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041b796d9bcd8b1eac1ae64d47ed6761f0155efe363064a86f6b14276d9b5bec20f321e2b45e6e849ea77da6c9217d5c97f9ed99ac117e421ae4355feda62f610181b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_single_encoding_strategy_curve:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000681d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e7102010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_unwrap:a93aabdf0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041a6dbc15148f2822173b5ca2070656da74ccc296371af94a2a43aebcb31877a702f07a5d8367939ee89c68b21a2345ab263df1dbadba4fba38614cba9caaea2e01c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 -test_single_swap_strategy_encoder_wrap:a93aabdf0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041e841b50cf915823a9e2cf908c12a570318ff52573bc1aec4194e4b1d50b2e2da377fab53e5d3bfabd06a2c9966405f094e27f41d23fe975a8fdf90ac581f990e1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_split_output_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041c5fde4fbb5914f434f5165ec8914873e635ecd74fec6eff68a4fb23c9231e33e5c505a6582e0835cd325c84f77d9c7fe0610c347714ba0c33b631e7b8633feed1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950101006f01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f5640000001006f01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d80000010000000000 -test_split_input_cyclic_swap:308f3ce00000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041c5fde4fbb5914f434f5165ec8914873e635ecd74fec6eff68a4fb23c9231e33e5c505a6582e0835cd325c84f77d9c7fe0610c347714ba0c33b631e7b8633feed1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013b006f00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010001006f00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8010001005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000 -test_split_swap_strategy_encoder:308f3ce00000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684d7e5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f863000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041b796d9bcd8b1eac1ae64d47ed6761f0155efe363064a86f6b14276d9b5bec20f321e2b45e6e849ea77da6c9217d5c97f9ed99ac117e421ae4355feda62f610181b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950001005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950001005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 -test_uniswap_v3_curve:59e3efbb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000d6006a2e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed00010000681d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000 -test_multi_protocol:740bae0c00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684d7e5c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006825f864000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000041feb3be192e9ce02a58daeb6787e0f5a4069e44b8683e31de9eb7cdcf809adb6e667f573e1aaab6b091ab1bf5b64adc8b9df6a5193b98768de8dd93a77ee5ae181c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000071c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d013950100681d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae46030100013ede3eca2a72b3aecc820e955b36f38437d013950072a0cb889707d426a7a386870a03bc70d1b069759800013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006df62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 -test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e01 -test_ekubo_encode_swap_multi:0001ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 -test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c599010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c -test_encode_uniswap_v4_simple_swap:4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec7010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001 -test_single_encoding_strategy_maverick:cc60c6230000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014cf6d2fe3e1b326114b07d22a6f6bb59e346c6700000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_uniswap_v3_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010200 +test_single_encoding_strategy_ekubo:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000071a0cb889707d426a7a386870a03bc70d1b069759802cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000000000000000000000000000000000 +test_uniswap_v3_uniswap_v3:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010100000000000000000000 +test_balancer_v2_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 +test_sequential_swap_strategy_encoder_no_permit2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410fa9c637031c3ab6898496918d2d431cf4a85b8f9fa9b18562528fffead3a3790c5f8a32866004f9275e0eb1f45c0954c373f101c0618e6885b04e3c559f782c1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004104b5583d7915973bc9f0f07d7d33ba6f3fb777ceaee0dd2c023cecb8764e8e72257e0255a7e04bb30096137a0fde38a8191f27b6fcaae371e7ec1799a1f43e441b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000 +test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041261b12a8bd804743e33746b765070f89e4a08bbe8339fce19ea7d180782c1fc82693906dccc47520368b341d3ca32cfe655625bea8f6844d2d95b61492f741881b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_no_permit2:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_swap_strategy_encoder_no_transfer_in:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041a0b72c7e3b647030d4af52974b437f041cdc78474e91115b614f3ee00f573a64797fb56364e9643beaf8effff491bf464388d81c71bc3f2cedd8b8e38b554b7b1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000 +test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041f8df51365aa2a34a1658af57e7add49b53e6f0bdab9b27a00578f07a9b78367224ea5f4b0b79092c6d1361512d60433af612822b910fd6d7eea7caa184ebbb041c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000 +test_single_encoding_strategy_curve_st_eth:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f6702201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2020000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041261b12a8bd804743e33746b765070f89e4a08bbe8339fce19ea7d180782c1fc82693906dccc47520368b341d3ca32cfe655625bea8f6844d2d95b61492f741881b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_encoding_strategy_curve:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e7102010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041579f177eccf39425b9a755adc0c961a0eeff873edcff1dc49ee507f4a3ef10ee36924ff24edd567694929826c77ca3b23a072154b7d815c88352671e480099bf1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 +test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041a0b72c7e3b647030d4af52974b437f041cdc78474e91115b614f3ee00f573a64797fb56364e9643beaf8effff491bf464388d81c71bc3f2cedd8b8e38b554b7b1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f8df51365aa2a34a1658af57e7add49b53e6f0bdab9b27a00578f07a9b78367224ea5f4b0b79092c6d1361512d60433af612822b910fd6d7eea7caa184ebbb041c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000 +test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f8df51365aa2a34a1658af57e7add49b53e6f0bdab9b27a00578f07a9b78367224ea5f4b0b79092c6d1361512d60433af612822b910fd6d7eea7caa184ebbb041c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000 +test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041261b12a8bd804743e33746b765070f89e4a08bbe8339fce19ea7d180782c1fc82693906dccc47520368b341d3ca32cfe655625bea8f6844d2d95b61492f741881b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 +test_uniswap_v3_curve:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20200000000000000000000 +test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684eed6800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827677000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000415d142a1f86e6baa6613d0c8a18d8882027cbeee05c02654ca66fcaaff9cba33f0d17c80da2eaf4084cbe19ea63cca2b453a2c8d46c17cc9f8d3a417a78c534901b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae46030100013ede3eca2a72b3aecc820e955b36f38437d01395020071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0102 +test_ekubo_encode_swap_multi:01ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 +test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c +test_encode_uniswap_v4_simple_swap:4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec70101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001 +test_single_encoding_strategy_maverick:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_encode_maverick_v2:40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c671d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e01 test_encode_uniswap_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0001 diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index cfdc1b7..607ec53 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -1,6 +1,6 @@ use std::{collections::HashSet, str::FromStr}; -use alloy_primitives::{aliases::U24, Address, U256, U8}; +use alloy_primitives::{aliases::U24, U256, U8}; use alloy_sol_types::SolValue; use tycho_common::Bytes; @@ -8,7 +8,6 @@ use crate::encoding::{ errors::EncodingError, evm::{ approvals::permit2::Permit2, - constants::CALLBACK_CONSTRAINED_PROTOCOLS, group_swaps::group_swaps, strategy_encoder::{ strategy_validators::{SequentialSwapValidator, SplitSwapValidator, SwapValidator}, @@ -52,12 +51,11 @@ impl SingleSwapStrategyEncoder { token_in_already_in_router: bool, ) -> Result { let (permit2, selector) = if let Some(swapper_pk) = swapper_pk { - (Some(Permit2::new(swapper_pk, chain.clone())?), "singleSwapPermit2(uint256,address,address,uint256,bool,bool,address,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) + (Some(Permit2::new(swapper_pk, chain.clone())?), "singleSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) } else { ( None, - "singleSwap(uint256,address,address,uint256,bool,bool,address,bool,address,bytes)" - .to_string(), + "singleSwap(uint256,address,address,uint256,bool,bool,address,bytes)".to_string(), ) }; Ok(Self { @@ -125,17 +123,16 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { let swap_receiver = if !unwrap { solution.receiver.clone() } else { self.router_address.clone() }; - let (mut transfer_from_needed, mut token_in_receiver, transfer_needed) = self + let transfer = self .transfer_optimization - .get_transfers(grouped_swap.clone(), wrap); + .get_transfers(grouped_swap.clone(), solution.given_token.clone(), wrap, false); let encoding_context = EncodingContext { receiver: swap_receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer_from_needed, - transfer_needed, + transfer, }; let mut grouped_protocol_data: Vec = vec![]; @@ -149,21 +146,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { .map_err(|_| EncodingError::FatalError("Invalid executor address".to_string()))?, grouped_protocol_data, ); - if CALLBACK_CONSTRAINED_PROTOCOLS.contains( - &grouped_swaps[0] - .protocol_system - .as_str(), - ) { - // The first swap is from a callback constrained protocol. This means that the in - // transfer needs to happen at callback time and not before. - transfer_from_needed = false; - token_in_receiver = Address::ZERO.to_string(); - } - let token_in_receiver = Address::from_str(&token_in_receiver).map_err(|_| { - EncodingError::FatalError(format!( - "Invalid funds receiver address: {token_in_receiver}" - )) - })?; + let method_calldata = if let Some(permit2) = self.permit2.clone() { let (permit, signature) = permit2.get_permit( &self.router_address, @@ -179,8 +162,6 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, - transfer_from_needed, - token_in_receiver, permit, signature.as_bytes().to_vec(), swap_data, @@ -195,8 +176,6 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, - transfer_from_needed, - token_in_receiver, swap_data, ) .abi_encode() @@ -250,11 +229,11 @@ impl SequentialSwapStrategyEncoder { token_in_already_in_router: bool, ) -> Result { let (permit2, selector) = if let Some(swapper_pk) = swapper_pk { - (Some(Permit2::new(swapper_pk, chain.clone())?), "sequentialSwapPermit2(uint256,address,address,uint256,bool,bool,address,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) + (Some(Permit2::new(swapper_pk, chain.clone())?), "sequentialSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) } else { ( None, - "sequentialSwap(uint256,address,address,uint256,bool,bool,address,bool,address,bytes)" + "sequentialSwap(uint256,address,address,uint256,bool,bool,address,bytes)" .to_string(), ) }; @@ -309,9 +288,6 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { NativeAction::Unwrap => unwrap = true, } } - let (mut transfer_from_needed, mut token_in_receiver, transfer_needed) = self - .transfer_optimization - .get_transfers(grouped_swaps[0].clone(), wrap); let mut swaps = vec![]; let mut next_in_between_swap_optimization_allowed = true; @@ -332,20 +308,21 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { .get_receiver(solution.receiver.clone(), next_swap)?; next_in_between_swap_optimization_allowed = next_swap_optimization; - let in_between_transfer = if i == 0 { - transfer_needed - } else { - self.transfer_optimization - .get_in_between_transfer(&protocol, in_between_swap_optimization_allowed) - }; + let transfer = self + .transfer_optimization + .get_transfers( + grouped_swap.clone(), + solution.given_token.clone(), + wrap, + in_between_swap_optimization_allowed, + ); let encoding_context = EncodingContext { receiver: swap_receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer_from_needed: if i == 0 { transfer_from_needed } else { false }, - transfer_needed: in_between_transfer, + transfer, }; let mut grouped_protocol_data: Vec = vec![]; @@ -364,21 +341,6 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { swaps.push(swap_data); } - if CALLBACK_CONSTRAINED_PROTOCOLS.contains( - &grouped_swaps[0] - .protocol_system - .as_str(), - ) { - // The first swap is from a callback constrained protocol. This means that the in - // transfer needs to happen at callback time and not before. - transfer_from_needed = false; - token_in_receiver = Address::ZERO.to_string(); - } - let token_in_receiver = Address::from_str(&token_in_receiver).map_err(|_| { - EncodingError::FatalError(format!( - "Invalid funds receiver address: {token_in_receiver}" - )) - })?; let encoded_swaps = ple_encode(swaps); let method_calldata = if let Some(permit2) = self.permit2.clone() { let (permit, signature) = permit2.get_permit( @@ -395,8 +357,6 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, - transfer_from_needed, - token_in_receiver, permit, signature.as_bytes().to_vec(), encoded_swaps, @@ -411,8 +371,6 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, - transfer_from_needed, - token_in_receiver, encoded_swaps, ) .abi_encode() @@ -466,11 +424,11 @@ impl SplitSwapStrategyEncoder { token_in_already_in_router: bool, ) -> Result { let (permit2, selector) = if let Some(swapper_pk) = swapper_pk { - (Some(Permit2::new(swapper_pk, chain.clone())?), "splitSwapPermit2(uint256,address,address,uint256,bool,bool,uint256,address,bool,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) + (Some(Permit2::new(swapper_pk, chain.clone())?), "splitSwapPermit2(uint256,address,address,uint256,bool,bool,uint256,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) } else { ( None, - "splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bool,bytes)" + "splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bytes)" .to_string(), ) }; @@ -574,9 +532,6 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { tokens.push(solution.checked_token.clone()); } - let (transfer_from_needed, _token_in_receiver, _transfer_needed) = self - .transfer_optimization - .get_transfers(grouped_swaps[0].clone(), wrap); let mut swaps = vec![]; for grouped_swap in grouped_swaps.iter() { let protocol = grouped_swap.protocol_system.clone(); @@ -593,17 +548,16 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { } else { self.router_address.clone() }; - let transfer_needed = self + let transfer = self .transfer_optimization - .get_in_between_transfer(&protocol, false); + .get_transfers(grouped_swap.clone(), solution.given_token.clone(), wrap, false); let encoding_context = EncodingContext { receiver: swap_receiver.clone(), exact_out: solution.exact_out, router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer_from_needed: false, - transfer_needed, + transfer, }; let mut grouped_protocol_data: Vec = vec![]; @@ -647,7 +601,6 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { unwrap, U256::from(tokens_len), bytes_to_address(&solution.receiver)?, - transfer_from_needed, permit, signature.as_bytes().to_vec(), encoded_swaps, @@ -663,7 +616,6 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { unwrap, U256::from(tokens_len), bytes_to_address(&solution.receiver)?, - transfer_from_needed, encoded_swaps, ) .abi_encode() @@ -792,7 +744,7 @@ mod tests { .unwrap(); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_input = [ - "a93aabdf", // Function selector + "30ace1b1", // Function selector "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out @@ -800,8 +752,6 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000001", // transfer from - "000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11", // funds receiver ] .join(""); @@ -817,13 +767,13 @@ mod tests { "a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one - "00", // transfer false + "00", // transfer type TransferFrom "0000000000000000000000000000", // padding )); let hex_calldata = encode(&calldata); - assert_eq!(hex_calldata[..584], expected_input); - assert_eq!(hex_calldata[1352..], expected_swap); + assert_eq!(hex_calldata[..456], expected_input); + assert_eq!(hex_calldata[1224..], expected_swap); if expected_amount.is_some() & slippage.is_some() & checked_amount.is_none() { // only write to file for 1 test case write_calldata_to_file( @@ -884,7 +834,7 @@ mod tests { .unwrap(); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_input = [ - "cc60c623", // Function selector + "20144a07", // Function selector "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out @@ -892,9 +842,7 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000001", // transfer from - "000000000000000000000000a478c2975ab1ea89e8196811f51a7b7ade33eb11", // funds receiver - "0000000000000000000000000000000000000000000000000000000000000140", // offset of swap bytes + "0000000000000000000000000000000000000000000000000000000000000100", // offset of swap bytes "0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding // Swap data @@ -903,7 +851,7 @@ mod tests { "a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one - "00", // transfer false + "00", // transfer type TransferFrom "0000000000000000000000000000", // padding ] .join(""); @@ -968,7 +916,7 @@ mod tests { .unwrap(); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_input = [ - "cc60c623", // Function selector + "20144a07", // Function selector "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out @@ -976,9 +924,7 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000000", // transfer from - "0000000000000000000000000000000000000000000000000000000000000000", // funds receiver - "0000000000000000000000000000000000000000000000000000000000000140", // offset of swap bytes + "0000000000000000000000000000000000000000000000000000000000000100", // offset of swap bytes "0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding // Swap data @@ -987,7 +933,7 @@ mod tests { "a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one - "01", // transfer true + "01", // transfer type Transfer "0000000000000000000000000000", // padding ] .join(""); @@ -1240,7 +1186,7 @@ mod tests { let hex_calldata = encode(&calldata); let expected = String::from(concat!( - "59e3efbb", /* function selector */ + "e8a980d7", /* function selector */ "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token ou @@ -1248,9 +1194,7 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000001", /* transfer from */ - "000000000000000000000000bb2b8038a1640196fbe3e38816f3e67cba72d940", /* funds receiver */ - "0000000000000000000000000000000000000000000000000000000000000140", /* length ple + "0000000000000000000000000000000000000000000000000000000000000100", /* length ple * encode */ "00000000000000000000000000000000000000000000000000000000000000a8", // swap 1 @@ -1260,7 +1204,7 @@ mod tests { "bb2b8038a1640196fbe3e38816f3e67cba72d940", // component id "004375dff511095cc5a197a54140a24efef3a416", // receiver (next pool) "00", // zero to one - "00", // transfer false + "00", // transfer type TransferFrom // swap 2 "0052", // swap length "5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address @@ -1268,7 +1212,7 @@ mod tests { "004375dff511095cc5a197a54140a24efef3a416", // component id "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver (final user) "01", // zero to one - "00", // transfer false + "02", // transfer type None "000000000000000000000000000000000000000000000000", // padding )); @@ -1366,7 +1310,7 @@ mod tests { .unwrap(); let hex_calldata = hex::encode(&calldata); let expected_input = [ - "740bae0c", // selector + "51bcc7b6", // selector "0000000000000000000000000000000000000000000000000000000005f5e100", // given amount "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token @@ -1374,14 +1318,12 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap action "0000000000000000000000000000000000000000000000000000000000000000", // unwrap action "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000000", // transfer from - "0000000000000000000000000000000000000000000000000000000000000000", // funds receiver ] .join(""); let expected_swaps = [ - "00000000000000000000000000000000000000000000000000000000000000d8", // length of ple encoded swaps without padding - "006a", // ple encoded swaps + "00000000000000000000000000000000000000000000000000000000000000d6", // length of ple encoded swaps without padding + "0069", // ple encoded swaps "2e234dae75c793f67a35089c9d99245e1c58470b", // executor address "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token out @@ -1389,9 +1331,8 @@ mod tests { "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id "01", // zero2one - "01", // transfer from true - "00", // transfer false - "006a", // ple encoded swaps + "00", // transfer type TransferFrom + "0069", // ple encoded swaps "2e234dae75c793f67a35089c9d99245e1c58470b", // executor address "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token out @@ -1399,14 +1340,13 @@ mod tests { "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id "00", // zero2one - "00", // transfer from false - "01", // transfer true - "0000000000000000", // padding + "01", // transfer type Transfer + "00000000000000000000", // padding ] .join(""); - assert_eq!(hex_calldata[..584], expected_input); - assert_eq!(hex_calldata[1352..], expected_swaps); + assert_eq!(hex_calldata[..456], expected_input); + assert_eq!(hex_calldata[1224..], expected_swaps); write_calldata_to_file("test_sequential_strategy_cyclic_swap", hex_calldata.as_str()); } @@ -2083,7 +2023,7 @@ mod tests { let hex_calldata = hex::encode(&calldata); let expected_input = [ - "308f3ce0", // selector + "7c553846", // selector "0000000000000000000000000000000000000000000000000000000005f5e100", // given amount "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token @@ -2092,12 +2032,11 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // unwrap action "0000000000000000000000000000000000000000000000000000000000000002", // tokens length "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000001", // transfer from ] .join(""); let expected_swaps = [ - "000000000000000000000000000000000000000000000000000000000000013b", // length of ple encoded swaps without padding - "006f", // ple encoded swaps + "0000000000000000000000000000000000000000000000000000000000000139", // length of ple encoded swaps without padding + "006e", // ple encoded swaps "00", // token in index "01", // token out index "999999", // split @@ -2108,9 +2047,8 @@ mod tests { "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id "01", // zero2one - "00", // transfer from false - "01", // transfer true - "006f", // ple encoded swaps + "00", // transfer type TransferFrom + "006e", // ple encoded swaps "00", // token in index "01", // token out index "000000", // split @@ -2121,8 +2059,7 @@ mod tests { "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id "01", // zero2one - "00", // transfer from false - "01", // transfer true + "00", // transfer type TransferFrom "0057", // ple encoded swaps "01", // token in index "00", // token out index @@ -2132,12 +2069,12 @@ mod tests { "b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id, "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "00", // zero2one - "01", // transfer true - "0000000000" // padding + "01", // transfer type Transfer + "00000000000000" // padding ] .join(""); - assert_eq!(hex_calldata[..584], expected_input); - assert_eq!(hex_calldata[1352..], expected_swaps); + assert_eq!(hex_calldata[..520], expected_input); + assert_eq!(hex_calldata[1288..], expected_swaps); write_calldata_to_file("test_split_input_cyclic_swap", hex_calldata.as_str()); } @@ -2249,7 +2186,7 @@ mod tests { let hex_calldata = hex::encode(&calldata); let expected_input = [ - "308f3ce0", // selector + "7c553846", // selector "0000000000000000000000000000000000000000000000000000000005f5e100", // given amount "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token @@ -2258,12 +2195,11 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // unwrap action "0000000000000000000000000000000000000000000000000000000000000002", // tokens length "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000001", // transfer from ] .join(""); let expected_swaps = [ - "000000000000000000000000000000000000000000000000000000000000013b", // length of ple encoded swaps without padding + "0000000000000000000000000000000000000000000000000000000000000139", // length of ple encoded swaps without padding "0057", // ple encoded swaps "00", // token in index "01", // token out index @@ -2273,8 +2209,8 @@ mod tests { "b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id "3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver "01", // zero2one - "01", // transfer true - "006f", // ple encoded swaps + "00", // transfer type TransferFrom + "006e", // ple encoded swaps "01", // token in index "00", // token out index "999999", // split @@ -2285,9 +2221,8 @@ mod tests { "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id "00", // zero2one - "00", // transfer from false - "01", // transfer true - "006f", // ple encoded swaps + "01", // transfer type Transfer + "006e", // ple encoded swaps "01", // token in index "00", // token out index "000000", // split @@ -2298,14 +2233,13 @@ mod tests { "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id "00", // zero2one - "00", // transfer from false - "01", // transfer true - "0000000000" // padding + "01", // transfer type Transfer + "00000000000000" // padding ] .join(""); - assert_eq!(hex_calldata[..584], expected_input); - assert_eq!(hex_calldata[1352..], expected_swaps); + assert_eq!(hex_calldata[..520], expected_input); + assert_eq!(hex_calldata[1288..], expected_swaps); write_calldata_to_file("test_split_output_cyclic_swap", hex_calldata.as_str()); } } @@ -2653,7 +2587,7 @@ mod tests { .unwrap(); let expected_input = [ - "a93aabdf", // Function selector (single swap) + "30ace1b1", // Function selector (single swap) "000000000000000000000000000000000000000000000000000000003b9aca00", // amount in "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in "0000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933", // token out @@ -2661,8 +2595,6 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000000", // transfer from - "0000000000000000000000000000000000000000000000000000000000000000", // funds receiver ] .join(""); @@ -2671,15 +2603,14 @@ mod tests { let expected_swaps = String::from(concat!( // length of ple encoded swaps without padding - "0000000000000000000000000000000000000000000000000000000000000087", + "0000000000000000000000000000000000000000000000000000000000000086", // Swap data header "f62849f9a0b5bf2913b396098f7c7019b51a820a", // executor address // Protocol data "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // group token in "6982508145454ce325ddbe47a25d4ec3d2311933", // group token in "00", // zero2one - "01", // transfer from true - "00", // transfer false + "00", // transfer type TransferFrom "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver // First pool params "0000000000000000000000000000000000000000", // intermediary token (ETH) @@ -2689,13 +2620,13 @@ mod tests { "6982508145454ce325ddbe47a25d4ec3d2311933", // intermediary token (PEPE) "0061a8", // fee "0001f4", // tick spacing - "00000000000000000000000000000000000000000000000000" // padding + "0000000000000000000000000000000000000000000000000000" // padding )); let hex_calldata = encode(&calldata); - assert_eq!(hex_calldata[..584], expected_input); - assert_eq!(hex_calldata[1352..], expected_swaps); + assert_eq!(hex_calldata[..456], expected_input); + assert_eq!(hex_calldata[1224..], expected_swaps); write_calldata_to_file( "test_single_encoding_strategy_usv4_grouped_swap", hex_calldata.as_str(), diff --git a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs index eeac6af..a97353f 100644 --- a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs +++ b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs @@ -8,6 +8,7 @@ use crate::encoding::{ constants::{CALLBACK_CONSTRAINED_PROTOCOLS, IN_TRANSFER_REQUIRED_PROTOCOLS}, group_swaps::SwapGroup, }, + models::TransferType, }; /// A struct that defines how the tokens will be transferred into the given pool given the solution. @@ -34,54 +35,47 @@ impl TransferOptimization { } } - /// Returns the information about the necessary transfers. - /// Returns (bool, String, bool) where: - /// * bool: true if a transfer from the user is needed, false otherwise (it might use regular - /// approvals or permit2) - /// * String: the address to transfer from (if not needed it's the zero address) - /// * bool: true if the tokens are already in the router and there only needs to be a transfer - /// from the router into the pool - pub fn get_transfers(&self, swap: SwapGroup, wrap: bool) -> (bool, String, bool) { - let zero_address = Bytes::from([0u8; 20]).to_string(); + /// Returns the transfer type that should be used for the first transfer. + pub fn get_transfers( + &self, + swap: SwapGroup, + given_token: Bytes, + wrap: bool, + in_between_swap_optimization: bool, + ) -> TransferType { + let is_first_swap = swap.token_in == given_token; let in_transfer_required: bool = IN_TRANSFER_REQUIRED_PROTOCOLS.contains(&swap.protocol_system.as_str()); if swap.token_in == self.native_token { // Funds are already in router. All protocols currently take care of native transfers. - (false, zero_address, false) + TransferType::None } else if (swap.token_in == self.wrapped_token) && wrap { // Wrapping already happened in the router so, we just do a normal transfer. - (false, zero_address, true) - } else if in_transfer_required { - if self.token_in_already_in_router { - // Transfer from router to pool. - (false, zero_address, true) + TransferType::Transfer + } else if is_first_swap { + if in_transfer_required { + if self.token_in_already_in_router { + // Transfer from router to pool. + TransferType::Transfer + } else { + // Transfer from swapper to pool + TransferType::TransferFrom + } + // in transfer is not necessary for these protocols. Only make a transfer from the + // swapper to the router if the tokens are not already in the router + } else if !self.token_in_already_in_router { + // Transfer from swapper to router using. + TransferType::TransferFrom } else { - // Transfer from swapper to pool - (true, swap.swaps[0].component.id.clone(), false) + TransferType::None } - // in transfer is not necessary for these protocols. Only make a transfer from the swapper - // to the router if the tokens are not already in the router - } else if !self.token_in_already_in_router { - // Transfer from swapper to router using. - (true, self.router_address.to_string(), false) - } else { - (false, zero_address, false) - } - } - - pub fn get_in_between_transfer( - &self, - protocol_system: &str, - in_between_swap_optimization: bool, - ) -> bool { - let in_transfer_required: bool = IN_TRANSFER_REQUIRED_PROTOCOLS.contains(protocol_system); - - if !in_transfer_required || in_between_swap_optimization { + // all other swaps that not the first one + } else if !in_transfer_required || in_between_swap_optimization { // funds should already be in the router or in the next pool - false + TransferType::None } else { - true + TransferType::Transfer } } @@ -149,31 +143,35 @@ mod tests { Bytes::from("0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f") } - fn zero_address() -> String { - Bytes::from([0u8; 20]).to_string() - } - #[rstest] + // First swap tests // WETH -(univ2)-> DAI we expect a transfer from the user to the protocol - #[case(weth(), "uniswap_v2".to_string(), false, false, true, "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", false)] + #[case(weth(), weth(), "uniswap_v2".to_string(), false, false,false, TransferType::TransferFrom)] // Native token swap. No transfer is needed - #[case(eth(), "uniswap_v2".to_string(),false, false, false, zero_address(), false)] + #[case(eth(), eth(), "uniswap_v2".to_string(),false, false,false, TransferType::None)] // ETH -(wrap)-> WETH -(univ2)-> DAI. Only a transfer from the router into the protocol is // needed - #[case(weth(), "uniswap_v2".to_string(),true, false, false, zero_address(), true)] + #[case(eth(), weth(), "uniswap_v2".to_string(),true, false,false,TransferType::Transfer)] // USDC -(univ2)-> DAI and the tokens are already in the router. Only a transfer from the router // to the protocol is needed - #[case(usdc(), "uniswap_v2".to_string(),false, true, false, zero_address(), true)] + #[case(usdc(), usdc(), "uniswap_v2".to_string(),false, true,false, TransferType::Transfer)] // USDC -(curve)-> DAI and the tokens are already in the router. No transfer is needed - #[case(usdc(), "vm:curve".to_string(),false, true, false, zero_address(), false)] + #[case(usdc(), usdc(), "vm:curve".to_string(),false, true, false,TransferType::None)] + // other swaps tests + // tokens need to be transferred into the pool + #[case(weth(), usdc(), "uniswap_v2".to_string(), false, false,false, TransferType::Transfer)] + // tokens are already in the pool (optimization) + #[case(weth(), usdc(), "uniswap_v2".to_string(), false, false, true, TransferType::None)] + // tokens are already in the router and don't need a transfer + #[case(weth(), usdc(), "vm:curve".to_string(), false, false, false, TransferType::None)] fn test_get_transfers( - #[case] token_in: Bytes, + #[case] given_token: Bytes, + #[case] swap_token_in: Bytes, #[case] protocol: String, #[case] wrap: bool, #[case] token_in_already_in_router: bool, - #[case] expected_transfer_from: bool, - #[case] expected_receiver: String, - #[case] expected_transfer: bool, + #[case] in_between_swap_optimization: bool, + #[case] expected_transfer: TransferType, ) { // The swap token is the same as the given token, which is not the native token let swaps = vec![Swap { @@ -182,34 +180,25 @@ mod tests { id: "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11".to_string(), ..Default::default() }, - token_in: token_in.clone(), + token_in: swap_token_in.clone(), token_out: dai(), split: 0f64, }]; - let swap = - SwapGroup { protocol_system: protocol, token_in, token_out: dai(), split: 0f64, swaps }; + let swap = SwapGroup { + protocol_system: protocol, + token_in: swap_token_in, + token_out: dai(), + split: 0f64, + swaps, + }; let optimization = TransferOptimization::new(eth(), weth(), token_in_already_in_router, router_address()); - let (transfer_from, receiver, transfer) = optimization.get_transfers(swap.clone(), wrap); - assert_eq!(transfer_from, expected_transfer_from); - assert_eq!(receiver, expected_receiver); - assert_eq!(transfer, expected_transfer); - } - - #[rstest] - // tokens need to be transferred into the pool - #[case("uniswap_v2", false, true)] - // tokens are already in the pool (optimization) - #[case("uniswap_v2", true, false)] - // tokens are already in the router and don't need a transfer - #[case("vm:curve", false, false)] - fn test_get_in_between_transfers( - #[case] protocol: &str, - #[case] in_between_swap_optimization: bool, - #[case] expected_transfer: bool, - ) { - let optimization = TransferOptimization::new(eth(), weth(), false, router_address()); - let transfer = optimization.get_in_between_transfer(protocol, in_between_swap_optimization); + let transfer = optimization.get_transfers( + swap.clone(), + given_token, + wrap, + in_between_swap_optimization, + ); assert_eq!(transfer, expected_transfer); } diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index cd3c421..4b33097 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -66,7 +66,7 @@ impl SwapEncoder for UniswapV2SwapEncoder { component_id, bytes_to_address(&encoding_context.receiver)?, zero_to_one, - encoding_context.transfer_needed, + (encoding_context.transfer as u8).to_be_bytes(), ); Ok(args.abi_encode_packed()) @@ -129,8 +129,7 @@ impl SwapEncoder for UniswapV3SwapEncoder { bytes_to_address(&encoding_context.receiver)?, component_id, zero_to_one, - encoding_context.transfer_from_needed, - encoding_context.transfer_needed, + (encoding_context.transfer as u8).to_be_bytes(), ); Ok(args.abi_encode_packed()) @@ -207,8 +206,7 @@ impl SwapEncoder for UniswapV4SwapEncoder { group_token_in_address, group_token_out_address, zero_to_one, - encoding_context.transfer_from_needed, - encoding_context.transfer_needed, + (encoding_context.transfer as u8).to_be_bytes(), bytes_to_address(&encoding_context.receiver)?, pool_params, ); @@ -284,6 +282,7 @@ impl SwapEncoder for BalancerV2SwapEncoder { component_id, bytes_to_address(&encoding_context.receiver)?, approval_needed, + (encoding_context.transfer as u8).to_be_bytes(), ); Ok(args.abi_encode_packed()) } @@ -345,8 +344,7 @@ impl SwapEncoder for EkuboSwapEncoder { let mut encoded = vec![]; if encoding_context.group_token_in == swap.token_in { - encoded.extend((encoding_context.transfer_from_needed as u8).to_be_bytes()); - encoded.extend((encoding_context.transfer_needed as u8).to_be_bytes()); + encoded.extend((encoding_context.transfer as u8).to_be_bytes()); encoded.extend(bytes_to_address(&encoding_context.receiver)?); encoded.extend(bytes_to_address(&swap.token_in)?); } @@ -578,6 +576,7 @@ impl SwapEncoder for CurveSwapEncoder { j.to_be_bytes::<1>(), approval_needed, bytes_to_address(&encoding_context.receiver)?, + (encoding_context.transfer as u8).to_be_bytes(), ); Ok(args.abi_encode_packed()) @@ -621,7 +620,7 @@ impl SwapEncoder for MaverickV2SwapEncoder { bytes_to_address(&swap.token_in)?, component_id, bytes_to_address(&encoding_context.receiver)?, - encoding_context.transfer_needed, + (encoding_context.transfer as u8).to_be_bytes(), ); Ok(args.abi_encode_packed()) } @@ -646,7 +645,7 @@ mod tests { }; use super::*; - use crate::encoding::evm::utils::write_calldata_to_file; + use crate::encoding::{evm::utils::write_calldata_to_file, models::TransferType}; mod uniswap_v2 { use super::*; @@ -671,8 +670,7 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_needed: true, - transfer_from_needed: false, + transfer: TransferType::Transfer, }; let encoder = UniswapV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -695,7 +693,7 @@ mod tests { "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // zero for one "00", - // transfer true + // transfer type Transfer "01", )) ); @@ -731,8 +729,7 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_needed: true, - transfer_from_needed: false, + transfer: TransferType::Transfer, }; let encoder = UniswapV3SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -759,9 +756,7 @@ mod tests { "88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // zero for one "00", - // transfer from false - "00", - // transfer true + // transfer type Transfer "01", )) ); @@ -796,8 +791,7 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_needed: false, - transfer_from_needed: false, + transfer: TransferType::None, }; let encoder = BalancerV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -825,7 +819,9 @@ mod tests { // receiver "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // approval needed - "01" + "01", + // transfer type None + "02" )) ); write_calldata_to_file("test_encode_balancer_v2", hex_swap.as_str()); @@ -869,8 +865,7 @@ mod tests { group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_needed: true, - transfer_from_needed: false, + transfer: TransferType::Transfer, }; let encoder = UniswapV4SwapEncoder::new( String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"), @@ -892,9 +887,7 @@ mod tests { "dac17f958d2ee523a2206206994597c13d831ec7", // zero for one "01", - // transfer from false - "00", - // transfer true + // transfer type Transfer "01", // receiver "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", @@ -943,8 +936,7 @@ mod tests { group_token_in: group_token_in.clone(), // Token out is the same as the group token out group_token_out: token_out.clone(), - transfer_needed: true, - transfer_from_needed: false, + transfer: TransferType::Transfer, }; let encoder = UniswapV4SwapEncoder::new( @@ -987,8 +979,7 @@ mod tests { router_address: Some(router_address.clone()), group_token_in: usde_address.clone(), group_token_out: wbtc_address.clone(), - transfer_needed: true, - transfer_from_needed: false, + transfer: TransferType::Transfer, }; // Setup - First sequence: USDE -> USDT @@ -1066,9 +1057,7 @@ mod tests { "2260fac5e5542a773aa44fbcfedf7c193bc2c599", // zero for one "01", - // transfer from false - "00", - // transfer true + // transfer type Transfer "01", // receiver "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", @@ -1125,8 +1114,7 @@ mod tests { group_token_out: token_out.clone(), exact_out: false, router_address: Some(Bytes::default()), - transfer_needed: true, - transfer_from_needed: false, + transfer: TransferType::Transfer, }; let encoder = @@ -1142,9 +1130,7 @@ mod tests { assert_eq!( hex_swap, concat!( - // transfer from false - "00", - // transfer true + // transfer type Transfer "01", // receiver "ca4f73fe97d0b987a0d12b39bbd562c779bab6f6", @@ -1174,8 +1160,7 @@ mod tests { group_token_out: group_token_out.clone(), exact_out: false, router_address: Some(Bytes::default()), - transfer_needed: true, - transfer_from_needed: false, + transfer: TransferType::Transfer, }; let first_swap = Swap { @@ -1225,9 +1210,7 @@ mod tests { combined_hex, // transfer type concat!( - // transfer from false - "00", - // transfer true + // transfer type Transfer "01", // receiver "ca4f73fe97d0b987a0d12b39bbd562c779bab6f6", @@ -1373,8 +1356,7 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_needed: false, - transfer_from_needed: false, + transfer: TransferType::None, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1405,7 +1387,9 @@ mod tests { // approval needed "01", // receiver, - "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", + // transfer type None + "02", )) ); } @@ -1442,8 +1426,7 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_needed: false, - transfer_from_needed: false, + transfer: TransferType::None, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1474,7 +1457,9 @@ mod tests { // approval needed "01", // receiver - "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", + // transfer type None + "02", )) ); } @@ -1512,8 +1497,7 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_needed: false, - transfer_from_needed: false, + transfer: TransferType::None, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1553,7 +1537,9 @@ mod tests { // approval needed "01", // receiver - "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e" + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", + // transfer type None + "02", )) ); } @@ -1582,8 +1568,7 @@ mod tests { router_address: Some(Bytes::default()), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer_needed: true, - transfer_from_needed: false, + transfer: TransferType::Transfer, }; let encoder = MaverickV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), diff --git a/src/encoding/evm/tycho_encoders.rs b/src/encoding/evm/tycho_encoders.rs index e3e41eb..3787372 100644 --- a/src/encoding/evm/tycho_encoders.rs +++ b/src/encoding/evm/tycho_encoders.rs @@ -6,14 +6,14 @@ use tycho_common::Bytes; use crate::encoding::{ errors::EncodingError, evm::{ - constants::GROUPABLE_PROTOCOLS, + constants::{GROUPABLE_PROTOCOLS, IN_TRANSFER_REQUIRED_PROTOCOLS}, group_swaps::group_swaps, strategy_encoder::strategy_encoders::{ SequentialSwapStrategyEncoder, SingleSwapStrategyEncoder, SplitSwapStrategyEncoder, }, swap_encoder::swap_encoder_registry::SwapEncoderRegistry, }, - models::{Chain, EncodingContext, NativeAction, Solution, Transaction}, + models::{Chain, EncodingContext, NativeAction, Solution, Transaction, TransferType}, strategy_encoder::StrategyEncoder, tycho_encoder::TychoEncoder, }; @@ -273,14 +273,20 @@ impl TychoExecutorEncoder { let mut grouped_protocol_data: Vec = vec![]; for swap in grouped_swap.swaps.iter() { + let transfer = if IN_TRANSFER_REQUIRED_PROTOCOLS + .contains(&swap.component.protocol_system.as_str()) + { + TransferType::Transfer + } else { + TransferType::None + }; let encoding_context = EncodingContext { receiver: receiver.clone(), exact_out: solution.exact_out, router_address: None, group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer_needed: true, - transfer_from_needed: false, + transfer, }; let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?; grouped_protocol_data.extend(protocol_data); @@ -462,7 +468,7 @@ mod tests { Bytes::from_str("0x3ede3eca2a72b3aecc820e955b36f38437d01395").unwrap() ); // single swap selector - assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "cc60c623"); + assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "20144a07"); } #[test] @@ -487,7 +493,7 @@ mod tests { let transactions = transactions.unwrap(); assert_eq!(transactions.len(), 1); // single swap selector - assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "cc60c623"); + assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "20144a07"); } #[test] @@ -534,7 +540,7 @@ mod tests { assert_eq!(transactions.len(), 1); assert_eq!(transactions[0].value, eth_amount_in); // sequential swap selector - assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "59e3efbb"); + assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "e8a980d7"); } #[test] @@ -1148,9 +1154,7 @@ mod tests { "6982508145454ce325ddbe47a25d4ec3d2311933", // zero for one "00", - // transfer from false - "00", - // transfer true + // transfer type Transfer "01", // receiver "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", diff --git a/src/encoding/models.rs b/src/encoding/models.rs index 961029d..ff0f3d7 100644 --- a/src/encoding/models.rs +++ b/src/encoding/models.rs @@ -106,9 +106,7 @@ pub struct Transaction { /// solution does not require router address. /// * `group_token_in`: Token to be used as the input for the group swap. /// * `group_token_out`: Token to be used as the output for the group swap. -/// * `transfer_from_needed`: true if the solution requires a transfer from the user to the router -/// or pool. -/// * `transfer_needed`: true if the solution requires a transfer from the router to the pool. +/// * `transfer`: Type of transfer to be performed. See `TransferType` for more details. #[derive(Clone, Debug)] pub struct EncodingContext { pub receiver: Bytes, @@ -116,8 +114,22 @@ pub struct EncodingContext { pub router_address: Option, pub group_token_in: Bytes, pub group_token_out: Bytes, - pub transfer_from_needed: bool, - pub transfer_needed: bool, + pub transfer: TransferType, +} + +/// Represents the type of transfer to be performed into the pool. +/// +/// # Fields +/// +/// * `Transfer`: Transfer the token from the router into the protocol. +/// * `TransferFrom`: Transfer the token from the sender to the protocol/router. +/// * `None`: No transfer is needed. Tokens are already in the pool. +#[repr(u8)] +#[derive(Clone, Debug, PartialEq)] +pub enum TransferType { + TransferFrom = 0, + Transfer = 1, + None = 2, } #[derive(Clone, PartialEq, Eq, Hash)] From eeebd511142464b4d36286539e1ad8c61fc1eb8c Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Fri, 16 May 2025 11:59:49 -0400 Subject: [PATCH 19/22] feat: perform all transfers in executors For organization (and thus safety) purposes. Rename to RestrictTransferFrom.sol so that we can perform multiple transfer froms (upto an allowance) in the case of split swaps (where the split is the first swap). TODO: Fix tests. --- foundry/src/OneTransferFromOnly.sol | 88 --------------- foundry/src/RestrictTransferFrom.sol | 110 +++++++++++++++++++ foundry/src/TychoRouter.sol | 6 +- foundry/src/executors/BalancerV2Executor.sol | 12 +- foundry/src/executors/CurveExecutor.sol | 15 ++- foundry/src/executors/EkuboExecutor.sol | 36 +++--- foundry/src/executors/MaverickV2Executor.sol | 24 ++-- foundry/src/executors/UniswapV2Executor.sol | 20 ++-- foundry/src/executors/UniswapV3Executor.sol | 38 ++----- foundry/src/executors/UniswapV4Executor.sol | 71 +++++------- 10 files changed, 201 insertions(+), 219 deletions(-) delete mode 100644 foundry/src/OneTransferFromOnly.sol create mode 100644 foundry/src/RestrictTransferFrom.sol diff --git a/foundry/src/OneTransferFromOnly.sol b/foundry/src/OneTransferFromOnly.sol deleted file mode 100644 index 32bcc70..0000000 --- a/foundry/src/OneTransferFromOnly.sol +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.26; - -import "@interfaces/IExecutor.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@permit2/src/interfaces/IAllowanceTransfer.sol"; - -error OneTransferFromOnly__AddressZero(); -error OneTransferFromOnly__MultipleTransferFrom(); - -/** - * @title OneTransferFromOnly - Restrict to one transferFrom on approved params per swap - * @dev Restricts to one `transferFrom` (using `permit2` or regular `transferFrom`) - * per swap, while ensuring that the `transferFrom` is only performed on the input - * token and the input amount, from the msg.sender's wallet that calls the main swap - * method. Reverts if multiple `transferFrom`s are attempted. - */ -contract OneTransferFromOnly { - using SafeERC20 for IERC20; - - IAllowanceTransfer public immutable permit2; - // keccak256("Dispatcher#TOKEN_IN_SLOT") - uint256 private constant _TOKEN_IN_SLOT = - 0x66f353cfe8e3cbe0d03292348fbf0fca32e6e07fa0c2a52b4aac22193ac3b894; - // keccak256("Dispatcher#AMOUNT_IN_SLOT") - uint256 private constant _AMOUNT_IN_SLOT = - 0x1f40aa2d23d66d03722685ce02e5d3a95545dfc8e7c56d1026790aa30be48937; - // keccak256("Dispatcher#IS_PERMIT2_SLOT") - uint256 private constant _IS_PERMIT2_SLOT = - 0x3162c9d1175ca0ca7441f87984fdac41bbfdb13246f42c8bb4414d345da39e2a; - // keccak256("Dispatcher#SENDER_SLOT") - uint256 private constant _SENDER_SLOT = - 0x5dcc7974be5cb30f183f878073999aaa6620995b9e052ab5a713071ff60ae9b5; - // keccak256("Dispatcher#IS_TRANSFER_EXECUTED_SLOT") - uint256 private constant _IS_TRANSFER_EXECUTED_SLOT = - 0x1c64085c839fc2ff0f0aad20613eb6d056a1024e5990211e9eb30824dcd128c2; - - constructor(address _permit2) { - if (_permit2 == address(0)) { - revert OneTransferFromOnly__AddressZero(); - } - permit2 = IAllowanceTransfer(_permit2); - } - - // slither-disable-next-line assembly - function _tstoreTransferFromInfo( - address tokenIn, - uint256 amountIn, - bool isPermit2 - ) internal { - assembly { - tstore(_TOKEN_IN_SLOT, tokenIn) - tstore(_AMOUNT_IN_SLOT, amountIn) - tstore(_IS_PERMIT2_SLOT, isPermit2) - tstore(_SENDER_SLOT, caller()) - tstore(_IS_TRANSFER_EXECUTED_SLOT, false) - } - } - - // slither-disable-next-line assembly - function _transfer(address receiver) internal { - address tokenIn; - uint256 amount; - bool isPermit2; - address sender; - bool isTransferExecuted; - assembly { - tokenIn := tload(_TOKEN_IN_SLOT) - amount := tload(_AMOUNT_IN_SLOT) - isPermit2 := tload(_IS_PERMIT2_SLOT) - sender := tload(_SENDER_SLOT) - isTransferExecuted := tload(_IS_TRANSFER_EXECUTED_SLOT) - } - if (isTransferExecuted) { - revert OneTransferFromOnly__MultipleTransferFrom(); - } - assembly { - tstore(_IS_TRANSFER_EXECUTED_SLOT, true) - } - if (isPermit2) { - // Permit2.permit is already called from the TychoRouter - permit2.transferFrom(sender, receiver, uint160(amount), tokenIn); - } else { - // slither-disable-next-line arbitrary-send-erc20 - IERC20(tokenIn).safeTransferFrom(sender, receiver, amount); - } - } -} diff --git a/foundry/src/RestrictTransferFrom.sol b/foundry/src/RestrictTransferFrom.sol new file mode 100644 index 0000000..8e93529 --- /dev/null +++ b/foundry/src/RestrictTransferFrom.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.26; + +import "@interfaces/IExecutor.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@permit2/src/interfaces/IAllowanceTransfer.sol"; + +error RestrictTransferFrom__AddressZero(); +error RestrictTransferFrom__ExceededTransferFromAllowance(); +error RestrictTransferFrom__UnknownTransferType(); + +/** + * @title RestrictTransferFrom - Restrict transferFrom upto allowed amount of token + * @dev Restricts to one `transferFrom` (using `permit2` or regular `transferFrom`) + * per swap, while ensuring that the `transferFrom` is only performed on the input + * token upto input amount, from the msg.sender's wallet that calls the main swap + * method. Reverts if `transferFrom`s are attempted above this allowed amount. + */ +contract RestrictTransferFrom { + using SafeERC20 for IERC20; + + IAllowanceTransfer public immutable permit2; + // keccak256("Dispatcher#TOKEN_IN_SLOT") + uint256 private constant _TOKEN_IN_SLOT = + 0x66f353cfe8e3cbe0d03292348fbf0fca32e6e07fa0c2a52b4aac22193ac3b894; + // keccak256("Dispatcher#AMOUNT_ALLOWED_SLOT") + uint256 private constant _AMOUNT_ALLOWED_SLOT = + 0xc76591aca92830b1554f3dcc7893e7519ec7c57bd4e64fec0c546d9078033291; + // keccak256("Dispatcher#IS_PERMIT2_SLOT") + uint256 private constant _IS_PERMIT2_SLOT = + 0x3162c9d1175ca0ca7441f87984fdac41bbfdb13246f42c8bb4414d345da39e2a; + // keccak256("Dispatcher#SENDER_SLOT") + uint256 private constant _SENDER_SLOT = + 0x5dcc7974be5cb30f183f878073999aaa6620995b9e052ab5a713071ff60ae9b5; + // keccak256("Dispatcher#AMOUNT_SPENT_SLOT") + uint256 private constant _AMOUNT_SPENT_SLOT = + 0x56044a5eb3aa5bd3ad908b7f15d1e8cb830836bb4ad178a0bf08955c94c40d30; + + constructor(address _permit2) { + if (_permit2 == address(0)) { + revert RestrictTransferFrom__AddressZero(); + } + permit2 = IAllowanceTransfer(_permit2); + } + + enum TransferType { + TransferFrom, + Transfer, + None + } + + // slither-disable-next-line assembly + function _tstoreTransferFromInfo( + address tokenIn, + uint256 amountIn, + bool isPermit2 + ) internal { + assembly { + tstore(_TOKEN_IN_SLOT, tokenIn) + tstore(_AMOUNT_IN_SLOT, amountIn) + tstore(_IS_PERMIT2_SLOT, isPermit2) + tstore(_SENDER_SLOT, caller()) + tstore(_IS_TRANSFER_EXECUTED_SLOT, false) + } + } + + // slither-disable-next-line assembly + function _transfer( + address receiver, + TransferType transferType, + address tokenIn, + uint256 amount + ) internal { + if (transferType == TransferType.TransferFrom){ + bool isPermit2; + address sender; + bool isTransferExecuted; + assembly { + tokenIn := tload(_TOKEN_IN_SLOT) + amountPermitted := tload(_AMOUNT_IN_SLOT) + isPermit2 := tload(_IS_PERMIT2_SLOT) + sender := tload(_SENDER_SLOT) + amountSpent := tload(_IS_TRANSFER_EXECUTED_SLOT) + } + if (amount + amountSpent > amountPermitted) { + revert RestrictTransferFrom__ExceededTransferFromAllowance(); + } + assembly { + tstore(_AMOUNT_SPENT_SLOT, amount) + } + if (isPermit2) { + // Permit2.permit is already called from the TychoRouter + permit2.transferFrom(sender, receiver, uint160(amount), tokenIn); + } else { + // slither-disable-next-line arbitrary-send-erc20 + IERC20(tokenIn).safeTransferFrom(sender, receiver, amount); + } + } else if (transferType == TransferType.Transfer) { + if (tokenIn == address(0)) { + Address.sendValue(payable(receiver), amount); + } else { + IERC20(tokenIn).safeTransfer(receiver, amount); + } + } else if (transferType == TransferType.None) { + return; + } else { + revert RestrictTransferFrom__UnknownTransferType(); + } + } +} diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 06213a2..1b84e99 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -14,7 +14,7 @@ import "@permit2/src/interfaces/IAllowanceTransfer.sol"; import "./Dispatcher.sol"; import {LibSwap} from "../lib/LibSwap.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; -import {OneTransferFromOnly} from "./OneTransferFromOnly.sol"; +import {RestrictTransferFrom} from "./RestrictTransferFrom.sol"; // ✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷ // ✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷ @@ -71,7 +71,7 @@ contract TychoRouter is Dispatcher, Pausable, ReentrancyGuard, - OneTransferFromOnly +RestrictTransferFrom { IWETH private immutable _weth; @@ -93,7 +93,7 @@ contract TychoRouter is address indexed token, uint256 amount, address indexed receiver ); - constructor(address _permit2, address weth) OneTransferFromOnly(_permit2) { + constructor(address _permit2, address weth) RestrictTransferFrom(_permit2) { if (_permit2 == address(0) || weth == address(0)) { revert TychoRouter__AddressZero(); } diff --git a/foundry/src/executors/BalancerV2Executor.sol b/foundry/src/executors/BalancerV2Executor.sol index 02b272b..4ecb932 100644 --- a/foundry/src/executors/BalancerV2Executor.sol +++ b/foundry/src/executors/BalancerV2Executor.sol @@ -10,15 +10,16 @@ import { import {IAsset} from "@balancer-labs/v2-interfaces/contracts/vault/IAsset.sol"; // slither-disable-next-line solc-version import {IVault} from "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol"; +import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; -error BalancerV2Executor__InvalidDataLength(); + error BalancerV2Executor__InvalidDataLength(); -contract BalancerV2Executor is IExecutor { +contract BalancerV2Executor is IExecutor, RestrictTransferFrom { using SafeERC20 for IERC20; address private constant VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; - constructor(address _permit2) {} + constructor(address _permit2) RestrictTransferFrom(_permit2) {} // slither-disable-next-line locked-ether function swap(uint256 givenAmount, bytes calldata data) @@ -31,9 +32,12 @@ contract BalancerV2Executor is IExecutor { IERC20 tokenOut, bytes32 poolId, address receiver, - bool approvalNeeded + bool approvalNeeded, + TransferType transferType ) = _decodeData(data); + _transfer(address(this), transferType, tokenIn, givenAmount); + if (approvalNeeded) { // slither-disable-next-line unused-return tokenIn.forceApprove(VAULT, type(uint256).max); diff --git a/foundry/src/executors/CurveExecutor.sol b/foundry/src/executors/CurveExecutor.sol index a3f2030..6f60e87 100644 --- a/foundry/src/executors/CurveExecutor.sol +++ b/foundry/src/executors/CurveExecutor.sol @@ -4,8 +4,9 @@ pragma solidity ^0.8.26; import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/Address.sol"; +import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; -error CurveExecutor__AddressZero(); + error CurveExecutor__AddressZero(); error CurveExecutor__InvalidDataLength(); interface CryptoPool { @@ -34,12 +35,12 @@ interface CryptoPoolETH { // slither-disable-end naming-convention } -contract CurveExecutor is IExecutor { +contract CurveExecutor is IExecutor, RestrictTransferFrom { using SafeERC20 for IERC20; address public immutable nativeToken; - constructor(address _nativeToken, address _permit2) { + constructor(address _nativeToken, address _permit2) RestrictTransferFrom(_permit2) { if (_nativeToken == address(0)) { revert CurveExecutor__AddressZero(); } @@ -52,7 +53,7 @@ contract CurveExecutor is IExecutor { payable returns (uint256) { - if (data.length != 84) revert CurveExecutor__InvalidDataLength(); + if (data.length != 85) revert CurveExecutor__InvalidDataLength(); ( address tokenIn, @@ -62,6 +63,7 @@ contract CurveExecutor is IExecutor { int128 i, int128 j, bool approvalNeeded, + TransferType transferType, address receiver ) = _decodeData(data); @@ -69,6 +71,7 @@ contract CurveExecutor is IExecutor { // slither-disable-next-line unused-return IERC20(tokenIn).forceApprove(address(pool), type(uint256).max); } + _transfer(address(this), transferType, tokenIn, amountIn); /// Inspired by Curve's router contract: https://github.com/curvefi/curve-router-ng/blob/9ab006ca848fc7f1995b6fbbecfecc1e0eb29e2a/contracts/Router.vy#L44 uint256 balanceBefore = _balanceOf(tokenOut); @@ -120,6 +123,7 @@ contract CurveExecutor is IExecutor { int128 i, int128 j, bool approvalNeeded, + TransferType transferType, address receiver ) { @@ -130,7 +134,8 @@ contract CurveExecutor is IExecutor { i = int128(uint128(uint8(data[61]))); j = int128(uint128(uint8(data[62]))); approvalNeeded = data[63] != 0; - receiver = address(bytes20(data[64:84])); + transferType = TransferType(uint8(data[64])); + receiver = address(bytes20(data[65:85])); } /** diff --git a/foundry/src/executors/EkuboExecutor.sol b/foundry/src/executors/EkuboExecutor.sol index 6c556f6..e619fa9 100644 --- a/foundry/src/executors/EkuboExecutor.sol +++ b/foundry/src/executors/EkuboExecutor.sol @@ -11,7 +11,7 @@ import {SafeTransferLib} from "@solady/utils/SafeTransferLib.sol"; import {LibBytes} from "@solady/utils/LibBytes.sol"; import {Config, EkuboPoolKey} from "@ekubo/types/poolKey.sol"; import {MAX_SQRT_RATIO, MIN_SQRT_RATIO} from "@ekubo/types/sqrtRatio.sol"; -import "../OneTransferFromOnly.sol"; +import "../RestrictTransferFrom.sol"; import "@openzeppelin/contracts/utils/Address.sol"; contract EkuboExecutor is @@ -19,7 +19,7 @@ contract EkuboExecutor is ILocker, IPayer, ICallback, - OneTransferFromOnly +RestrictTransferFrom { error EkuboExecutor__InvalidDataLength(); error EkuboExecutor__CoreOnly(); @@ -36,7 +36,7 @@ contract EkuboExecutor is using SafeERC20 for IERC20; constructor(address _core, address _permit2) - OneTransferFromOnly(_permit2) + RestrictTransferFrom(_permit2) { core = ICore(_core); } @@ -46,7 +46,7 @@ contract EkuboExecutor is payable returns (uint256 calculatedAmount) { - if (data.length < 93) revert EkuboExecutor__InvalidDataLength(); + if (data.length < 92) revert EkuboExecutor__InvalidDataLength(); // amountIn must be at most type(int128).MAX calculatedAmount = @@ -125,10 +125,9 @@ contract EkuboExecutor is function _locked(bytes calldata swapData) internal returns (int128) { int128 nextAmountIn = int128(uint128(bytes16(swapData[0:16]))); uint128 tokenInDebtAmount = uint128(nextAmountIn); - bool transferFromNeeded = (swapData[16] != 0); - bool transferNeeded = (swapData[17] != 0); - address receiver = address(bytes20(swapData[18:38])); - address tokenIn = address(bytes20(swapData[38:58])); + TransferType transferType = TransferType(uint8(swapData[16])); + address receiver = address(bytes20(swapData[17:37])); + address tokenIn = address(bytes20(swapData[37:57])); address nextTokenIn = tokenIn; @@ -162,7 +161,7 @@ contract EkuboExecutor is offset += HOP_BYTE_LEN; } - _pay(tokenIn, tokenInDebtAmount, transferFromNeeded, transferNeeded); + _pay(tokenIn, tokenInDebtAmount, transferType); core.withdraw(nextTokenIn, receiver, uint128(nextAmountIn)); return nextAmountIn; } @@ -170,8 +169,7 @@ contract EkuboExecutor is function _pay( address token, uint128 amount, - bool transferFromNeeded, - bool transferNeeded + TransferType transferType ) internal { address target = address(core); @@ -185,11 +183,10 @@ contract EkuboExecutor is mstore(free, shl(224, 0x0c11dedd)) mstore(add(free, 4), token) mstore(add(free, 36), shl(128, amount)) - mstore(add(free, 52), shl(248, transferFromNeeded)) - mstore(add(free, 53), shl(248, transferNeeded)) + mstore(add(free, 52), shl(248, transferType)) - // 4 (selector) + 32 (token) + 16 (amount) + 1 (transferFromNeeded) + 1 (transferNeeded) = 54 - if iszero(call(gas(), target, 0, free, 54, 0, 0)) { + // 4 (selector) + 32 (token) + 16 (amount) + 1 (transferType) = 53 + if iszero(call(gas(), target, 0, free, 53, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } @@ -200,13 +197,8 @@ contract EkuboExecutor is function _payCallback(bytes calldata payData) internal { address token = address(bytes20(payData[12:32])); // This arg is abi-encoded uint128 amount = uint128(bytes16(payData[32:48])); - bool transferFromNeeded = (payData[48] != 0); - bool transferNeeded = (payData[49] != 0); - if (transferFromNeeded) { - _transfer(msg.sender); - } else if (transferNeeded) { - IERC20(token).safeTransfer(msg.sender, amount); - } + TransferType transferType = TransferType(uint8(payData[48])); + _transfer(core, transferType, token, amount); } // To receive withdrawals from Core diff --git a/foundry/src/executors/MaverickV2Executor.sol b/foundry/src/executors/MaverickV2Executor.sol index a7c9cee..681f133 100644 --- a/foundry/src/executors/MaverickV2Executor.sol +++ b/foundry/src/executors/MaverickV2Executor.sol @@ -4,17 +4,18 @@ pragma solidity ^0.8.26; import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/Address.sol"; +import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; -error MaverickV2Executor__InvalidDataLength(); + error MaverickV2Executor__InvalidDataLength(); error MaverickV2Executor__InvalidTarget(); error MaverickV2Executor__InvalidFactory(); -contract MaverickV2Executor is IExecutor { +contract MaverickV2Executor is IExecutor, RestrictTransferFrom { using SafeERC20 for IERC20; address public immutable factory; - constructor(address _factory, address _permit2) { + constructor(address _factory, address _permit2) RestrictTransferFrom(_permit2) { if (_factory == address(0)) { revert MaverickV2Executor__InvalidFactory(); } @@ -30,9 +31,9 @@ contract MaverickV2Executor is IExecutor { address target; address receiver; IERC20 tokenIn; - bool transferNeeded; + TransferType transferType; - (tokenIn, target, receiver, transferNeeded) = _decodeData(data); + (tokenIn, target, receiver, transferType) = _decodeData(data); _verifyPairAddress(target); IMaverickV2Pool pool = IMaverickV2Pool(target); @@ -47,14 +48,7 @@ contract MaverickV2Executor is IExecutor { tickLimit: tickLimit }); - if (transferNeeded) { - if (address(tokenIn) == address(0)) { - Address.sendValue(payable(target), givenAmount); - } else { - // slither-disable-next-line arbitrary-send-erc20 - tokenIn.safeTransfer(target, givenAmount); - } - } + _transfer(target, transferType, tokenIn, givenAmount); // slither-disable-next-line unused-return (, calculatedAmount) = pool.swap(receiver, swapParams, ""); @@ -67,7 +61,7 @@ contract MaverickV2Executor is IExecutor { IERC20 inToken, address target, address receiver, - bool transferNeeded + TransferType transferType ) { if (data.length != 61) { @@ -76,7 +70,7 @@ contract MaverickV2Executor is IExecutor { inToken = IERC20(address(bytes20(data[0:20]))); target = address(bytes20(data[20:40])); receiver = address(bytes20(data[40:60])); - transferNeeded = (data[60] != 0); + transferType = TransferType(uint8(data[60])); } function _verifyPairAddress(address target) internal view { diff --git a/foundry/src/executors/UniswapV2Executor.sol b/foundry/src/executors/UniswapV2Executor.sol index d5b1831..eea95e9 100644 --- a/foundry/src/executors/UniswapV2Executor.sol +++ b/foundry/src/executors/UniswapV2Executor.sol @@ -4,14 +4,15 @@ pragma solidity ^0.8.26; import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@uniswap-v2/contracts/interfaces/IUniswapV2Pair.sol"; +import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; -error UniswapV2Executor__InvalidDataLength(); + error UniswapV2Executor__InvalidDataLength(); error UniswapV2Executor__InvalidTarget(); error UniswapV2Executor__InvalidFactory(); error UniswapV2Executor__InvalidInitCode(); error UniswapV2Executor__InvalidFee(); -contract UniswapV2Executor is IExecutor { +contract UniswapV2Executor is IExecutor, RestrictTransferFrom { using SafeERC20 for IERC20; address public immutable factory; @@ -24,7 +25,7 @@ contract UniswapV2Executor is IExecutor { bytes32 _initCode, address _permit2, uint256 _feeBps - ) { + ) RestrictTransferFrom(_permit2) { if (_factory == address(0)) { revert UniswapV2Executor__InvalidFactory(); } @@ -50,19 +51,16 @@ contract UniswapV2Executor is IExecutor { address target; address receiver; bool zeroForOne; - bool transferNeeded; + TransferType transferType; - (tokenIn, target, receiver, zeroForOne, transferNeeded) = + (tokenIn, target, receiver, zeroForOne, transferType) = _decodeData(data); _verifyPairAddress(target); calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne); - if (transferNeeded) { - // slither-disable-next-line arbitrary-send-erc20 - tokenIn.safeTransfer(target, givenAmount); - } + _transfer(target, transferType, address(tokenIn), givenAmount); IUniswapV2Pair pool = IUniswapV2Pair(target); if (zeroForOne) { @@ -80,7 +78,7 @@ contract UniswapV2Executor is IExecutor { address target, address receiver, bool zeroForOne, - bool transferNeeded + TransferType transferType, ) { if (data.length != 62) { @@ -90,7 +88,7 @@ contract UniswapV2Executor is IExecutor { target = address(bytes20(data[20:40])); receiver = address(bytes20(data[40:60])); zeroForOne = data[60] != 0; - transferNeeded = data[61] != 0; + transferType = TransferType(uint8(data[61])); } function _getAmountOut(address target, uint256 amountIn, bool zeroForOne) diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index a8a5d0f..6b792df 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -5,7 +5,7 @@ import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; import "@interfaces/ICallback.sol"; -import {OneTransferFromOnly} from "../OneTransferFromOnly.sol"; +import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; import "@openzeppelin/contracts/utils/Address.sol"; error UniswapV3Executor__InvalidDataLength(); @@ -13,7 +13,7 @@ error UniswapV3Executor__InvalidFactory(); error UniswapV3Executor__InvalidTarget(); error UniswapV3Executor__InvalidInitCode(); -contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { +contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom { using SafeERC20 for IERC20; uint160 private constant MIN_SQRT_RATIO = 4295128739; @@ -25,7 +25,7 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { address private immutable self; constructor(address _factory, bytes32 _initCode, address _permit2) - OneTransferFromOnly(_permit2) + RestrictTransferFrom(_permit2) { if (_factory == address(0)) { revert UniswapV3Executor__InvalidFactory(); @@ -51,8 +51,7 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { address receiver, address target, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded + uint8 transferType ) = _decodeData(data); _verifyPairAddress(tokenIn, tokenOut, fee, target); @@ -62,7 +61,7 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { IUniswapV3Pool pool = IUniswapV3Pool(target); bytes memory callbackData = _makeV3CallbackData( - tokenIn, tokenOut, fee, transferFromNeeded, transferNeeded + tokenIn, tokenOut, fee, transferType ); { @@ -99,24 +98,14 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { abi.decode(msgData[4:68], (int256, int256)); address tokenIn = address(bytes20(msgData[132:152])); - - bool transferFromNeeded = msgData[175] != 0; - bool transferNeeded = msgData[176] != 0; + bool transferType = TransferType(uint8(msgData[175])); verifyCallback(msgData[132:]); uint256 amountOwed = amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta); - if (transferFromNeeded) { - _transfer(msg.sender); - } else if (transferNeeded) { - if (tokenIn == address(0)) { - Address.sendValue(payable(msg.sender), amountOwed); - } else { - IERC20(tokenIn).safeTransfer(msg.sender, amountOwed); - } - } + _transfer(msg.sender, transferType, tokenIn, amountOwed); return abi.encode(amountOwed, tokenIn); } @@ -147,11 +136,10 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { address receiver, address target, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded + uint8 transferType ) { - if (data.length != 86) { + if (data.length != 85) { revert UniswapV3Executor__InvalidDataLength(); } tokenIn = address(bytes20(data[0:20])); @@ -160,19 +148,17 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly { receiver = address(bytes20(data[43:63])); target = address(bytes20(data[63:83])); zeroForOne = uint8(data[83]) > 0; - transferFromNeeded = data[84] != 0; - transferNeeded = data[85] != 0; + transferType = uint8(data[84]); } function _makeV3CallbackData( address tokenIn, address tokenOut, uint24 fee, - bool transferFromNeeded, - bool transferNeeded + uint8 transferType ) internal pure returns (bytes memory) { return abi.encodePacked( - tokenIn, tokenOut, fee, transferFromNeeded, transferNeeded + tokenIn, tokenOut, fee, transferType ); } diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index 52a1910..fea689e 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -22,7 +22,7 @@ import {IUnlockCallback} from import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol"; -import "../OneTransferFromOnly.sol"; +import "../RestrictTransferFrom.sol"; import "@openzeppelin/contracts/utils/Address.sol"; error UniswapV4Executor__InvalidDataLength(); @@ -38,7 +38,7 @@ contract UniswapV4Executor is IExecutor, IUnlockCallback, ICallback, - OneTransferFromOnly +RestrictTransferFrom { using SafeERC20 for IERC20; using CurrencyLibrary for Currency; @@ -58,7 +58,7 @@ contract UniswapV4Executor is } constructor(IPoolManager _poolManager, address _permit2) - OneTransferFromOnly(_permit2) + RestrictTransferFrom(_permit2) { poolManager = _poolManager; _self = address(this); @@ -83,8 +83,7 @@ contract UniswapV4Executor is address tokenIn, address tokenOut, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded, + TransferType transferType, address receiver, UniswapV4Executor.UniswapV4Pool[] memory pools ) = _decodeData(data); @@ -102,8 +101,7 @@ contract UniswapV4Executor is key, zeroForOne, amountIn, - transferFromNeeded, - transferNeeded, + transferType, receiver, bytes("") ); @@ -125,8 +123,7 @@ contract UniswapV4Executor is currencyIn, path, amountIn, - transferFromNeeded, - transferNeeded, + transferType, receiver ); } @@ -144,26 +141,24 @@ contract UniswapV4Executor is address tokenIn, address tokenOut, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded, + TransferType transferType, address receiver, UniswapV4Pool[] memory pools ) { - if (data.length < 89) { + if (data.length < 88) { revert UniswapV4Executor__InvalidDataLength(); } tokenIn = address(bytes20(data[0:20])); tokenOut = address(bytes20(data[20:40])); zeroForOne = data[40] != 0; - transferFromNeeded = data[41] != 0; - transferNeeded = data[42] != 0; - receiver = address(bytes20(data[43:63])); + transferType = TransferType(uint8(data[41])); + receiver = address(bytes20(data[42:62])); - uint256 poolsLength = (data.length - 63) / 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[63:]; + bytes memory poolsData = data[62:]; uint256 offset = 0; for (uint256 i = 0; i < poolsLength; i++) { address intermediaryToken; @@ -243,8 +238,7 @@ contract UniswapV4Executor is * @param poolKey The key of the pool to swap in. * @param zeroForOne Whether the swap is from token0 to token1 (true) or vice versa (false). * @param amountIn The amount of tokens to swap in. - * @param transferFromNeeded Whether to transferFrom input tokens into the core contract from the swapper's wallet . - * @param transferNeeded Whether to transfer input tokens into the core contract from the router contract + * @param transferType The type of action necessary to pay back the pool. * @param receiver The address of the receiver. * @param hookData Additional data for hook contracts. */ @@ -252,8 +246,7 @@ contract UniswapV4Executor is PoolKey memory poolKey, bool zeroForOne, uint128 amountIn, - bool transferFromNeeded, - bool transferNeeded, + TransferType transferType, address receiver, bytes calldata hookData ) external returns (uint128) { @@ -266,7 +259,7 @@ contract UniswapV4Executor is if (amount > amountIn) { revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount); } - _settle(currencyIn, amount, transferFromNeeded, transferNeeded); + _settle(currencyIn, amount, transferType); Currency currencyOut = zeroForOne ? poolKey.currency1 : poolKey.currency0; @@ -279,16 +272,14 @@ contract UniswapV4Executor is * @param currencyIn The currency of the input token. * @param path The path to swap along. * @param amountIn The amount of tokens to swap in. - * @param transferFromNeeded Whether to transferFrom input tokens into the core contract from the swapper's wallet . - * @param transferNeeded Whether to transfer input tokens into the core contract from the router contract + * @param transferType The type of action necessary to pay back the pool. * @param receiver The address of the receiver. */ function swapExactInput( Currency currencyIn, PathKey[] calldata path, uint128 amountIn, - bool transferFromNeeded, - bool transferNeeded, + TransferType transferType, address receiver ) external returns (uint128) { uint128 amountOut = 0; @@ -319,7 +310,7 @@ contract UniswapV4Executor is if (amount > amountIn) { revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount); } - _settle(currencyIn, amount, transferFromNeeded, transferNeeded); + _settle(currencyIn, amount, transferType); _take( swapCurrencyIn, // at the end of the loop this is actually currency out @@ -391,17 +382,13 @@ contract UniswapV4Executor is * @dev The implementing contract must ensure that the `payer` is a secure address. * @param currency The currency to settle. * @param amount The amount to send. - * @param transferFromNeeded Whether to manually transferFrom input tokens into the - * core contract from the swapper. - * @param transferNeeded Whether to manually transfer input tokens into the - * core contract from the router. + * @param transferType The type of action necessary to pay back the pool. * @dev Returns early if the amount is 0. */ function _settle( Currency currency, uint256 amount, - bool transferFromNeeded, - bool transferNeeded + TransferType transferType ) internal { if (amount == 0) return; poolManager.sync(currency); @@ -409,18 +396,12 @@ contract UniswapV4Executor is // slither-disable-next-line unused-return poolManager.settle{value: amount}(); } else { - if (transferFromNeeded) { - // transferFrom swapper's wallet into the core contract - _transfer(address(poolManager)); - } else if (transferNeeded) { - address tokenIn = Currency.unwrap(currency); - // transfer from router contract into the core contract - if (tokenIn == address(0)) { - Address.sendValue(payable(address(poolManager)), amount); - } else { - IERC20(tokenIn).safeTransfer(address(poolManager), amount); - } - } + _transfer( + address(poolManager), + transferType, + address(currency), + amount + ); // slither-disable-next-line unused-return poolManager.settle(); } From d4244a708949f5a2cf9810fdb2849d33cff63fa2 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Fri, 16 May 2025 17:57:29 +0100 Subject: [PATCH 20/22] fix: Fix tests (not there yet) Took 58 minutes --- foundry/src/RestrictTransferFrom.sol | 15 +- foundry/src/TychoRouter.sol | 52 ++----- foundry/src/executors/BalancerV2Executor.sol | 8 +- foundry/src/executors/CurveExecutor.sol | 6 +- foundry/src/executors/EkuboExecutor.sol | 14 +- foundry/src/executors/MaverickV2Executor.sol | 8 +- foundry/src/executors/UniswapV2Executor.sol | 4 +- foundry/src/executors/UniswapV3Executor.sol | 19 +-- foundry/src/executors/UniswapV4Executor.sol | 2 +- .../test/TychoRouterProtocolIntegration.t.sol | 24 +-- foundry/test/TychoRouterSequentialSwap.t.sol | 50 ++++--- foundry/test/TychoRouterSingleSwap.t.sol | 55 +++---- foundry/test/TychoRouterSplitSwap.t.sol | 79 ++++++---- foundry/test/TychoRouterTestSetup.sol | 13 +- .../test/executors/BalancerV2Executor.t.sol | 22 ++- foundry/test/executors/CurveExecutor.t.sol | 138 ++++++++++++++---- foundry/test/executors/EkuboExecutor.t.sol | 11 +- .../test/executors/MaverickV2Executor.t.sol | 45 ++++-- .../test/executors/UniswapV2Executor.t.sol | 63 ++++++-- .../test/executors/UniswapV3Executor.t.sol | 33 ++--- .../test/executors/UniswapV4Executor.t.sol | 31 ++-- foundry/test/executors/UniswapV4Utils.sol | 11 +- .../evm/swap_encoder/swap_encoders.rs | 14 +- 23 files changed, 417 insertions(+), 300 deletions(-) diff --git a/foundry/src/RestrictTransferFrom.sol b/foundry/src/RestrictTransferFrom.sol index 8e93529..4480a1d 100644 --- a/foundry/src/RestrictTransferFrom.sol +++ b/foundry/src/RestrictTransferFrom.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.26; import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@permit2/src/interfaces/IAllowanceTransfer.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; error RestrictTransferFrom__AddressZero(); error RestrictTransferFrom__ExceededTransferFromAllowance(); @@ -57,10 +58,10 @@ contract RestrictTransferFrom { ) internal { assembly { tstore(_TOKEN_IN_SLOT, tokenIn) - tstore(_AMOUNT_IN_SLOT, amountIn) + tstore(_AMOUNT_ALLOWED_SLOT, amountIn) tstore(_IS_PERMIT2_SLOT, isPermit2) tstore(_SENDER_SLOT, caller()) - tstore(_IS_TRANSFER_EXECUTED_SLOT, false) + tstore(_AMOUNT_SPENT_SLOT, 0) } } @@ -71,18 +72,20 @@ contract RestrictTransferFrom { address tokenIn, uint256 amount ) internal { - if (transferType == TransferType.TransferFrom){ + if (transferType == TransferType.TransferFrom) { bool isPermit2; address sender; bool isTransferExecuted; + uint256 amountSpent; + uint256 amountAllowed; assembly { tokenIn := tload(_TOKEN_IN_SLOT) - amountPermitted := tload(_AMOUNT_IN_SLOT) + amountAllowed := tload(_AMOUNT_ALLOWED_SLOT) isPermit2 := tload(_IS_PERMIT2_SLOT) sender := tload(_SENDER_SLOT) - amountSpent := tload(_IS_TRANSFER_EXECUTED_SLOT) + amountSpent := tload(_AMOUNT_SPENT_SLOT) } - if (amount + amountSpent > amountPermitted) { + if (amount + amountSpent > amountAllowed) { revert RestrictTransferFrom__ExceededTransferFromAllowance(); } assembly { diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 1b84e99..46740bf 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -71,7 +71,7 @@ contract TychoRouter is Dispatcher, Pausable, ReentrancyGuard, -RestrictTransferFrom + RestrictTransferFrom { IWETH private immutable _weth; @@ -93,7 +93,9 @@ RestrictTransferFrom address indexed token, uint256 amount, address indexed receiver ); - constructor(address _permit2, address weth) RestrictTransferFrom(_permit2) { + constructor(address _permit2, address weth) + RestrictTransferFrom(_permit2) + { if (_permit2 == address(0) || weth == address(0)) { revert TychoRouter__AddressZero(); } @@ -121,8 +123,6 @@ RestrictTransferFrom * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the router. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -136,14 +136,11 @@ RestrictTransferFrom bool unwrapEth, uint256 nTokens, address receiver, - bool transferFromNeeded, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); _tstoreTransferFromInfo(tokenIn, amountIn, false); - if (transferFromNeeded) { - _transfer(address(this)); - } + return _splitSwapChecked( amountIn, tokenIn, @@ -178,8 +175,6 @@ RestrictTransferFrom * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the router. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swaps Encoded swap graph data containing details of each swap. @@ -195,7 +190,6 @@ RestrictTransferFrom bool unwrapEth, uint256 nTokens, address receiver, - bool transferFromNeeded, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, bytes calldata swaps @@ -206,9 +200,6 @@ RestrictTransferFrom permit2.permit(msg.sender, permitSingle, signature); } _tstoreTransferFromInfo(tokenIn, amountIn, true); - if (transferFromNeeded) { - _transfer(address(this)); - } return _splitSwapChecked( amountIn, @@ -242,9 +233,6 @@ RestrictTransferFrom * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). - * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -257,15 +245,11 @@ RestrictTransferFrom bool wrapEth, bool unwrapEth, address receiver, - bool transferFromNeeded, - address tokenInReceiver, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); _tstoreTransferFromInfo(tokenIn, amountIn, false); - if (transferFromNeeded) { - _transfer(tokenInReceiver); - } + return _sequentialSwapChecked( amountIn, tokenIn, @@ -297,8 +281,6 @@ RestrictTransferFrom * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swaps Encoded swap graph data containing details of each swap. @@ -313,8 +295,6 @@ RestrictTransferFrom bool wrapEth, bool unwrapEth, address receiver, - bool transferFromNeeded, - address tokenInReceiver, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, bytes calldata swaps @@ -326,9 +306,7 @@ RestrictTransferFrom } _tstoreTransferFromInfo(tokenIn, amountIn, true); - if (transferFromNeeded) { - _transfer(tokenInReceiver); - } + return _sequentialSwapChecked( amountIn, tokenIn, @@ -358,8 +336,6 @@ RestrictTransferFrom * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param swapData Encoded swap details. * * @return amountOut The total amount of the output token received by the receiver. @@ -372,15 +348,11 @@ RestrictTransferFrom bool wrapEth, bool unwrapEth, address receiver, - bool transferFromNeeded, - address tokenInReceiver, bytes calldata swapData ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); _tstoreTransferFromInfo(tokenIn, amountIn, false); - if (transferFromNeeded) { - _transfer(tokenInReceiver); - } + return _singleSwap( amountIn, tokenIn, @@ -412,8 +384,6 @@ RestrictTransferFrom * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swapData Encoded swap details. @@ -428,8 +398,6 @@ RestrictTransferFrom bool wrapEth, bool unwrapEth, address receiver, - bool transferFromNeeded, - address tokenInReceiver, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, bytes calldata swapData @@ -440,9 +408,7 @@ RestrictTransferFrom permit2.permit(msg.sender, permitSingle, signature); } _tstoreTransferFromInfo(tokenIn, amountIn, true); - if (transferFromNeeded) { - _transfer(tokenInReceiver); - } + return _singleSwap( amountIn, tokenIn, diff --git a/foundry/src/executors/BalancerV2Executor.sol b/foundry/src/executors/BalancerV2Executor.sol index 4ecb932..3fcf343 100644 --- a/foundry/src/executors/BalancerV2Executor.sol +++ b/foundry/src/executors/BalancerV2Executor.sol @@ -12,7 +12,7 @@ import {IAsset} from "@balancer-labs/v2-interfaces/contracts/vault/IAsset.sol"; import {IVault} from "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol"; import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; - error BalancerV2Executor__InvalidDataLength(); +error BalancerV2Executor__InvalidDataLength(); contract BalancerV2Executor is IExecutor, RestrictTransferFrom { using SafeERC20 for IERC20; @@ -36,7 +36,7 @@ contract BalancerV2Executor is IExecutor, RestrictTransferFrom { TransferType transferType ) = _decodeData(data); - _transfer(address(this), transferType, tokenIn, givenAmount); + _transfer(address(this), transferType, address(tokenIn), givenAmount); if (approvalNeeded) { // slither-disable-next-line unused-return @@ -73,7 +73,8 @@ contract BalancerV2Executor is IExecutor, RestrictTransferFrom { IERC20 tokenOut, bytes32 poolId, address receiver, - bool approvalNeeded + bool approvalNeeded, + TransferType transferType ) { if (data.length != 93) { @@ -85,5 +86,6 @@ contract BalancerV2Executor is IExecutor, RestrictTransferFrom { poolId = bytes32(data[40:72]); receiver = address(bytes20(data[72:92])); approvalNeeded = data[92] != 0; + transferType = TransferType(uint8(data[93])); } } diff --git a/foundry/src/executors/CurveExecutor.sol b/foundry/src/executors/CurveExecutor.sol index 6f60e87..517db9b 100644 --- a/foundry/src/executors/CurveExecutor.sol +++ b/foundry/src/executors/CurveExecutor.sol @@ -6,7 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; - error CurveExecutor__AddressZero(); +error CurveExecutor__AddressZero(); error CurveExecutor__InvalidDataLength(); interface CryptoPool { @@ -40,7 +40,9 @@ contract CurveExecutor is IExecutor, RestrictTransferFrom { address public immutable nativeToken; - constructor(address _nativeToken, address _permit2) RestrictTransferFrom(_permit2) { + constructor(address _nativeToken, address _permit2) + RestrictTransferFrom(_permit2) + { if (_nativeToken == address(0)) { revert CurveExecutor__AddressZero(); } diff --git a/foundry/src/executors/EkuboExecutor.sol b/foundry/src/executors/EkuboExecutor.sol index e619fa9..5c6d9f0 100644 --- a/foundry/src/executors/EkuboExecutor.sol +++ b/foundry/src/executors/EkuboExecutor.sol @@ -11,7 +11,7 @@ import {SafeTransferLib} from "@solady/utils/SafeTransferLib.sol"; import {LibBytes} from "@solady/utils/LibBytes.sol"; import {Config, EkuboPoolKey} from "@ekubo/types/poolKey.sol"; import {MAX_SQRT_RATIO, MIN_SQRT_RATIO} from "@ekubo/types/sqrtRatio.sol"; -import "../RestrictTransferFrom.sol"; +import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; import "@openzeppelin/contracts/utils/Address.sol"; contract EkuboExecutor is @@ -19,7 +19,7 @@ contract EkuboExecutor is ILocker, IPayer, ICallback, -RestrictTransferFrom + RestrictTransferFrom { error EkuboExecutor__InvalidDataLength(); error EkuboExecutor__CoreOnly(); @@ -166,11 +166,9 @@ RestrictTransferFrom return nextAmountIn; } - function _pay( - address token, - uint128 amount, - TransferType transferType - ) internal { + function _pay(address token, uint128 amount, TransferType transferType) + internal + { address target = address(core); if (token == NATIVE_TOKEN_ADDRESS) { @@ -198,7 +196,7 @@ RestrictTransferFrom address token = address(bytes20(payData[12:32])); // This arg is abi-encoded uint128 amount = uint128(bytes16(payData[32:48])); TransferType transferType = TransferType(uint8(payData[48])); - _transfer(core, transferType, token, amount); + _transfer(address(core), transferType, token, amount); } // To receive withdrawals from Core diff --git a/foundry/src/executors/MaverickV2Executor.sol b/foundry/src/executors/MaverickV2Executor.sol index 681f133..bded021 100644 --- a/foundry/src/executors/MaverickV2Executor.sol +++ b/foundry/src/executors/MaverickV2Executor.sol @@ -6,7 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; - error MaverickV2Executor__InvalidDataLength(); +error MaverickV2Executor__InvalidDataLength(); error MaverickV2Executor__InvalidTarget(); error MaverickV2Executor__InvalidFactory(); @@ -15,7 +15,9 @@ contract MaverickV2Executor is IExecutor, RestrictTransferFrom { address public immutable factory; - constructor(address _factory, address _permit2) RestrictTransferFrom(_permit2) { + constructor(address _factory, address _permit2) + RestrictTransferFrom(_permit2) + { if (_factory == address(0)) { revert MaverickV2Executor__InvalidFactory(); } @@ -48,7 +50,7 @@ contract MaverickV2Executor is IExecutor, RestrictTransferFrom { tickLimit: tickLimit }); - _transfer(target, transferType, tokenIn, givenAmount); + _transfer(target, transferType, address(tokenIn), givenAmount); // slither-disable-next-line unused-return (, calculatedAmount) = pool.swap(receiver, swapParams, ""); diff --git a/foundry/src/executors/UniswapV2Executor.sol b/foundry/src/executors/UniswapV2Executor.sol index eea95e9..50e39a4 100644 --- a/foundry/src/executors/UniswapV2Executor.sol +++ b/foundry/src/executors/UniswapV2Executor.sol @@ -6,7 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@uniswap-v2/contracts/interfaces/IUniswapV2Pair.sol"; import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; - error UniswapV2Executor__InvalidDataLength(); +error UniswapV2Executor__InvalidDataLength(); error UniswapV2Executor__InvalidTarget(); error UniswapV2Executor__InvalidFactory(); error UniswapV2Executor__InvalidInitCode(); @@ -78,7 +78,7 @@ contract UniswapV2Executor is IExecutor, RestrictTransferFrom { address target, address receiver, bool zeroForOne, - TransferType transferType, + TransferType transferType ) { if (data.length != 62) { diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index 6b792df..b35619e 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -51,7 +51,7 @@ contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom { address receiver, address target, bool zeroForOne, - uint8 transferType + TransferType transferType ) = _decodeData(data); _verifyPairAddress(tokenIn, tokenOut, fee, target); @@ -60,9 +60,8 @@ contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom { int256 amount1; IUniswapV3Pool pool = IUniswapV3Pool(target); - bytes memory callbackData = _makeV3CallbackData( - tokenIn, tokenOut, fee, transferType - ); + bytes memory callbackData = + _makeV3CallbackData(tokenIn, tokenOut, fee, transferType); { (amount0, amount1) = pool.swap( @@ -98,7 +97,7 @@ contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom { abi.decode(msgData[4:68], (int256, int256)); address tokenIn = address(bytes20(msgData[132:152])); - bool transferType = TransferType(uint8(msgData[175])); + TransferType transferType = TransferType(uint8(msgData[175])); verifyCallback(msgData[132:]); @@ -136,7 +135,7 @@ contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom { address receiver, address target, bool zeroForOne, - uint8 transferType + TransferType transferType ) { if (data.length != 85) { @@ -148,18 +147,16 @@ contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom { receiver = address(bytes20(data[43:63])); target = address(bytes20(data[63:83])); zeroForOne = uint8(data[83]) > 0; - transferType = uint8(data[84]); + transferType = TransferType(uint8(data[84])); } function _makeV3CallbackData( address tokenIn, address tokenOut, uint24 fee, - uint8 transferType + TransferType transferType ) internal pure returns (bytes memory) { - return abi.encodePacked( - tokenIn, tokenOut, fee, transferType - ); + return abi.encodePacked(tokenIn, tokenOut, fee, uint8(transferType)); } function _verifyPairAddress( diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index fea689e..e57797c 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -399,7 +399,7 @@ RestrictTransferFrom _transfer( address(poolManager), transferType, - address(currency), + Currency.unwrap(currency), amount ); // slither-disable-next-line unused-return diff --git a/foundry/test/TychoRouterProtocolIntegration.t.sol b/foundry/test/TychoRouterProtocolIntegration.t.sol index a7761d3..15d073d 100644 --- a/foundry/test/TychoRouterProtocolIntegration.t.sol +++ b/foundry/test/TychoRouterProtocolIntegration.t.sol @@ -26,8 +26,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { USDE_ADDR, USDT_ADDR, true, - true, // permit2 transferFrom to protocol - false, // transfer to protocol + RestrictTransferFrom.TransferType.TransferFrom, ALICE, pools ); @@ -43,8 +42,6 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { false, false, ALICE, - false, - address(0), permitSingle, signature, swap @@ -77,8 +74,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { USDE_ADDR, WBTC_ADDR, true, - true, // transferFrom to protocol - false, // transfer to protocol + RestrictTransferFrom.TransferType.TransferFrom, ALICE, pools ); @@ -89,16 +85,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(USDE_ADDR).approve(tychoRouterAddr, amountIn); tychoRouter.singleSwap( - amountIn, - USDE_ADDR, - WBTC_ADDR, - 118280, - false, - false, - ALICE, - false, - address(0), - swap + amountIn, USDE_ADDR, WBTC_ADDR, 118280, false, false, ALICE, swap ); assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), 118281); @@ -277,8 +264,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { ALICE, DAI_WETH_USV3, zeroForOne, - true, // permit2 transferFrom to protocol - false // transfer to protocol + RestrictTransferFrom.TransferType.TransferFrom ); bytes memory swap = encodeSingleSwap(address(usv3Executor), protocolData); @@ -291,8 +277,6 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { false, false, ALICE, - false, - address(0), permitSingle, signature, swap diff --git a/foundry/test/TychoRouterSequentialSwap.t.sol b/foundry/test/TychoRouterSequentialSwap.t.sol index 7a0459c..390e20a 100644 --- a/foundry/test/TychoRouterSequentialSwap.t.sol +++ b/foundry/test/TychoRouterSequentialSwap.t.sol @@ -22,7 +22,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, DAI_USDC_POOL, // receiver (direct to next pool) false, - false // transfer to protocol from router + RestrictTransferFrom.TransferType.None // transfer to protocol from router ) ); @@ -34,7 +34,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { DAI_USDC_POOL, ALICE, true, - false // transfer to protocol from router + RestrictTransferFrom.TransferType.None // transfer to protocol from router ) ); return swaps; @@ -60,8 +60,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, permitSingle, signature, pleEncode(swaps) @@ -89,8 +87,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, pleEncode(swaps) ); @@ -117,8 +113,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, pleEncode(swaps) ); } @@ -141,8 +135,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, pleEncode(swaps) ); } @@ -177,8 +169,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, permitSingle, signature, pleEncode(swaps) @@ -208,14 +198,24 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { swaps[0] = encodeSequentialSwap( address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, WETH_DAI_POOL, DAI_USDC_POOL, false, true + WETH_ADDR, + WETH_DAI_POOL, + DAI_USDC_POOL, + false, + RestrictTransferFrom.TransferType.Transfer ) ); // DAI -> USDC swaps[1] = encodeSequentialSwap( address(usv2Executor), - encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, ALICE, true, false) + encodeUniswapV2Swap( + DAI_ADDR, + DAI_USDC_POOL, + ALICE, + true, + RestrictTransferFrom.TransferType.None + ) ); uint256 amountOut = tychoRouter.sequentialSwapPermit2{value: amountIn}( @@ -226,8 +226,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { true, false, ALICE, - false, - address(0), emptyPermitSingle, "", pleEncode(swaps) @@ -260,7 +258,11 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { swaps[0] = encodeSequentialSwap( address(usv2Executor), encodeUniswapV2Swap( - USDC_ADDR, DAI_USDC_POOL, tychoRouterAddr, false, false + USDC_ADDR, + DAI_USDC_POOL, + tychoRouterAddr, + false, + RestrictTransferFrom.TransferType.TransferFrom ) ); @@ -268,7 +270,11 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { swaps[1] = encodeSequentialSwap( address(usv2Executor), encodeUniswapV2Swap( - DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, true + DAI_ADDR, + WETH_DAI_POOL, + tychoRouterAddr, + true, + RestrictTransferFrom.TransferType.Transfer ) ); @@ -280,8 +286,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, true, ALICE, - true, - DAI_USDC_POOL, permitSingle, signature, pleEncode(swaps) @@ -307,8 +311,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3, true, - false, - true + RestrictTransferFrom.TransferType.Transfer ); bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap( @@ -317,8 +320,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3_2, false, - false, // permit2 transferFrom to protocol - true // transfer to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes[] memory swaps = new bytes[](2); diff --git a/foundry/test/TychoRouterSingleSwap.t.sol b/foundry/test/TychoRouterSingleSwap.t.sol index 97e9468..ffc65e6 100644 --- a/foundry/test/TychoRouterSingleSwap.t.sol +++ b/foundry/test/TychoRouterSingleSwap.t.sol @@ -26,7 +26,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - false // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -40,8 +40,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, // transferFrom to WETH_DAI_POOL - WETH_DAI_POOL, // receiver of input tokens permitSingle, signature, swap @@ -69,7 +67,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - false // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -84,8 +82,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, swap ); @@ -107,24 +103,20 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, false); + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, + WETH_DAI_POOL, + ALICE, + false, + RestrictTransferFrom.TransferType.None + ); bytes memory swap = encodeSingleSwap(address(usv2Executor), protocolData); vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector); tychoRouter.singleSwap( - amountIn, - WETH_ADDR, - DAI_ADDR, - 0, - false, - false, - ALICE, - true, - WETH_DAI_POOL, - swap + amountIn, WETH_ADDR, DAI_ADDR, 0, false, false, ALICE, swap ); } @@ -142,7 +134,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - false // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -158,8 +150,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, swap ); } @@ -179,7 +169,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - false // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -202,8 +192,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, swap ); } @@ -225,8 +213,13 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { sigDeadline: 0 }); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, true); + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, + WETH_DAI_POOL, + ALICE, + false, + RestrictTransferFrom.TransferType.None + ); bytes memory swap = encodeSingleSwap(address(usv2Executor), protocolData); @@ -239,8 +232,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { true, false, ALICE, - false, - tychoRouterAddr, emptyPermitSingle, "", swap @@ -266,7 +257,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { ) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn); bytes memory protocolData = encodeUniswapV2Swap( - DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, false + DAI_ADDR, + WETH_DAI_POOL, + tychoRouterAddr, + true, + RestrictTransferFrom.TransferType.None ); bytes memory swap = @@ -280,8 +275,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, true, ALICE, - true, // transferFrom to WETH_DAI_POOL - WETH_DAI_POOL, // receiver of input tokens permitSingle, signature, swap diff --git a/foundry/test/TychoRouterSplitSwap.t.sol b/foundry/test/TychoRouterSplitSwap.t.sol index 582490c..21d79de 100644 --- a/foundry/test/TychoRouterSplitSwap.t.sol +++ b/foundry/test/TychoRouterSplitSwap.t.sol @@ -23,7 +23,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { (0xffffff * 60) / 100, // 60% address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, WETH_WBTC_POOL, tychoRouterAddr, false, true + WETH_ADDR, + WETH_WBTC_POOL, + tychoRouterAddr, + false, + RestrictTransferFrom.TransferType.Transfer ) ); // WBTC -> USDC @@ -32,7 +36,13 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint8(2), uint24(0), address(usv2Executor), - encodeUniswapV2Swap(WBTC_ADDR, USDC_WBTC_POOL, ALICE, true, true) + encodeUniswapV2Swap( + WBTC_ADDR, + USDC_WBTC_POOL, + ALICE, + true, + RestrictTransferFrom.TransferType.Transfer + ) ); // WETH -> DAI swaps[2] = encodeSplitSwap( @@ -41,7 +51,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint24(0), address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, true + WETH_ADDR, + WETH_DAI_POOL, + tychoRouterAddr, + false, + RestrictTransferFrom.TransferType.Transfer ) ); @@ -51,7 +65,13 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint8(2), uint24(0), address(usv2Executor), - encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, ALICE, true, true) + encodeUniswapV2Swap( + DAI_ADDR, + DAI_USDC_POOL, + ALICE, + true, + RestrictTransferFrom.TransferType.Transfer + ) ); return swaps; @@ -95,7 +115,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, - true, permitSingle, signature, pleEncode(swaps) @@ -125,7 +144,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, - true, pleEncode(swaps) ); @@ -154,7 +172,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, - true, pleEncode(swaps) ); vm.stopPrank(); @@ -180,7 +197,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 2, ALICE, - true, pleEncode(swaps) ); @@ -218,7 +234,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, - true, permitSingle, signature, pleEncode(swaps) @@ -245,8 +260,13 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { spender: address(0), sigDeadline: 0 }); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, true); + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, + WETH_DAI_POOL, + ALICE, + false, + RestrictTransferFrom.TransferType.Transfer + ); bytes memory swap = encodeSplitSwap( uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData @@ -263,7 +283,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 2, ALICE, - false, emptyPermitSingle, "", pleEncode(swaps) @@ -291,7 +310,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { ) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn); bytes memory protocolData = encodeUniswapV2Swap( - DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, true + DAI_ADDR, + WETH_DAI_POOL, + tychoRouterAddr, + true, + RestrictTransferFrom.TransferType.Transfer ); bytes memory swap = encodeSplitSwap( @@ -309,7 +332,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { true, 2, ALICE, - true, permitSingle, signature, pleEncode(swaps) @@ -349,8 +371,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3, true, - false, // transferFrom swapper required - true // transfer from tycho router to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap( @@ -359,8 +380,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3_2, true, - false, // transferFrom swapper required - true // transfer from tycho router to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes memory wethUsdcV2OneZeroData = encodeUniswapV2Swap( @@ -368,7 +388,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { USDC_WETH_USV2, tychoRouterAddr, false, - true // transfer from tycho router to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes[] memory swaps = new bytes[](3); @@ -424,8 +444,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3, true, - true, // transferFrom swapper required - false // transfer from tycho router to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap( @@ -434,8 +453,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3_2, true, - true, // transferFrom swapper required - false // transfer from tycho router to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes[] memory swaps = new bytes[](2); @@ -465,7 +483,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 2, ALICE, - false, pleEncode(swaps) ); vm.stopPrank(); @@ -488,7 +505,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { USDC_WETH_USV2, tychoRouterAddr, true, - true // transfer required + RestrictTransferFrom.TransferType.Transfer ); bytes memory usdcWethV3Pool1OneZeroData = encodeUniswapV3Swap( @@ -497,8 +514,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3, false, - false, // transferFrom required - true // transfer required + RestrictTransferFrom.TransferType.Transfer ); bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap( @@ -507,8 +523,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3_2, false, - false, // transferFrom required - true // transfer required + RestrictTransferFrom.TransferType.Transfer ); bytes[] memory swaps = new bytes[](3); @@ -547,7 +562,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { deal(BASE_USDC, tychoRouterAddr, amountIn); bytes memory protocolData = encodeUniswapV2Swap( - BASE_USDC, USDC_MAG7_POOL, tychoRouterAddr, true, true + BASE_USDC, + USDC_MAG7_POOL, + tychoRouterAddr, + true, + RestrictTransferFrom.TransferType.Transfer ); bytes memory swap = encodeSplitSwap( diff --git a/foundry/test/TychoRouterTestSetup.sol b/foundry/test/TychoRouterTestSetup.sol index 31dd507..8086535 100644 --- a/foundry/test/TychoRouterTestSetup.sol +++ b/foundry/test/TychoRouterTestSetup.sol @@ -185,11 +185,10 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { address target, address receiver, bool zero2one, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) internal pure returns (bytes memory) { - return abi.encodePacked( - tokenIn, target, receiver, zero2one, transferNeeded - ); + return + abi.encodePacked(tokenIn, target, receiver, zero2one, transferType); } function encodeUniswapV3Swap( @@ -198,8 +197,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { address receiver, address target, bool zero2one, - bool transferFromNeeded, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) internal view returns (bytes memory) { IUniswapV3Pool pool = IUniswapV3Pool(target); return abi.encodePacked( @@ -209,8 +207,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { receiver, target, zero2one, - transferFromNeeded, - transferNeeded + transferType ); } } diff --git a/foundry/test/executors/BalancerV2Executor.t.sol b/foundry/test/executors/BalancerV2Executor.t.sol index 46b2ffd..c087945 100644 --- a/foundry/test/executors/BalancerV2Executor.t.sol +++ b/foundry/test/executors/BalancerV2Executor.t.sol @@ -16,7 +16,8 @@ contract BalancerV2ExecutorExposed is BalancerV2Executor { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval + bool needsApproval, + TransferType transferType ) { return _decodeData(data); @@ -40,7 +41,12 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { function testDecodeParams() public view { bytes memory params = abi.encodePacked( - WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, address(2), true + WETH_ADDR, + BAL_ADDR, + WETH_BAL_POOL_ID, + address(2), + true, + RestrictTransferFrom.TransferType.None ); ( @@ -48,7 +54,8 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval + bool needsApproval, + RestrictTransferFrom.TransferType transferType ) = balancerV2Exposed.decodeParams(params); assertEq(address(tokenIn), WETH_ADDR); @@ -56,6 +63,9 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { assertEq(poolId, WETH_BAL_POOL_ID); assertEq(receiver, address(2)); assertEq(needsApproval, true); + assertEq( + uint8(transferType), uint8(RestrictTransferFrom.TransferType.None) + ); } function testDecodeParamsInvalidDataLength() public { @@ -89,7 +99,8 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval + bool needsApproval, + RestrictTransferFrom.TransferType transferType ) = balancerV2Exposed.decodeParams(protocolData); assertEq(address(tokenIn), WETH_ADDR); @@ -97,6 +108,9 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { assertEq(poolId, WETH_BAL_POOL_ID); assertEq(receiver, BOB); assertEq(needsApproval, true); + assertEq( + uint8(transferType), uint8(RestrictTransferFrom.TransferType.None) + ); } function testSwapIntegration() public { diff --git a/foundry/test/executors/CurveExecutor.t.sol b/foundry/test/executors/CurveExecutor.t.sol index 3d5621e..d8dab35 100644 --- a/foundry/test/executors/CurveExecutor.t.sol +++ b/foundry/test/executors/CurveExecutor.t.sol @@ -37,6 +37,7 @@ contract CurveExecutorExposed is CurveExecutor { int128 i, int128 j, bool tokenApprovalNeeded, + RestrictTransferFrom.TransferType transferType, address receiver ) { @@ -67,6 +68,7 @@ contract CurveExecutorTest is Test, Constants { uint8(2), uint8(0), true, + RestrictTransferFrom.TransferType.None, ALICE ); @@ -78,6 +80,7 @@ contract CurveExecutorTest is Test, Constants { int128 i, int128 j, bool tokenApprovalNeeded, + RestrictTransferFrom.TransferType transferType, address receiver ) = curveExecutorExposed.decodeData(data); @@ -88,6 +91,9 @@ contract CurveExecutorTest is Test, Constants { assertEq(i, 2); assertEq(j, 0); assertEq(tokenApprovalNeeded, true); + assertEq( + uint8(transferType), uint8(RestrictTransferFrom.TransferType.None) + ); assertEq(receiver, ALICE); } @@ -96,7 +102,14 @@ 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, ALICE); + bytes memory data = _getData( + DAI_ADDR, + USDC_ADDR, + TRIPOOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -109,8 +122,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(ETH_ADDR_FOR_CURVE, STETH_ADDR, STETH_POOL, 1, ALICE); + bytes memory data = _getData( + ETH_ADDR_FOR_CURVE, + STETH_ADDR, + STETH_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -126,8 +145,14 @@ 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, ALICE); + bytes memory data = _getData( + WETH_ADDR, + WBTC_ADDR, + TRICRYPTO2_POOL, + 3, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -140,7 +165,14 @@ 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, ALICE); + bytes memory data = _getData( + USDC_ADDR, + SUSD_ADDR, + SUSD_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -153,8 +185,14 @@ 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, ALICE); + bytes memory data = _getData( + FRAX_ADDR, + USDC_ADDR, + FRAX_USDC_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -167,8 +205,14 @@ 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, ALICE); + bytes memory data = _getData( + USDC_ADDR, + USDE_ADDR, + USDE_USDC_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -181,8 +225,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 100 * 10 ** 6; deal(DOLA_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(DOLA_ADDR, FRAXPYUSD_POOL, DOLA_FRAXPYUSD_POOL, 1, ALICE); + bytes memory data = _getData( + DOLA_ADDR, + FRAXPYUSD_POOL, + DOLA_FRAXPYUSD_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -196,8 +246,14 @@ contract CurveExecutorTest is Test, Constants { 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, ALICE); + bytes memory data = _getData( + XYO_ADDR, + ETH_ADDR_FOR_CURVE, + ETH_XYO_POOL, + 2, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -210,8 +266,14 @@ 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, ALICE); + bytes memory data = _getData( + BSGG_ADDR, + USDT_ADDR, + BSGG_USDT_POOL, + 2, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -224,8 +286,14 @@ 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, ALICE); + bytes memory data = _getData( + WETH_ADDR, + USDC_ADDR, + TRICRYPTO_POOL, + 2, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -238,8 +306,14 @@ 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, ALICE); + bytes memory data = _getData( + UWU_ADDR, + WETH_ADDR, + UWU_WETH_POOL, + 2, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -252,8 +326,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(USDT_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(USDT_ADDR, CRVUSD_ADDR, CRVUSD_USDT_POOL, 1, ALICE); + bytes memory data = _getData( + USDT_ADDR, + CRVUSD_ADDR, + CRVUSD_USDT_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -266,8 +346,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 100 * 10 ** 9; // 9 decimals deal(WTAO_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(WTAO_ADDR, WSTTAO_ADDR, WSTTAO_WTAO_POOL, 1, ALICE); + bytes memory data = _getData( + WTAO_ADDR, + WSTTAO_ADDR, + WSTTAO_WTAO_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -280,7 +366,8 @@ contract CurveExecutorTest is Test, Constants { address tokenOut, address pool, uint8 poolType, - address receiver + address receiver, + RestrictTransferFrom.TransferType transferType ) internal view returns (bytes memory data) { (int128 i, int128 j) = _getIndexes(tokenIn, tokenOut, pool); data = abi.encodePacked( @@ -291,6 +378,7 @@ contract CurveExecutorTest is Test, Constants { uint8(uint256(uint128(i))), uint8(uint256(uint128(j))), true, + transferType, receiver ); } diff --git a/foundry/test/executors/EkuboExecutor.t.sol b/foundry/test/executors/EkuboExecutor.t.sol index b46e983..7fa3eb1 100644 --- a/foundry/test/executors/EkuboExecutor.t.sol +++ b/foundry/test/executors/EkuboExecutor.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.26; import "../TestUtils.sol"; import {Constants} from "../Constants.sol"; -import {EkuboExecutor} from "@src/executors/EkuboExecutor.sol"; +import "@src/executors/EkuboExecutor.sol"; import {ICore} from "@ekubo/interfaces/ICore.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {NATIVE_TOKEN_ADDRESS} from "@ekubo/math/constants.sol"; @@ -45,8 +45,7 @@ contract EkuboExecutorTest is Constants, TestUtils { uint256 usdcBalanceBeforeExecutor = USDC.balanceOf(address(executor)); bytes memory data = abi.encodePacked( - false, // transferFromNeeded (transfer user to core) - true, // transferNeeded (transfer from executor to core) + uint8(RestrictTransferFrom.TransferType.Transfer), // transfer type (transfer from executor to core) address(executor), // receiver NATIVE_TOKEN_ADDRESS, // tokenIn USDC_ADDR, // tokenOut @@ -83,8 +82,7 @@ contract EkuboExecutorTest is Constants, TestUtils { uint256 ethBalanceBeforeExecutor = address(executor).balance; bytes memory data = abi.encodePacked( - false, // transferFromNeeded (transfer user to core) - true, // transferNeeded (transfer from executor to core) + uint8(RestrictTransferFrom.TransferType.Transfer), // transferNeeded (transfer from executor to core) address(executor), // receiver USDC_ADDR, // tokenIn NATIVE_TOKEN_ADDRESS, // tokenOut @@ -142,8 +140,7 @@ contract EkuboExecutorTest is Constants, TestUtils { // Same test case as in swap_encoder::tests::ekubo::test_encode_swap_multi function testMultiHopSwap() public { bytes memory data = abi.encodePacked( - false, // transferFromNeeded (transfer user to core) - true, // transferNeeded (transfer from executor to core) + uint8(RestrictTransferFrom.TransferType.Transfer), // transferNeeded (transfer from executor to core) address(executor), // receiver NATIVE_TOKEN_ADDRESS, // tokenIn USDC_ADDR, // tokenOut of 1st swap diff --git a/foundry/test/executors/MaverickV2Executor.t.sol b/foundry/test/executors/MaverickV2Executor.t.sol index 241d265..9e4bbb3 100644 --- a/foundry/test/executors/MaverickV2Executor.t.sol +++ b/foundry/test/executors/MaverickV2Executor.t.sol @@ -17,7 +17,7 @@ contract MaverickV2ExecutorExposed is MaverickV2Executor { IERC20 tokenIn, address target, address receiver, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) { return _decodeData(data); @@ -39,16 +39,28 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { } function testDecodeParams() public view { - bytes memory params = - abi.encodePacked(GHO_ADDR, GHO_USDC_POOL, address(2), true); + bytes memory params = abi.encodePacked( + GHO_ADDR, + GHO_USDC_POOL, + address(2), + true, + RestrictTransferFrom.TransferType.Transfer + ); - (IERC20 tokenIn, address target, address receiver, bool transferNeeded) - = maverickV2Exposed.decodeParams(params); + ( + IERC20 tokenIn, + address target, + address receiver, + RestrictTransferFrom.TransferType transferType + ) = maverickV2Exposed.decodeParams(params); assertEq(address(tokenIn), GHO_ADDR); assertEq(target, GHO_USDC_POOL); assertEq(receiver, address(2)); - assertEq(transferNeeded, true); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); } function testDecodeParamsInvalidDataLength() public { @@ -61,8 +73,12 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { function testSwap() public { uint256 amountIn = 10e18; - bytes memory protocolData = - abi.encodePacked(GHO_ADDR, GHO_USDC_POOL, BOB, true); + bytes memory protocolData = abi.encodePacked( + GHO_ADDR, + GHO_USDC_POOL, + BOB, + RestrictTransferFrom.TransferType.Transfer + ); deal(GHO_ADDR, address(maverickV2Exposed), amountIn); uint256 balanceBefore = USDC.balanceOf(BOB); @@ -79,13 +95,20 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { bytes memory protocolData = loadCallDataFromFile("test_encode_maverick_v2"); - (IERC20 tokenIn, address pool, address receiver, bool transferNeeded) = - maverickV2Exposed.decodeParams(protocolData); + ( + IERC20 tokenIn, + address pool, + address receiver, + RestrictTransferFrom.TransferType transferType + ) = maverickV2Exposed.decodeParams(protocolData); assertEq(address(tokenIn), GHO_ADDR); assertEq(pool, GHO_USDC_POOL); assertEq(receiver, BOB); - assertEq(transferNeeded, true); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); } function testSwapIntegration() public { diff --git a/foundry/test/executors/UniswapV2Executor.t.sol b/foundry/test/executors/UniswapV2Executor.t.sol index a6a34bd..a509877 100644 --- a/foundry/test/executors/UniswapV2Executor.t.sol +++ b/foundry/test/executors/UniswapV2Executor.t.sol @@ -23,7 +23,7 @@ contract UniswapV2ExecutorExposed is UniswapV2Executor { address target, address receiver, bool zeroForOne, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) { return _decodeData(data); @@ -82,22 +82,30 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { } function testDecodeParams() public view { - bytes memory params = - abi.encodePacked(WETH_ADDR, address(2), address(3), false, true); + bytes memory params = abi.encodePacked( + WETH_ADDR, + address(2), + address(3), + false, + RestrictTransferFrom.TransferType.Transfer + ); ( IERC20 tokenIn, address target, address receiver, bool zeroForOne, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) = uniswapV2Exposed.decodeParams(params); assertEq(address(tokenIn), WETH_ADDR); assertEq(target, address(2)); assertEq(receiver, address(3)); assertEq(zeroForOne, false); - assertEq(transferNeeded, true); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); } function testDecodeParamsInvalidDataLength() public { @@ -148,8 +156,13 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { uint256 amountIn = 10 ** 18; uint256 amountOut = 1847751195973566072891; bool zeroForOne = false; - bytes memory protocolData = - abi.encodePacked(WETH_ADDR, WETH_DAI_POOL, BOB, zeroForOne, true); + bytes memory protocolData = abi.encodePacked( + WETH_ADDR, + WETH_DAI_POOL, + BOB, + zeroForOne, + RestrictTransferFrom.TransferType.Transfer + ); deal(WETH_ADDR, address(uniswapV2Exposed), amountIn); uniswapV2Exposed.swap(amountIn, protocolData); @@ -162,8 +175,13 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { uint256 amountIn = 10 ** 18; uint256 amountOut = 1847751195973566072891; bool zeroForOne = false; - bytes memory protocolData = - abi.encodePacked(WETH_ADDR, WETH_DAI_POOL, BOB, zeroForOne, false); + bytes memory protocolData = abi.encodePacked( + WETH_ADDR, + WETH_DAI_POOL, + BOB, + zeroForOne, + RestrictTransferFrom.TransferType.None + ); deal(WETH_ADDR, address(this), amountIn); IERC20(WETH_ADDR).transfer(address(WETH_DAI_POOL), amountIn); @@ -175,21 +193,24 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { function testDecodeIntegration() public view { bytes memory protocolData = - hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc288e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000010000"; + hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc288e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000010001"; ( IERC20 tokenIn, address target, address receiver, bool zeroForOne, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) = uniswapV2Exposed.decodeParams(protocolData); assertEq(address(tokenIn), WETH_ADDR); assertEq(target, 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640); assertEq(receiver, 0x0000000000000000000000000000000000000001); assertEq(zeroForOne, false); - assertEq(transferNeeded, false); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); } function testSwapIntegration() public { @@ -208,8 +229,13 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { uint256 amountIn = 10 ** 18; bool zeroForOne = false; address fakePool = address(new FakeUniswapV2Pool(WETH_ADDR, DAI_ADDR)); - bytes memory protocolData = - abi.encodePacked(WETH_ADDR, fakePool, BOB, zeroForOne, true); + bytes memory protocolData = abi.encodePacked( + WETH_ADDR, + fakePool, + BOB, + zeroForOne, + RestrictTransferFrom.TransferType.Transfer + ); deal(WETH_ADDR, address(uniswapV2Exposed), amountIn); vm.expectRevert(UniswapV2Executor__InvalidTarget.selector); @@ -223,8 +249,13 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { vm.rollFork(26857267); uint256 amountIn = 10 * 10 ** 6; bool zeroForOne = true; - bytes memory protocolData = - abi.encodePacked(BASE_USDC, USDC_MAG7_POOL, BOB, zeroForOne, true); + bytes memory protocolData = abi.encodePacked( + BASE_USDC, + USDC_MAG7_POOL, + BOB, + zeroForOne, + RestrictTransferFrom.TransferType.Transfer + ); deal(BASE_USDC, address(uniswapV2Exposed), amountIn); diff --git a/foundry/test/executors/UniswapV3Executor.t.sol b/foundry/test/executors/UniswapV3Executor.t.sol index b3335d4..566f4c8 100644 --- a/foundry/test/executors/UniswapV3Executor.t.sol +++ b/foundry/test/executors/UniswapV3Executor.t.sol @@ -22,8 +22,7 @@ contract UniswapV3ExecutorExposed is UniswapV3Executor { address receiver, address target, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) { return _decodeData(data); @@ -72,8 +71,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address(2), address(3), false, - false, - true + RestrictTransferFrom.TransferType.Transfer ); ( @@ -83,8 +81,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address receiver, address target, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) = uniswapV3Exposed.decodeData(data); assertEq(tokenIn, WETH_ADDR); @@ -93,8 +90,10 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { assertEq(receiver, address(2)); assertEq(target, address(3)); assertEq(zeroForOne, false); - assertEq(transferFromNeeded, false); - assertEq(transferNeeded, true); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); } function testSwapIntegration() public { @@ -110,8 +109,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address(this), DAI_WETH_USV3, zeroForOne, - false, - true + RestrictTransferFrom.TransferType.Transfer ); uint256 amountOut = uniswapV3Exposed.swap(amountIn, data); @@ -149,7 +147,11 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { vm.startPrank(DAI_WETH_USV3); bytes memory protocolData = abi.encodePacked( - WETH_ADDR, DAI_ADDR, poolFee, false, true, address(uniswapV3Exposed) + WETH_ADDR, + DAI_ADDR, + poolFee, + RestrictTransferFrom.TransferType.Transfer, + address(uniswapV3Exposed) ); uint256 dataOffset = 3; // some offset uint256 dataLength = protocolData.length; @@ -182,8 +184,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address(this), fakePool, zeroForOne, - false, - true + RestrictTransferFrom.TransferType.Transfer ); vm.expectRevert(UniswapV3Executor__InvalidTarget.selector); @@ -196,8 +197,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address receiver, address target, bool zero2one, - bool transferFromNeeded, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) internal view returns (bytes memory) { IUniswapV3Pool pool = IUniswapV3Pool(target); return abi.encodePacked( @@ -207,8 +207,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { receiver, target, zero2one, - transferFromNeeded, - transferNeeded + transferType ); } } diff --git a/foundry/test/executors/UniswapV4Executor.t.sol b/foundry/test/executors/UniswapV4Executor.t.sol index d2918a0..21c39cc 100644 --- a/foundry/test/executors/UniswapV4Executor.t.sol +++ b/foundry/test/executors/UniswapV4Executor.t.sol @@ -21,8 +21,7 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor { address tokenIn, address tokenOut, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded, + RestrictTransferFrom.TransferType transferType, address receiver, UniswapV4Pool[] memory pools ) @@ -53,8 +52,6 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { int24 tickSpacing1 = 60; uint24 pool2Fee = 1000; int24 tickSpacing2 = -10; - bool transferFromNeeded = false; - bool transferNeeded = true; UniswapV4Executor.UniswapV4Pool[] memory pools = new UniswapV4Executor.UniswapV4Pool[](2); @@ -73,8 +70,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { USDE_ADDR, USDT_ADDR, zeroForOne, - transferFromNeeded, - transferNeeded, + RestrictTransferFrom.TransferType.Transfer, ALICE, pools ); @@ -83,8 +79,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { address tokenIn, address tokenOut, bool zeroForOneDecoded, - bool transferFromNeededDecoded, - bool transferNeededDecoded, + RestrictTransferFrom.TransferType transferType, address receiver, UniswapV4Executor.UniswapV4Pool[] memory decodedPools ) = uniswapV4Exposed.decodeData(data); @@ -92,8 +87,10 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { assertEq(tokenIn, USDE_ADDR); assertEq(tokenOut, USDT_ADDR); assertEq(zeroForOneDecoded, zeroForOne); - assertEq(transferFromNeededDecoded, transferFromNeeded); - assertEq(transferNeededDecoded, transferNeeded); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); assertEq(receiver, ALICE); assertEq(decodedPools.length, 2); assertEq(decodedPools[0].intermediaryToken, USDT_ADDR); @@ -120,7 +117,12 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, USDT_ADDR, true, false, true, ALICE, pools + USDE_ADDR, + USDT_ADDR, + true, + RestrictTransferFrom.TransferType.Transfer, + ALICE, + pools ); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); @@ -172,7 +174,12 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, WBTC_ADDR, true, false, true, ALICE, pools + USDE_ADDR, + WBTC_ADDR, + true, + RestrictTransferFrom.TransferType.Transfer, + ALICE, + pools ); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); diff --git a/foundry/test/executors/UniswapV4Utils.sol b/foundry/test/executors/UniswapV4Utils.sol index 6746ebe..c280fcb 100644 --- a/foundry/test/executors/UniswapV4Utils.sol +++ b/foundry/test/executors/UniswapV4Utils.sol @@ -8,8 +8,7 @@ library UniswapV4Utils { address tokenIn, address tokenOut, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded, + RestrictTransferFrom.TransferType transferType, address receiver, UniswapV4Executor.UniswapV4Pool[] memory pools ) public pure returns (bytes memory) { @@ -25,13 +24,7 @@ library UniswapV4Utils { } return abi.encodePacked( - tokenIn, - tokenOut, - zeroForOne, - transferFromNeeded, - transferNeeded, - receiver, - encodedPools + tokenIn, tokenOut, zeroForOne, transferType, receiver, encodedPools ); } } diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index 4b33097..fb7b7b1 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -575,8 +575,8 @@ impl SwapEncoder for CurveSwapEncoder { i.to_be_bytes::<1>(), j.to_be_bytes::<1>(), approval_needed, - bytes_to_address(&encoding_context.receiver)?, (encoding_context.transfer as u8).to_be_bytes(), + bytes_to_address(&encoding_context.receiver)?, ); Ok(args.abi_encode_packed()) @@ -1386,10 +1386,10 @@ mod tests { "01", // approval needed "01", - // receiver, - "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // transfer type None "02", + // receiver, + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", )) ); } @@ -1456,10 +1456,10 @@ mod tests { "00", // approval needed "01", - // receiver - "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // transfer type None "02", + // receiver + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", )) ); } @@ -1536,10 +1536,10 @@ mod tests { "01", // approval needed "01", - // receiver - "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // transfer type None "02", + // receiver + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", )) ); } From e0c195f63d6a4b05ea635141d3760194e1d0da4f Mon Sep 17 00:00:00 2001 From: TAMARA LIPOWSKI Date: Fri, 16 May 2025 14:14:21 -0400 Subject: [PATCH 21/22] fix: Fix remaining tests after latest encoding changes --- foundry/src/RestrictTransferFrom.sol | 14 ++++--- foundry/src/executors/BalancerV2Executor.sol | 2 +- foundry/src/executors/EkuboExecutor.sol | 2 +- foundry/src/executors/UniswapV4Executor.sol | 6 +-- foundry/test/TychoRouterSequentialSwap.t.sol | 4 +- foundry/test/TychoRouterSingleSwap.t.sol | 12 +++--- foundry/test/TychoRouterSplitSwap.t.sol | 37 +++++++++---------- foundry/test/TychoRouterTestSetup.sol | 6 +++ foundry/test/assets/calldata.txt | 6 +-- .../test/executors/BalancerV2Executor.t.sol | 10 ++++- .../test/executors/MaverickV2Executor.t.sol | 1 - .../evm/strategy_encoder/strategy_encoders.rs | 1 + 12 files changed, 58 insertions(+), 43 deletions(-) diff --git a/foundry/src/RestrictTransferFrom.sol b/foundry/src/RestrictTransferFrom.sol index 4480a1d..b0ed8c5 100644 --- a/foundry/src/RestrictTransferFrom.sol +++ b/foundry/src/RestrictTransferFrom.sol @@ -7,7 +7,9 @@ import "@permit2/src/interfaces/IAllowanceTransfer.sol"; import "@openzeppelin/contracts/utils/Address.sol"; error RestrictTransferFrom__AddressZero(); -error RestrictTransferFrom__ExceededTransferFromAllowance(); +error RestrictTransferFrom__ExceededTransferFromAllowance( + uint256 allowedAmount, uint256 amountAttempted +); error RestrictTransferFrom__UnknownTransferType(); /** @@ -75,7 +77,6 @@ contract RestrictTransferFrom { if (transferType == TransferType.TransferFrom) { bool isPermit2; address sender; - bool isTransferExecuted; uint256 amountSpent; uint256 amountAllowed; assembly { @@ -85,11 +86,14 @@ contract RestrictTransferFrom { sender := tload(_SENDER_SLOT) amountSpent := tload(_AMOUNT_SPENT_SLOT) } - if (amount + amountSpent > amountAllowed) { - revert RestrictTransferFrom__ExceededTransferFromAllowance(); + uint256 amountAttempted = amountSpent + amount; + if (amountAttempted > amountAllowed) { + revert RestrictTransferFrom__ExceededTransferFromAllowance( + amountAllowed, amountAttempted + ); } assembly { - tstore(_AMOUNT_SPENT_SLOT, amount) + tstore(_AMOUNT_SPENT_SLOT, amountAttempted) } if (isPermit2) { // Permit2.permit is already called from the TychoRouter diff --git a/foundry/src/executors/BalancerV2Executor.sol b/foundry/src/executors/BalancerV2Executor.sol index 3fcf343..43cc7d5 100644 --- a/foundry/src/executors/BalancerV2Executor.sol +++ b/foundry/src/executors/BalancerV2Executor.sol @@ -77,7 +77,7 @@ contract BalancerV2Executor is IExecutor, RestrictTransferFrom { TransferType transferType ) { - if (data.length != 93) { + if (data.length != 94) { revert BalancerV2Executor__InvalidDataLength(); } diff --git a/foundry/src/executors/EkuboExecutor.sol b/foundry/src/executors/EkuboExecutor.sol index 5c6d9f0..63a57b3 100644 --- a/foundry/src/executors/EkuboExecutor.sol +++ b/foundry/src/executors/EkuboExecutor.sol @@ -27,7 +27,7 @@ contract EkuboExecutor is ICore immutable core; - uint256 constant POOL_DATA_OFFSET = 58; + uint256 constant POOL_DATA_OFFSET = 57; uint256 constant HOP_BYTE_LEN = 52; bytes4 constant LOCKED_SELECTOR = 0xb45a3c0e; // locked(uint256) diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index e57797c..b8fd87d 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -38,7 +38,7 @@ contract UniswapV4Executor is IExecutor, IUnlockCallback, ICallback, -RestrictTransferFrom + RestrictTransferFrom { using SafeERC20 for IERC20; using CurrencyLibrary for Currency; @@ -48,8 +48,8 @@ RestrictTransferFrom IPoolManager public immutable poolManager; address private immutable _self; - bytes4 constant SWAP_EXACT_INPUT_SINGLE_SELECTOR = 0xbaa46608; - bytes4 constant SWAP_EXACT_INPUT_SELECTOR = 0x653f1785; + bytes4 constant SWAP_EXACT_INPUT_SINGLE_SELECTOR = 0x6022fbcd; + bytes4 constant SWAP_EXACT_INPUT_SELECTOR = 0x044f0d3d; struct UniswapV4Pool { address intermediaryToken; diff --git a/foundry/test/TychoRouterSequentialSwap.t.sol b/foundry/test/TychoRouterSequentialSwap.t.sol index 390e20a..c7ec175 100644 --- a/foundry/test/TychoRouterSequentialSwap.t.sol +++ b/foundry/test/TychoRouterSequentialSwap.t.sol @@ -22,7 +22,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, DAI_USDC_POOL, // receiver (direct to next pool) false, - RestrictTransferFrom.TransferType.None // transfer to protocol from router + RestrictTransferFrom.TransferType.TransferFrom // transfer to protocol from router ) ); @@ -34,7 +34,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { DAI_USDC_POOL, ALICE, true, - RestrictTransferFrom.TransferType.None // transfer to protocol from router + RestrictTransferFrom.TransferType.None // funds already sent to pool ) ); return swaps; diff --git a/foundry/test/TychoRouterSingleSwap.t.sol b/foundry/test/TychoRouterSingleSwap.t.sol index ffc65e6..107ee6c 100644 --- a/foundry/test/TychoRouterSingleSwap.t.sol +++ b/foundry/test/TychoRouterSingleSwap.t.sol @@ -26,7 +26,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.TransferFrom ); bytes memory swap = @@ -67,7 +67,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.TransferFrom ); bytes memory swap = @@ -134,7 +134,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.TransferFrom ); bytes memory swap = @@ -169,7 +169,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.TransferFrom ); bytes memory swap = @@ -218,7 +218,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - RestrictTransferFrom.TransferType.None + RestrictTransferFrom.TransferType.Transfer // ETH has already been transferred to router ); bytes memory swap = @@ -261,7 +261,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, tychoRouterAddr, true, - RestrictTransferFrom.TransferType.None + RestrictTransferFrom.TransferType.TransferFrom ); bytes memory swap = diff --git a/foundry/test/TychoRouterSplitSwap.t.sol b/foundry/test/TychoRouterSplitSwap.t.sol index 21d79de..6fcf57a 100644 --- a/foundry/test/TychoRouterSplitSwap.t.sol +++ b/foundry/test/TychoRouterSplitSwap.t.sol @@ -2,19 +2,26 @@ pragma solidity ^0.8.26; import "@src/executors/UniswapV4Executor.sol"; -import {TychoRouter} from "@src/TychoRouter.sol"; +import {TychoRouter, RestrictTransferFrom} from "@src/TychoRouter.sol"; import "./TychoRouterTestSetup.sol"; import "./executors/UniswapV4Utils.sol"; import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol"; contract TychoRouterSplitSwapTest is TychoRouterTestSetup { - function _getSplitSwaps() private view returns (bytes[] memory) { + function _getSplitSwaps(bool transferFrom) + private + view + returns (bytes[] memory) + { // Trade 1 WETH for USDC through DAI and WBTC with 4 swaps on Uniswap V2 // -> DAI -> // 1 WETH USDC // -> WBTC -> // (univ2) (univ2) bytes[] memory swaps = new bytes[](4); + RestrictTransferFrom.TransferType transferType = transferFrom + ? RestrictTransferFrom.TransferType.TransferFrom + : RestrictTransferFrom.TransferType.Transfer; // WETH -> WBTC (60%) swaps[0] = encodeSplitSwap( @@ -23,11 +30,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { (0xffffff * 60) / 100, // 60% address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, - WETH_WBTC_POOL, - tychoRouterAddr, - false, - RestrictTransferFrom.TransferType.Transfer + WETH_ADDR, WETH_WBTC_POOL, tychoRouterAddr, false, transferType ) ); // WBTC -> USDC @@ -51,11 +54,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint24(0), address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, - WETH_DAI_POOL, - tychoRouterAddr, - false, - RestrictTransferFrom.TransferType.Transfer + WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, transferType ) ); @@ -83,7 +82,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint256 amountIn = 1 ether; deal(WETH_ADDR, address(tychoRouterAddr), amountIn); vm.startPrank(ALICE); - bytes[] memory swaps = _getSplitSwaps(); + bytes[] memory swaps = _getSplitSwaps(false); tychoRouter.exposedSplitSwap(amountIn, 4, pleEncode(swaps)); vm.stopPrank(); @@ -104,7 +103,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { bytes memory signature ) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn); - bytes[] memory swaps = _getSplitSwaps(); + bytes[] memory swaps = _getSplitSwaps(true); tychoRouter.splitSwapPermit2( amountIn, @@ -133,7 +132,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn); - bytes[] memory swaps = _getSplitSwaps(); + bytes[] memory swaps = _getSplitSwaps(true); tychoRouter.splitSwap( amountIn, @@ -160,7 +159,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes[] memory swaps = _getSplitSwaps(); + bytes[] memory swaps = _getSplitSwaps(true); vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector); tychoRouter.splitSwap( @@ -185,7 +184,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); // Approve less than the amountIn IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn - 1); - bytes[] memory swaps = _getSplitSwaps(); + bytes[] memory swaps = _getSplitSwaps(true); vm.expectRevert(); tychoRouter.splitSwap( @@ -214,7 +213,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { bytes memory signature ) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn); - bytes[] memory swaps = _getSplitSwaps(); + bytes[] memory swaps = _getSplitSwaps(true); uint256 minAmountOut = 3000 * 1e18; @@ -314,7 +313,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, tychoRouterAddr, true, - RestrictTransferFrom.TransferType.Transfer + RestrictTransferFrom.TransferType.TransferFrom ); bytes memory swap = encodeSplitSwap( diff --git a/foundry/test/TychoRouterTestSetup.sol b/foundry/test/TychoRouterTestSetup.sol index 8086535..395afa6 100644 --- a/foundry/test/TychoRouterTestSetup.sol +++ b/foundry/test/TychoRouterTestSetup.sol @@ -28,6 +28,12 @@ contract TychoRouterExposed is TychoRouter { return _unwrapETH(amount); } + function tstoreExposed(address tokenIn, uint256 amountIn, bool isPermit2) + external + { + _tstoreTransferFromInfo(tokenIn, amountIn, isPermit2); + } + function exposedSplitSwap( uint256 amountIn, uint256 nTokens, diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index bd2ab1f..d6b05c8 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -12,14 +12,14 @@ test_single_encoding_strategy_usv4_eth_in:30ace1b1000000000000000000000000000000 test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041f8df51365aa2a34a1658af57e7add49b53e6f0bdab9b27a00578f07a9b78367224ea5f4b0b79092c6d1361512d60433af612822b910fd6d7eea7caa184ebbb041c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000 test_single_encoding_strategy_curve_st_eth:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f6702201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2020000000000000000000000000000000000000000000000 test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041261b12a8bd804743e33746b765070f89e4a08bbe8339fce19ea7d180782c1fc82693906dccc47520368b341d3ca32cfe655625bea8f6844d2d95b61492f741881b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_single_encoding_strategy_curve:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e7102010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_curve:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041579f177eccf39425b9a755adc0c961a0eeff873edcff1dc49ee507f4a3ef10ee36924ff24edd567694929826c77ca3b23a072154b7d815c88352671e480099bf1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041a0b72c7e3b647030d4af52974b437f041cdc78474e91115b614f3ee00f573a64797fb56364e9643beaf8effff491bf464388d81c71bc3f2cedd8b8e38b554b7b1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f8df51365aa2a34a1658af57e7add49b53e6f0bdab9b27a00578f07a9b78367224ea5f4b0b79092c6d1361512d60433af612822b910fd6d7eea7caa184ebbb041c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000 test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f8df51365aa2a34a1658af57e7add49b53e6f0bdab9b27a00578f07a9b78367224ea5f4b0b79092c6d1361512d60433af612822b910fd6d7eea7caa184ebbb041c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000 test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041261b12a8bd804743e33746b765070f89e4a08bbe8339fce19ea7d180782c1fc82693906dccc47520368b341d3ca32cfe655625bea8f6844d2d95b61492f741881b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 -test_uniswap_v3_curve:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20200000000000000000000 -test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684eed6800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827677000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000415d142a1f86e6baa6613d0c8a18d8882027cbeee05c02654ca66fcaaff9cba33f0d17c80da2eaf4084cbe19ea63cca2b453a2c8d46c17cc9f8d3a417a78c534901b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae46030100013ede3eca2a72b3aecc820e955b36f38437d01395020071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_uniswap_v3_curve:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000 +test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684f0d4a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827875200000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041ced5310551c0060b76a36fb93ff84cde86c92c185bd976446eb7473dac468e4e37a08f016005c63f7bcc7e41488d15e95cda5d1a74d387485bdc5dfa2485555b1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0102 test_ekubo_encode_swap_multi:01ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c diff --git a/foundry/test/executors/BalancerV2Executor.t.sol b/foundry/test/executors/BalancerV2Executor.t.sol index c087945..6b099f3 100644 --- a/foundry/test/executors/BalancerV2Executor.t.sol +++ b/foundry/test/executors/BalancerV2Executor.t.sol @@ -78,8 +78,14 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { function testSwap() public { uint256 amountIn = 10 ** 18; - bytes memory protocolData = - abi.encodePacked(WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, BOB, true); + bytes memory protocolData = abi.encodePacked( + WETH_ADDR, + BAL_ADDR, + WETH_BAL_POOL_ID, + BOB, + true, + RestrictTransferFrom.TransferType.Transfer + ); deal(WETH_ADDR, address(balancerV2Exposed), amountIn); uint256 balanceBefore = BAL.balanceOf(BOB); diff --git a/foundry/test/executors/MaverickV2Executor.t.sol b/foundry/test/executors/MaverickV2Executor.t.sol index 9e4bbb3..b9eef8d 100644 --- a/foundry/test/executors/MaverickV2Executor.t.sol +++ b/foundry/test/executors/MaverickV2Executor.t.sol @@ -43,7 +43,6 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { GHO_ADDR, GHO_USDC_POOL, address(2), - true, RestrictTransferFrom.TransferType.Transfer ); diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index 607ec53..d97e5fa 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -2693,6 +2693,7 @@ mod tests { .unwrap(); let hex_calldata = encode(&calldata); + println!("calldata: {}", hex_calldata); write_calldata_to_file("test_single_encoding_strategy_curve", hex_calldata.as_str()); } From cc9e88cfed9763da14f2a9fd77b60f6b78b75e5c Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Mon, 19 May 2025 12:02:57 +0100 Subject: [PATCH 22/22] feat: Add transferFromNeeded to non permit2 methods This will block an attempt to transfer from the user when we expect the funds to already be in the router. chores: - add docs - in EncodingContext, rename transfer to transfer_type Took 58 minutes --- foundry/src/RestrictTransferFrom.sol | 20 +++++++- foundry/src/TychoRouter.sol | 18 ++++--- .../test/TychoRouterProtocolIntegration.t.sol | 10 +++- foundry/test/TychoRouterSequentialSwap.t.sol | 3 ++ foundry/test/TychoRouterSingleSwap.t.sol | 48 ++++++++++++++++++- foundry/test/TychoRouterSplitSwap.t.sol | 4 ++ foundry/test/TychoRouterTestSetup.sol | 13 +++-- foundry/test/assets/calldata.txt | 46 +++++++++--------- .../evm/strategy_encoder/strategy_encoders.rs | 41 +++++++++++----- .../transfer_optimizations.rs | 2 +- .../evm/swap_encoder/swap_encoders.rs | 38 +++++++-------- src/encoding/evm/tycho_encoders.rs | 8 ++-- src/encoding/models.rs | 4 +- 13 files changed, 179 insertions(+), 76 deletions(-) diff --git a/foundry/src/RestrictTransferFrom.sol b/foundry/src/RestrictTransferFrom.sol index b0ed8c5..db9e250 100644 --- a/foundry/src/RestrictTransferFrom.sol +++ b/foundry/src/RestrictTransferFrom.sol @@ -52,21 +52,37 @@ contract RestrictTransferFrom { None } + /** + * @dev This function is used to store the transfer information in the + * contract's storage. This is done as the first step in the swap process in TychoRouter. + */ // slither-disable-next-line assembly function _tstoreTransferFromInfo( address tokenIn, uint256 amountIn, - bool isPermit2 + bool isPermit2, + bool transferFromNeeded ) internal { + uint256 amountAllowed = amountIn; + if (!transferFromNeeded) { + amountAllowed = 0; + } assembly { tstore(_TOKEN_IN_SLOT, tokenIn) - tstore(_AMOUNT_ALLOWED_SLOT, amountIn) + tstore(_AMOUNT_ALLOWED_SLOT, amountAllowed) tstore(_IS_PERMIT2_SLOT, isPermit2) tstore(_SENDER_SLOT, caller()) tstore(_AMOUNT_SPENT_SLOT, 0) } } + /** + * @dev This function is used to transfer the tokens from the sender to the receiver. + * This function is called within the Executor contracts. + * If the TransferType is TransferFrom, it will check if the amount is within the allowed amount and transfer those funds from the user. + * If the TransferType is Transfer, it will transfer the funds from the TychoRouter to the receiver. + * If the TransferType is None, it will do nothing. + */ // slither-disable-next-line assembly function _transfer( address receiver, diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 46740bf..503f09b 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -123,6 +123,7 @@ contract TychoRouter is * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. + * @param transferFromNeeded If false, the contract will assume that the input token is already transferred to the contract and don't allow any transferFroms * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -136,10 +137,11 @@ contract TychoRouter is bool unwrapEth, uint256 nTokens, address receiver, + bool transferFromNeeded, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); - _tstoreTransferFromInfo(tokenIn, amountIn, false); + _tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded); return _splitSwapChecked( amountIn, @@ -199,7 +201,7 @@ contract TychoRouter is if (tokenIn != address(0)) { permit2.permit(msg.sender, permitSingle, signature); } - _tstoreTransferFromInfo(tokenIn, amountIn, true); + _tstoreTransferFromInfo(tokenIn, amountIn, true, true); return _splitSwapChecked( amountIn, @@ -233,6 +235,7 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. + * @param transferFromNeeded If false, the contract will assume that the input token is already transferred to the contract and don't allow any transferFroms * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -245,10 +248,11 @@ contract TychoRouter is bool wrapEth, bool unwrapEth, address receiver, + bool transferFromNeeded, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); - _tstoreTransferFromInfo(tokenIn, amountIn, false); + _tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded); return _sequentialSwapChecked( amountIn, @@ -305,7 +309,7 @@ contract TychoRouter is permit2.permit(msg.sender, permitSingle, signature); } - _tstoreTransferFromInfo(tokenIn, amountIn, true); + _tstoreTransferFromInfo(tokenIn, amountIn, true, true); return _sequentialSwapChecked( amountIn, @@ -336,6 +340,7 @@ contract TychoRouter is * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. + * @param transferFromNeeded If false, the contract will assume that the input token is already transferred to the contract and don't allow any transferFroms * @param swapData Encoded swap details. * * @return amountOut The total amount of the output token received by the receiver. @@ -348,10 +353,11 @@ contract TychoRouter is bool wrapEth, bool unwrapEth, address receiver, + bool transferFromNeeded, bytes calldata swapData ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); - _tstoreTransferFromInfo(tokenIn, amountIn, false); + _tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded); return _singleSwap( amountIn, @@ -407,7 +413,7 @@ contract TychoRouter is if (tokenIn != address(0)) { permit2.permit(msg.sender, permitSingle, signature); } - _tstoreTransferFromInfo(tokenIn, amountIn, true); + _tstoreTransferFromInfo(tokenIn, amountIn, true, true); return _singleSwap( amountIn, diff --git a/foundry/test/TychoRouterProtocolIntegration.t.sol b/foundry/test/TychoRouterProtocolIntegration.t.sol index 15d073d..7157310 100644 --- a/foundry/test/TychoRouterProtocolIntegration.t.sol +++ b/foundry/test/TychoRouterProtocolIntegration.t.sol @@ -85,7 +85,15 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(USDE_ADDR).approve(tychoRouterAddr, amountIn); tychoRouter.singleSwap( - amountIn, USDE_ADDR, WBTC_ADDR, 118280, false, false, ALICE, swap + amountIn, + USDE_ADDR, + WBTC_ADDR, + 118280, + false, + false, + ALICE, + true, + swap ); assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), 118281); diff --git a/foundry/test/TychoRouterSequentialSwap.t.sol b/foundry/test/TychoRouterSequentialSwap.t.sol index c7ec175..9c5d710 100644 --- a/foundry/test/TychoRouterSequentialSwap.t.sol +++ b/foundry/test/TychoRouterSequentialSwap.t.sol @@ -87,6 +87,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, pleEncode(swaps) ); @@ -113,6 +114,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, pleEncode(swaps) ); } @@ -135,6 +137,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, pleEncode(swaps) ); } diff --git a/foundry/test/TychoRouterSingleSwap.t.sol b/foundry/test/TychoRouterSingleSwap.t.sol index 107ee6c..ec74865 100644 --- a/foundry/test/TychoRouterSingleSwap.t.sol +++ b/foundry/test/TychoRouterSingleSwap.t.sol @@ -82,6 +82,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, swap ); @@ -116,7 +117,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector); tychoRouter.singleSwap( - amountIn, WETH_ADDR, DAI_ADDR, 0, false, false, ALICE, swap + amountIn, WETH_ADDR, DAI_ADDR, 0, false, false, ALICE, true, swap ); } @@ -150,6 +151,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, swap ); } @@ -192,6 +194,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, + true, swap ); } @@ -287,6 +290,49 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { vm.stopPrank(); } + function testSingleSwapNoTransferNeededIllegalTransfer() public { + // Tokens are already in the router, there is no need to transfer them. + // Failure because there will be an attempt on an illegal transfer. + uint256 amountIn = 1 ether; + + deal(WETH_ADDR, address(tychoRouter), amountIn); + vm.startPrank(ALICE); + // Approve the tokenIn to be transferred to the router + IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); + + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, + WETH_DAI_POOL, + ALICE, + false, + RestrictTransferFrom.TransferType.TransferFrom + ); + + bytes memory swap = + encodeSingleSwap(address(usv2Executor), protocolData); + + vm.expectRevert( + abi.encodeWithSelector( + RestrictTransferFrom__ExceededTransferFromAllowance.selector, + 0, // allowed amount + amountIn // attempted amount + ) + ); + uint256 amountOut = tychoRouter.singleSwap( + amountIn, + WETH_ADDR, + DAI_ADDR, + 2000 * 1e18, + false, + false, + ALICE, + false, + swap + ); + + vm.stopPrank(); + } + function testSingleSwapIntegration() public { // Tests swapping WETH -> DAI on a USV2 pool with regular approvals deal(WETH_ADDR, ALICE, 1 ether); diff --git a/foundry/test/TychoRouterSplitSwap.t.sol b/foundry/test/TychoRouterSplitSwap.t.sol index 6fcf57a..480d3e7 100644 --- a/foundry/test/TychoRouterSplitSwap.t.sol +++ b/foundry/test/TychoRouterSplitSwap.t.sol @@ -143,6 +143,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, + true, pleEncode(swaps) ); @@ -171,6 +172,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, + true, pleEncode(swaps) ); vm.stopPrank(); @@ -196,6 +198,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 2, ALICE, + true, pleEncode(swaps) ); @@ -482,6 +485,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 2, ALICE, + true, pleEncode(swaps) ); vm.stopPrank(); diff --git a/foundry/test/TychoRouterTestSetup.sol b/foundry/test/TychoRouterTestSetup.sol index 395afa6..d8747e4 100644 --- a/foundry/test/TychoRouterTestSetup.sol +++ b/foundry/test/TychoRouterTestSetup.sol @@ -28,10 +28,15 @@ contract TychoRouterExposed is TychoRouter { return _unwrapETH(amount); } - function tstoreExposed(address tokenIn, uint256 amountIn, bool isPermit2) - external - { - _tstoreTransferFromInfo(tokenIn, amountIn, isPermit2); + function tstoreExposed( + address tokenIn, + uint256 amountIn, + bool isPermit2, + bool transferFromNeeded + ) external { + _tstoreTransferFromInfo( + tokenIn, amountIn, isPermit2, transferFromNeeded + ); } function exposedSplitSwap( diff --git a/foundry/test/assets/calldata.txt b/foundry/test/assets/calldata.txt index d6b05c8..28bd7c1 100644 --- a/foundry/test/assets/calldata.txt +++ b/foundry/test/assets/calldata.txt @@ -1,29 +1,29 @@ -test_uniswap_v3_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010200 -test_single_encoding_strategy_ekubo:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000071a0cb889707d426a7a386870a03bc70d1b069759802cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000000000000000000000000000000000 -test_uniswap_v3_uniswap_v3:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010100000000000000000000 -test_balancer_v2_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 -test_sequential_swap_strategy_encoder_no_permit2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410fa9c637031c3ab6898496918d2d431cf4a85b8f9fa9b18562528fffead3a3790c5f8a32866004f9275e0eb1f45c0954c373f101c0618e6885b04e3c559f782c1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004104b5583d7915973bc9f0f07d7d33ba6f3fb777ceaee0dd2c023cecb8764e8e72257e0255a7e04bb30096137a0fde38a8191f27b6fcaae371e7ec1799a1f43e441b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000 -test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041261b12a8bd804743e33746b765070f89e4a08bbe8339fce19ea7d180782c1fc82693906dccc47520368b341d3ca32cfe655625bea8f6844d2d95b61492f741881b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_no_permit2:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_single_swap_strategy_encoder_no_transfer_in:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041a0b72c7e3b647030d4af52974b437f041cdc78474e91115b614f3ee00f573a64797fb56364e9643beaf8effff491bf464388d81c71bc3f2cedd8b8e38b554b7b1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000 -test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041f8df51365aa2a34a1658af57e7add49b53e6f0bdab9b27a00578f07a9b78367224ea5f4b0b79092c6d1361512d60433af612822b910fd6d7eea7caa184ebbb041c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000 -test_single_encoding_strategy_curve_st_eth:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f6702201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2020000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041261b12a8bd804743e33746b765070f89e4a08bbe8339fce19ea7d180782c1fc82693906dccc47520368b341d3ca32cfe655625bea8f6844d2d95b61492f741881b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 -test_single_encoding_strategy_curve:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 -test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041579f177eccf39425b9a755adc0c961a0eeff873edcff1dc49ee507f4a3ef10ee36924ff24edd567694929826c77ca3b23a072154b7d815c88352671e480099bf1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 -test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041a0b72c7e3b647030d4af52974b437f041cdc78474e91115b614f3ee00f573a64797fb56364e9643beaf8effff491bf464388d81c71bc3f2cedd8b8e38b554b7b1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 -test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f8df51365aa2a34a1658af57e7add49b53e6f0bdab9b27a00578f07a9b78367224ea5f4b0b79092c6d1361512d60433af612822b910fd6d7eea7caa184ebbb041c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000 -test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f8df51365aa2a34a1658af57e7add49b53e6f0bdab9b27a00578f07a9b78367224ea5f4b0b79092c6d1361512d60433af612822b910fd6d7eea7caa184ebbb041c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000 -test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000684eed6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827676f000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041261b12a8bd804743e33746b765070f89e4a08bbe8339fce19ea7d180782c1fc82693906dccc47520368b341d3ca32cfe655625bea8f6844d2d95b61492f741881b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 -test_uniswap_v3_curve:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000 -test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000684f0d4a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006827875200000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041ced5310551c0060b76a36fb93ff84cde86c92c185bd976446eb7473dac468e4e37a08f016005c63f7bcc7e41488d15e95cda5d1a74d387485bdc5dfa2485555b1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 +test_uniswap_v3_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010200 +test_single_encoding_strategy_ekubo:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000071a0cb889707d426a7a386870a03bc70d1b069759802cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000000000000000000000000000000000 +test_uniswap_v3_uniswap_v3:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010100000000000000000000 +test_balancer_v2_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 +test_sequential_swap_strategy_encoder_no_permit2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000068529cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c800000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041b70914df20e4b2675adc5a61d26b959e0fd21e7cce6503b884d5ba9e1db2c82164112e4dc362b9a3ef794a03fcfebe0710700028b79abe8b7de525288ac904991c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000068529cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c8000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c33e9da2d2a5bea1087e27f42b9255fcaea06efa76558843f6192d571b15c09c5818e1a4b3a111bb6accc4cb8b583c318d2386e0e94cc87b9fcc4065db0d65611c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000 +test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410c38cb809e33a4b6239b5aab3ac879ec39ba3a6979404f6cfc882cc15b81e92f02fef7985c8edd3985b39224f2738ca6bbcfe7acf0cd44d8bab89636dcce3bfb1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_no_permit2:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_swap_strategy_encoder_no_transfer_in:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c800000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041f59744bfe3e154be7c72429eb93db7ef2ec00344feeb1376195a2e3f133437f7533c3df955de146e229e4a37fda22acbe11d9393215d14cf1e19334aebbf35e61b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000 +test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000415eb0e4c29f56696a0a8c0445740b653ae67c0f52fe364f52adc19c84fd6fdc837bc0df41516f33500ebe7f05f653bc0e53ec3ec27c223484d29e4567bf5a0f561c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000 +test_single_encoding_strategy_curve_st_eth:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410c38cb809e33a4b6239b5aab3ac879ec39ba3a6979404f6cfc882cc15b81e92f02fef7985c8edd3985b39224f2738ca6bbcfe7acf0cd44d8bab89636dcce3bfb1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_encoding_strategy_curve:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 +test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041e5679a7262a283109d2e312e4ffbec563f501f347efc00418f3a6701492635977583d4e2ff29904a33496b64f1bc2ac73796a546a495ab110cca86e6de1655b61c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 +test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004160aa554efc922689a7f426a984f9fc278aa948b9c78f4e7cc0a5f177e5fb6859632b92d3326f710603d43d3a8ea5753c58a61316fd1bff8e0b388f74c98993b91b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 +test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c90000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000415eb0e4c29f56696a0a8c0445740b653ae67c0f52fe364f52adc19c84fd6fdc837bc0df41516f33500ebe7f05f653bc0e53ec3ec27c223484d29e4567bf5a0f561c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000 +test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c90000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000415eb0e4c29f56696a0a8c0445740b653ae67c0f52fe364f52adc19c84fd6fdc837bc0df41516f33500ebe7f05f653bc0e53ec3ec27c223484d29e4567bf5a0f561c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000 +test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c90000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000410c38cb809e33a4b6239b5aab3ac879ec39ba3a6979404f6cfc882cc15b81e92f02fef7985c8edd3985b39224f2738ca6bbcfe7acf0cd44d8bab89636dcce3bfb1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 +test_uniswap_v3_curve:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000 +test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041a81d713c715dd501edf102a3c3a755a931e3c72e7322d66b620ece81d7c98bae3d46479041445649eeefdb6ccc09c2b933cd37eda3ae8c99034e84f5570eb2c31c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0102 test_ekubo_encode_swap_multi:01ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c test_encode_uniswap_v4_simple_swap:4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec70101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001 -test_single_encoding_strategy_maverick:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 +test_single_encoding_strategy_maverick:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_encode_maverick_v2:40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c671d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e01 test_encode_uniswap_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0001 diff --git a/src/encoding/evm/strategy_encoder/strategy_encoders.rs b/src/encoding/evm/strategy_encoder/strategy_encoders.rs index d97e5fa..9d1973e 100644 --- a/src/encoding/evm/strategy_encoder/strategy_encoders.rs +++ b/src/encoding/evm/strategy_encoder/strategy_encoders.rs @@ -33,6 +33,7 @@ use crate::encoding::{ /// * `selector`: String, the selector for the swap function in the router contract /// * `router_address`: Address of the router to be used to execute swaps /// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers +/// * `token_in_already_in_router`: bool, whether the token in is already in the router #[derive(Clone)] pub struct SingleSwapStrategyEncoder { swap_encoder_registry: SwapEncoderRegistry, @@ -40,6 +41,7 @@ pub struct SingleSwapStrategyEncoder { selector: String, router_address: Bytes, transfer_optimization: TransferOptimization, + token_in_already_in_router: bool, } impl SingleSwapStrategyEncoder { @@ -55,7 +57,8 @@ impl SingleSwapStrategyEncoder { } else { ( None, - "singleSwap(uint256,address,address,uint256,bool,bool,address,bytes)".to_string(), + "singleSwap(uint256,address,address,uint256,bool,bool,address,bool,bytes)" + .to_string(), ) }; Ok(Self { @@ -69,6 +72,7 @@ impl SingleSwapStrategyEncoder { token_in_already_in_router, router_address, ), + token_in_already_in_router, }) } @@ -132,7 +136,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer, + transfer_type: transfer, }; let mut grouped_protocol_data: Vec = vec![]; @@ -176,6 +180,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, + !self.token_in_already_in_router, swap_data, ) .abi_encode() @@ -208,6 +213,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder { /// * `sequential_swap_validator`: SequentialSwapValidator, responsible for checking validity of /// sequential swap solutions /// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers +/// * `token_in_already_in_router`: bool, whether the token in is already in the router #[derive(Clone)] pub struct SequentialSwapStrategyEncoder { swap_encoder_registry: SwapEncoderRegistry, @@ -218,6 +224,7 @@ pub struct SequentialSwapStrategyEncoder { wrapped_address: Bytes, sequential_swap_validator: SequentialSwapValidator, transfer_optimization: TransferOptimization, + token_in_already_in_router: bool, } impl SequentialSwapStrategyEncoder { @@ -233,7 +240,7 @@ impl SequentialSwapStrategyEncoder { } else { ( None, - "sequentialSwap(uint256,address,address,uint256,bool,bool,address,bytes)" + "sequentialSwap(uint256,address,address,uint256,bool,bool,address,bool,bytes)" .to_string(), ) }; @@ -251,6 +258,7 @@ impl SequentialSwapStrategyEncoder { token_in_already_in_router, router_address, ), + token_in_already_in_router, }) } @@ -322,7 +330,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer, + transfer_type: transfer, }; let mut grouped_protocol_data: Vec = vec![]; @@ -371,6 +379,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { wrap, unwrap, bytes_to_address(&solution.receiver)?, + !self.token_in_already_in_router, encoded_swaps, ) .abi_encode() @@ -403,6 +412,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder { /// solutions /// * `router_address`: Address of the router to be used to execute swaps /// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers +/// * `token_in_already_in_router`: bool, whether the token in is already in the router #[derive(Clone)] pub struct SplitSwapStrategyEncoder { swap_encoder_registry: SwapEncoderRegistry, @@ -413,6 +423,7 @@ pub struct SplitSwapStrategyEncoder { split_swap_validator: SplitSwapValidator, router_address: Bytes, transfer_optimization: TransferOptimization, + token_in_already_in_router: bool, } impl SplitSwapStrategyEncoder { @@ -428,7 +439,7 @@ impl SplitSwapStrategyEncoder { } else { ( None, - "splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bytes)" + "splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bool,bytes)" .to_string(), ) }; @@ -446,6 +457,7 @@ impl SplitSwapStrategyEncoder { token_in_already_in_router, router_address, ), + token_in_already_in_router, }) } @@ -557,7 +569,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { router_address: Some(self.router_address.clone()), group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer, + transfer_type: transfer, }; let mut grouped_protocol_data: Vec = vec![]; @@ -616,6 +628,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder { unwrap, U256::from(tokens_len), bytes_to_address(&solution.receiver)?, + !self.token_in_already_in_router, encoded_swaps, ) .abi_encode() @@ -834,7 +847,7 @@ mod tests { .unwrap(); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_input = [ - "20144a07", // Function selector + "5c4b639c", // Function selector "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out @@ -842,7 +855,8 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000100", // offset of swap bytes + "0000000000000000000000000000000000000000000000000000000000000001", // transfer from needed + "0000000000000000000000000000000000000000000000000000000000000120", // offset of swap bytes "0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding // Swap data @@ -916,7 +930,7 @@ mod tests { .unwrap(); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_input = [ - "20144a07", // Function selector + "5c4b639c", // Function selector "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out @@ -924,7 +938,8 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000100", // offset of swap bytes + "0000000000000000000000000000000000000000000000000000000000000000", // transfer from not needed + "0000000000000000000000000000000000000000000000000000000000000120", // offset of swap bytes "0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding // Swap data @@ -1186,7 +1201,7 @@ mod tests { let hex_calldata = encode(&calldata); let expected = String::from(concat!( - "e8a980d7", /* function selector */ + "e21dd0d3", /* function selector */ "0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in "000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in "000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token ou @@ -1194,7 +1209,8 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000", // wrap "0000000000000000000000000000000000000000000000000000000000000000", // unwrap "000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver - "0000000000000000000000000000000000000000000000000000000000000100", /* length ple + "0000000000000000000000000000000000000000000000000000000000000001", /* transfer from needed */ + "0000000000000000000000000000000000000000000000000000000000000120", /* length ple * encode */ "00000000000000000000000000000000000000000000000000000000000000a8", // swap 1 @@ -2693,7 +2709,6 @@ mod tests { .unwrap(); let hex_calldata = encode(&calldata); - println!("calldata: {}", hex_calldata); write_calldata_to_file("test_single_encoding_strategy_curve", hex_calldata.as_str()); } diff --git a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs index a97353f..c13c028 100644 --- a/src/encoding/evm/strategy_encoder/transfer_optimizations.rs +++ b/src/encoding/evm/strategy_encoder/transfer_optimizations.rs @@ -35,7 +35,7 @@ impl TransferOptimization { } } - /// Returns the transfer type that should be used for the first transfer. + /// Returns the transfer type that should be used for the current transfer. pub fn get_transfers( &self, swap: SwapGroup, diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index fb7b7b1..b4711f6 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -66,7 +66,7 @@ impl SwapEncoder for UniswapV2SwapEncoder { component_id, bytes_to_address(&encoding_context.receiver)?, zero_to_one, - (encoding_context.transfer as u8).to_be_bytes(), + (encoding_context.transfer_type as u8).to_be_bytes(), ); Ok(args.abi_encode_packed()) @@ -129,7 +129,7 @@ impl SwapEncoder for UniswapV3SwapEncoder { bytes_to_address(&encoding_context.receiver)?, component_id, zero_to_one, - (encoding_context.transfer as u8).to_be_bytes(), + (encoding_context.transfer_type as u8).to_be_bytes(), ); Ok(args.abi_encode_packed()) @@ -206,7 +206,7 @@ impl SwapEncoder for UniswapV4SwapEncoder { group_token_in_address, group_token_out_address, zero_to_one, - (encoding_context.transfer as u8).to_be_bytes(), + (encoding_context.transfer_type as u8).to_be_bytes(), bytes_to_address(&encoding_context.receiver)?, pool_params, ); @@ -282,7 +282,7 @@ impl SwapEncoder for BalancerV2SwapEncoder { component_id, bytes_to_address(&encoding_context.receiver)?, approval_needed, - (encoding_context.transfer as u8).to_be_bytes(), + (encoding_context.transfer_type as u8).to_be_bytes(), ); Ok(args.abi_encode_packed()) } @@ -344,7 +344,7 @@ impl SwapEncoder for EkuboSwapEncoder { let mut encoded = vec![]; if encoding_context.group_token_in == swap.token_in { - encoded.extend((encoding_context.transfer as u8).to_be_bytes()); + encoded.extend((encoding_context.transfer_type as u8).to_be_bytes()); encoded.extend(bytes_to_address(&encoding_context.receiver)?); encoded.extend(bytes_to_address(&swap.token_in)?); } @@ -575,7 +575,7 @@ impl SwapEncoder for CurveSwapEncoder { i.to_be_bytes::<1>(), j.to_be_bytes::<1>(), approval_needed, - (encoding_context.transfer as u8).to_be_bytes(), + (encoding_context.transfer_type as u8).to_be_bytes(), bytes_to_address(&encoding_context.receiver)?, ); @@ -620,7 +620,7 @@ impl SwapEncoder for MaverickV2SwapEncoder { bytes_to_address(&swap.token_in)?, component_id, bytes_to_address(&encoding_context.receiver)?, - (encoding_context.transfer as u8).to_be_bytes(), + (encoding_context.transfer_type as u8).to_be_bytes(), ); Ok(args.abi_encode_packed()) } @@ -670,7 +670,7 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: TransferType::Transfer, + transfer_type: TransferType::Transfer, }; let encoder = UniswapV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -729,7 +729,7 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: TransferType::Transfer, + transfer_type: TransferType::Transfer, }; let encoder = UniswapV3SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -791,7 +791,7 @@ mod tests { router_address: Some(Bytes::zero(20)), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: TransferType::None, + transfer_type: TransferType::None, }; let encoder = BalancerV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), @@ -865,7 +865,7 @@ mod tests { group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: TransferType::Transfer, + transfer_type: TransferType::Transfer, }; let encoder = UniswapV4SwapEncoder::new( String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"), @@ -936,7 +936,7 @@ mod tests { group_token_in: group_token_in.clone(), // Token out is the same as the group token out group_token_out: token_out.clone(), - transfer: TransferType::Transfer, + transfer_type: TransferType::Transfer, }; let encoder = UniswapV4SwapEncoder::new( @@ -979,7 +979,7 @@ mod tests { router_address: Some(router_address.clone()), group_token_in: usde_address.clone(), group_token_out: wbtc_address.clone(), - transfer: TransferType::Transfer, + transfer_type: TransferType::Transfer, }; // Setup - First sequence: USDE -> USDT @@ -1114,7 +1114,7 @@ mod tests { group_token_out: token_out.clone(), exact_out: false, router_address: Some(Bytes::default()), - transfer: TransferType::Transfer, + transfer_type: TransferType::Transfer, }; let encoder = @@ -1160,7 +1160,7 @@ mod tests { group_token_out: group_token_out.clone(), exact_out: false, router_address: Some(Bytes::default()), - transfer: TransferType::Transfer, + transfer_type: TransferType::Transfer, }; let first_swap = Swap { @@ -1356,7 +1356,7 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: TransferType::None, + transfer_type: TransferType::None, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1426,7 +1426,7 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: TransferType::None, + transfer_type: TransferType::None, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1497,7 +1497,7 @@ mod tests { router_address: None, group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: TransferType::None, + transfer_type: TransferType::None, }; let encoder = CurveSwapEncoder::new( String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"), @@ -1568,7 +1568,7 @@ mod tests { router_address: Some(Bytes::default()), group_token_in: token_in.clone(), group_token_out: token_out.clone(), - transfer: TransferType::Transfer, + transfer_type: TransferType::Transfer, }; let encoder = MaverickV2SwapEncoder::new( String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"), diff --git a/src/encoding/evm/tycho_encoders.rs b/src/encoding/evm/tycho_encoders.rs index 3787372..51d27f5 100644 --- a/src/encoding/evm/tycho_encoders.rs +++ b/src/encoding/evm/tycho_encoders.rs @@ -286,7 +286,7 @@ impl TychoExecutorEncoder { router_address: None, group_token_in: grouped_swap.token_in.clone(), group_token_out: grouped_swap.token_out.clone(), - transfer, + transfer_type: transfer, }; let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?; grouped_protocol_data.extend(protocol_data); @@ -468,7 +468,7 @@ mod tests { Bytes::from_str("0x3ede3eca2a72b3aecc820e955b36f38437d01395").unwrap() ); // single swap selector - assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "20144a07"); + assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "5c4b639c"); } #[test] @@ -493,7 +493,7 @@ mod tests { let transactions = transactions.unwrap(); assert_eq!(transactions.len(), 1); // single swap selector - assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "20144a07"); + assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "5c4b639c"); } #[test] @@ -540,7 +540,7 @@ mod tests { assert_eq!(transactions.len(), 1); assert_eq!(transactions[0].value, eth_amount_in); // sequential swap selector - assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "e8a980d7"); + assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "e21dd0d3"); } #[test] diff --git a/src/encoding/models.rs b/src/encoding/models.rs index ff0f3d7..ef8ae1b 100644 --- a/src/encoding/models.rs +++ b/src/encoding/models.rs @@ -114,15 +114,15 @@ pub struct EncodingContext { pub router_address: Option, pub group_token_in: Bytes, pub group_token_out: Bytes, - pub transfer: TransferType, + pub transfer_type: TransferType, } /// Represents the type of transfer to be performed into the pool. /// /// # Fields /// -/// * `Transfer`: Transfer the token from the router into the protocol. /// * `TransferFrom`: Transfer the token from the sender to the protocol/router. +/// * `Transfer`: Transfer the token from the router into the protocol. /// * `None`: No transfer is needed. Tokens are already in the pool. #[repr(u8)] #[derive(Clone, Debug, PartialEq)]