feat: Support out transfer straight to the receiver

- The out transfer is now a responsibility of the Executors -> remove this from router methods
- Also adding a check that the receiver got the full amount out
- In encoding, if it is the last swap, pass the receiver as the trade receiver and not the router address (fix encoding tests)
- Fixed some solidity tests (after rebasing with a PR that is still open, I will fix them all)

TODO: Adapt curve and uniswap v4 to support this

--- don't change below this line ---
ENG-4315 Took 3 hours 7 minutes

Took 20 minutes

Took 59 seconds


Took 7 minutes
This commit is contained in:
Diana Carvalho
2025-04-15 12:26:28 +01:00
parent c10d5874f8
commit 9bcb58e5aa
5 changed files with 139 additions and 104 deletions

View File

@@ -58,6 +58,9 @@ import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
error TychoRouter__AddressZero();
error TychoRouter__EmptySwaps();
error TychoRouter__NegativeSlippage(uint256 amount, uint256 minAmount);
error TychoRouter__AmountOutNotFullyReceived(
uint256 amountIn, uint256 amountConsumed
);
error TychoRouter__MessageValueMismatch(uint256 value, uint256 amount);
error TychoRouter__InvalidDataLength();
error TychoRouter__UndefinedMinAmountOut();
@@ -408,9 +411,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
address receiver,
bytes calldata swaps
) internal returns (uint256 amountOut) {
if (receiver == address(0)) {
revert TychoRouter__AddressZero();
}
if (minAmountOut == 0) {
revert TychoRouter__UndefinedMinAmountOut();
}
@@ -420,6 +420,8 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
_wrapETH(amountIn);
tokenIn = address(_weth);
}
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
amountOut = _splitSwap(amountIn, nTokens, swaps);
if (amountOut < minAmountOut) {
@@ -428,11 +430,13 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
if (unwrapEth) {
_unwrapETH(amountOut);
}
if (tokenOut == address(0)) {
Address.sendValue(payable(receiver), amountOut);
} else {
IERC20(tokenOut).safeTransfer(receiver, amountOut);
}
uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver);
uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut;
if (userAmount != amountOut) {
revert TychoRouter__AmountOutNotFullyReceived(userAmount, amountOut);
}
}
@@ -454,9 +458,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
address receiver,
bytes calldata swap_
) internal returns (uint256 amountOut) {
if (receiver == address(0)) {
revert TychoRouter__AddressZero();
}
if (minAmountOut == 0) {
revert TychoRouter__UndefinedMinAmountOut();
}
@@ -470,6 +471,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
(address executor, bytes calldata protocolData) =
swap_.decodeSingleSwap();
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
amountOut = _callExecutor(executor, amountIn, protocolData);
if (amountOut < minAmountOut) {
@@ -478,11 +480,14 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
if (unwrapEth) {
_unwrapETH(amountOut);
}
if (tokenOut == address(0)) {
Address.sendValue(payable(receiver), amountOut);
} else {
IERC20(tokenOut).safeTransfer(receiver, amountOut);
}
uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver);
uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut;
if (userAmount != amountOut) {
revert TychoRouter__AmountOutNotFullyReceived(userAmount, amountOut);
}
}
@@ -504,9 +509,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
address receiver,
bytes calldata swaps
) internal returns (uint256 amountOut) {
if (receiver == address(0)) {
revert TychoRouter__AddressZero();
}
if (minAmountOut == 0) {
revert TychoRouter__UndefinedMinAmountOut();
}
@@ -517,7 +519,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
tokenIn = address(_weth);
}
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
amountOut = _sequentialSwap(amountIn, swaps);
uint256 currentBalanceTokenIn = _balanceOf(tokenIn, address(this));
if (amountOut < minAmountOut) {
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
@@ -525,11 +529,13 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
if (unwrapEth) {
_unwrapETH(amountOut);
}
if (tokenOut == address(0)) {
Address.sendValue(payable(receiver), amountOut);
} else {
IERC20(tokenOut).safeTransfer(receiver, amountOut);
}
uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver);
uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut;
if (userAmount != amountOut) {
revert TychoRouter__AmountOutNotFullyReceived(userAmount, amountOut);
}
}
@@ -764,4 +770,13 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
_handleCallback(data);
return "";
}
function _balanceOf(address token, address owner)
internal
view
returns (uint256)
{
return
token == address(0) ? owner.balance : IERC20(token).balanceOf(owner);
}
}

View File

@@ -36,7 +36,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
encodeUniswapV2Swap(
DAI_ADDR,
DAI_USDC_POOL,
tychoRouterAddr,
ALICE,
true,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
)
@@ -44,22 +44,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
return swaps;
}
function testSequentialSwapInternalMethod() public {
// Trade 1 WETH for USDC through DAI - see _getSequentialSwaps for more info
uint256 amountIn = 1 ether;
deal(WETH_ADDR, ALICE, amountIn);
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
bytes[] memory swaps = _getSequentialSwaps(false);
tychoRouter.exposedSequentialSwap(amountIn, pleEncode(swaps));
vm.stopPrank();
uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(tychoRouterAddr);
assertEq(usdcBalance, 2644659787);
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
}
function testSequentialSwapPermit2() public {
// Trade 1 WETH for USDC through DAI - see _getSequentialSwaps for more info
uint256 amountIn = 1 ether;

View File

@@ -21,11 +21,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
bytes memory signature
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR,
bytes memory protocolData =
encodeUniswapV2Swap(WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
ALICE, false,
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
);
@@ -62,11 +61,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
// Approve the tokenIn to be transferred to the router
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR,
bytes memory protocolData =
encodeUniswapV2Swap(WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
ALICE, false,
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
);
@@ -103,11 +101,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR,
bytes memory protocolData =
encodeUniswapV2Swap(WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
ALICE, false,
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
);
@@ -129,11 +126,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn - 1);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR,
bytes memory protocolData =
encodeUniswapV2Swap(WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
ALICE, false,
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
);
@@ -164,11 +160,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
// Approve the tokenIn to be transferred to the router
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR,
bytes memory protocolData =
encodeUniswapV2Swap(WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
ALICE, false,
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
);
@@ -213,11 +208,10 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
sigDeadline: 0
});
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR,
bytes memory protocolData =
encodeUniswapV2Swap(WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
ALICE, false,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);

View File

@@ -44,11 +44,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
uint8(2),
uint24(0),
address(usv2Executor),
encodeUniswapV2Swap(
WBTC_ADDR,
USDC_WBTC_POOL,
tychoRouterAddr,
true,
encodeUniswapV2Swap(WBTC_ADDR, USDC_WBTC_POOL, ALICE, true,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
)
);
@@ -72,7 +68,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
encodeUniswapV2Swap(
DAI_ADDR,
DAI_USDC_POOL,
tychoRouterAddr,
ALICE,
true,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
)
@@ -92,7 +88,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
tychoRouter.exposedSplitSwap(amountIn, 4, pleEncode(swaps));
vm.stopPrank();
uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(tychoRouterAddr);
uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(ALICE);
assertEq(usdcBalance, 2615491639);
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
}
@@ -136,7 +132,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
deal(WETH_ADDR, ALICE, amountIn);
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
bytes[] memory swaps = _getSplitSwaps(false);
@@ -154,7 +150,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(ALICE);
assertEq(usdcBalance, 2615491639);
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
assertEq(IERC20(WETH_ADDR).balanceOf(ALICE), 0);
}
function testSplitSwapUndefinedMinAmount() public {
@@ -265,11 +261,10 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
spender: address(0),
sigDeadline: 0
});
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR,
bytes memory protocolData =
encodeUniswapV2Swap(WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
ALICE, false,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
@@ -367,7 +362,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
bytes memory protocolData = encodeUniswapV3Swap(
WETH_ADDR,
DAI_ADDR,
tychoRouterAddr,
ALICE,
DAI_WETH_USV3,
zeroForOne,
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL

View File

@@ -111,16 +111,19 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
NativeAction::Unwrap => unwrap = true,
}
}
let protocol = grouped_swap.protocol_system.clone();
let swap_encoder = self
.get_swap_encoder(&grouped_swap.protocol_system)
.get_swap_encoder(&protocol)
.ok_or_else(|| {
EncodingError::InvalidInput(format!(
"Swap encoder not found for protocol: {}",
grouped_swap.protocol_system
protocol
))
})?;
let receiver =
if !unwrap { solution.receiver.clone() } else { self.router_address.clone() };
let mut grouped_protocol_data: Vec<u8> = vec![];
for swap in grouped_swap.swaps.iter() {
let transfer_type = self.get_transfer_type(
@@ -133,7 +136,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
);
let encoding_context = EncodingContext {
receiver: self.router_address.clone(),
receiver: receiver.clone(),
exact_out: solution.exact_out,
router_address: Some(self.router_address.clone()),
group_token_in: grouped_swap.input_token.clone(),
@@ -286,16 +289,23 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
}
let mut swaps = vec![];
for grouped_swap in grouped_swaps.iter() {
for (i, grouped_swap) in grouped_swaps.iter().enumerate() {
let protocol = grouped_swap.protocol_system.clone();
let swap_encoder = self
.get_swap_encoder(&grouped_swap.protocol_system)
.get_swap_encoder(&protocol)
.ok_or_else(|| {
EncodingError::InvalidInput(format!(
"Swap encoder not found for protocol: {}",
grouped_swap.protocol_system
protocol
))
})?;
let receiver = if i == grouped_swaps.len() - 1 && !unwrap {
solution.receiver.clone()
} else {
self.router_address.clone()
};
let mut grouped_protocol_data: Vec<u8> = vec![];
for swap in grouped_swap.swaps.iter() {
let transfer_type = self.get_transfer_type(
@@ -308,7 +318,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
);
let encoding_context = EncodingContext {
receiver: self.router_address.clone(),
receiver: receiver.clone(),
exact_out: solution.exact_out,
router_address: Some(self.router_address.clone()),
group_token_in: grouped_swap.input_token.clone(),
@@ -516,15 +526,22 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
let mut swaps = vec![];
for grouped_swap in grouped_swaps.iter() {
let protocol = grouped_swap.protocol_system.clone();
let swap_encoder = self
.get_swap_encoder(&grouped_swap.protocol_system)
.get_swap_encoder(&protocol)
.ok_or_else(|| {
EncodingError::InvalidInput(format!(
"Swap encoder not found for protocol: {}",
grouped_swap.protocol_system
protocol
))
})?;
let receiver = if !wrap && grouped_swap.output_token == solution.checked_token {
solution.receiver.clone()
} else {
self.router_address.clone()
};
let mut grouped_protocol_data: Vec<u8> = vec![];
for swap in grouped_swap.swaps.iter() {
let transfer_type = self.get_transfer_type(
@@ -537,7 +554,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
);
let encoding_context = EncodingContext {
receiver: self.router_address.clone(),
receiver: receiver.clone(),
exact_out: solution.exact_out,
router_address: Some(self.router_address.clone()),
group_token_in: grouped_swap.input_token.clone(),
@@ -766,7 +783,7 @@ mod tests {
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
"00", // zero2one
"02", // transfer type
"00000000000000", // padding
@@ -869,7 +886,7 @@ mod tests {
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
"00", // zero2one
"02", // transfer type
"0000000000000000000000000000", // padding
@@ -1197,9 +1214,6 @@ mod tests {
#[test]
fn test_sequential_swap_strategy_encoder_no_permit2() {
// Note: This test does not assert anything. It is only used to obtain integration test
// data for our router solidity test.
//
// Performs a split swap from WETH to USDC though WBTC and DAI using USV2 pools
//
// WETH ───(USV2)──> WBTC ───(USV2)──> USDC
@@ -1253,8 +1267,41 @@ mod tests {
.encode_strategy(solution)
.unwrap();
let _hex_calldata = encode(&calldata);
println!("{}", _hex_calldata);
let hex_calldata = encode(&calldata);
println!("{}", hex_calldata);
let expected = String::from(concat!(
"e8a980d7", /* function selector */
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token ou
"00000000000000000000000000000000000000000000000000000000018f61ec", // min amount out
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
"0000000000000000000000000000000000000000000000000000000000000100", /* length ple
* encode */
"00000000000000000000000000000000000000000000000000000000000000a8",
// swap 1
"0052", // swap length
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"bb2b8038a1640196fbe3e38816f3e67cba72d940", // component id
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver (router)
"00", // zero to one
"00", // transfer type
// swap 2
"0052", // swap length
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
"2260fac5e5542a773aa44fbcfedf7c193bc2c599", // token in
"004375dff511095cc5a197a54140a24efef3a416", // component id
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver (final user)
"01", // zero to one
"00", // transfer type
"000000000000000000000000000000000000000000000000", // padding
));
assert_eq!(hex_calldata, expected);
}
#[test]
@@ -1529,7 +1576,7 @@ mod tests {
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
"00", // zero2one
"01", // transfer type
"0000000000000000000000000000", // padding
@@ -1612,7 +1659,7 @@ mod tests {
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
"00", // zero2one
"01", // transfer type
"00000000000000", // padding
@@ -1863,7 +1910,7 @@ mod tests {
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token out
"0001f4", // pool fee
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
"01", // zero2one
"02", // transfer type
@@ -1874,7 +1921,7 @@ mod tests {
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token out
"000bb8", // pool fee
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
"00", // zero2one
"00", // transfer type
@@ -2017,7 +2064,7 @@ mod tests {
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token out
"0001f4", // pool fee
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
"01", // zero2one
"02", // transfer type
@@ -2029,7 +2076,7 @@ mod tests {
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token out
"000bb8", // pool fee
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
"01", // zero2one
"02", // transfer type
@@ -2040,7 +2087,7 @@ mod tests {
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address,
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id,
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
"00", // zero2one
"00", // transfer type
"00000000000000" // padding
@@ -2178,7 +2225,7 @@ mod tests {
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"01", // zero2one
"02", // transfer type
"006e", // ple encoded swaps
@@ -2189,7 +2236,7 @@ mod tests {
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token out
"0001f4", // pool fee
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
"00", // zero2one
"00", // transfer type
@@ -2201,7 +2248,7 @@ mod tests {
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token out
"000bb8", // pool fee
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
"00", // zero2one
"00", // transfer type