fix: Hook and hook data are per pool! not per swap

This was a big bug that was blocking a grouped swap in uniswap v4 with hooks
Updated execution and encoding to match te fix

Took 49 minutes
This commit is contained in:
Diana Carvalho
2025-10-09 11:16:26 +02:00
parent f82ae3b92a
commit d13b4d8586
7 changed files with 168 additions and 111 deletions

View File

@@ -59,6 +59,8 @@ contract UniswapV4Executor is
address intermediaryToken; address intermediaryToken;
uint24 fee; uint24 fee;
int24 tickSpacing; int24 tickSpacing;
address hook;
bytes hookData;
} }
constructor(IPoolManager _poolManager, address _permit2) constructor(IPoolManager _poolManager, address _permit2)
@@ -89,8 +91,6 @@ contract UniswapV4Executor is
bool zeroForOne, bool zeroForOne,
TransferType transferType, TransferType transferType,
address receiver, address receiver,
address hook,
bytes memory hookData,
UniswapV4Executor.UniswapV4Pool[] memory pools UniswapV4Executor.UniswapV4Pool[] memory pools
) = _decodeData(data); ) = _decodeData(data);
bytes memory swapData; bytes memory swapData;
@@ -100,7 +100,7 @@ contract UniswapV4Executor is
currency1: Currency.wrap(zeroForOne ? tokenOut : tokenIn), currency1: Currency.wrap(zeroForOne ? tokenOut : tokenIn),
fee: pools[0].fee, fee: pools[0].fee,
tickSpacing: pools[0].tickSpacing, tickSpacing: pools[0].tickSpacing,
hooks: IHooks(hook) hooks: IHooks(pools[0].hook)
}); });
swapData = abi.encodeWithSelector( swapData = abi.encodeWithSelector(
this.swapExactInputSingle.selector, this.swapExactInputSingle.selector,
@@ -109,7 +109,7 @@ contract UniswapV4Executor is
amountIn, amountIn,
transferType, transferType,
receiver, receiver,
hookData pools[0].hookData
); );
} else { } else {
PathKey[] memory path = new PathKey[](pools.length); PathKey[] memory path = new PathKey[](pools.length);
@@ -118,8 +118,8 @@ contract UniswapV4Executor is
intermediateCurrency: Currency.wrap(pools[i].intermediaryToken), intermediateCurrency: Currency.wrap(pools[i].intermediaryToken),
fee: pools[i].fee, fee: pools[i].fee,
tickSpacing: pools[i].tickSpacing, tickSpacing: pools[i].tickSpacing,
hooks: IHooks(hook), hooks: IHooks(pools[i].hook),
hookData: hookData hookData: pools[i].hookData
}); });
} }
@@ -149,8 +149,6 @@ contract UniswapV4Executor is
bool zeroForOne, bool zeroForOne,
TransferType transferType, TransferType transferType,
address receiver, address receiver,
address hook,
bytes memory hookData,
UniswapV4Pool[] memory pools UniswapV4Pool[] memory pools
) )
{ {
@@ -163,42 +161,71 @@ contract UniswapV4Executor is
zeroForOne = data[40] != 0; zeroForOne = data[40] != 0;
transferType = TransferType(uint8(data[41])); transferType = TransferType(uint8(data[41]));
receiver = address(bytes20(data[42:62])); receiver = address(bytes20(data[42:62]));
hook = address(bytes20(data[62:82]));
bytes calldata remaining = data[82:]; bytes calldata remaining = data[62:];
// Decode first pool with hook data
if (remaining.length < 48) {
// 20 + 3 + 3 + 20 + 2 = 48 minimum
revert UniswapV4Executor__InvalidDataLength();
}
address firstToken = address(bytes20(remaining[0:20])); address firstToken = address(bytes20(remaining[0:20]));
uint24 firstFee = uint24(bytes3(remaining[20:23])); uint24 firstFee = uint24(bytes3(remaining[20:23]));
int24 firstTickSpacing = int24(uint24(bytes3(remaining[23:26]))); int24 firstTickSpacing = int24(uint24(bytes3(remaining[23:26])));
UniswapV4Pool memory firstPool = address firstHook = address(bytes20(remaining[26:46]));
UniswapV4Pool(firstToken, firstFee, firstTickSpacing); uint16 firstHookDataLength = uint16(bytes2(remaining[46:48]));
uint256 firstPoolTotalLength = 48 + firstHookDataLength;
if (remaining.length < firstPoolTotalLength) {
revert UniswapV4Executor__InvalidDataLength();
}
bytes memory firstHookData = remaining[48:48 + firstHookDataLength];
// Remaining after first pool are ple encoded // Remaining after first pool are ple encoded
bytes[] memory encodedPools = bytes[] memory encodedPools = LibPrefixLengthEncodedByteArray.toArray(
LibPrefixLengthEncodedByteArray.toArray(remaining[26:]); remaining[firstPoolTotalLength:]
);
pools = new UniswapV4Pool[](1 + encodedPools.length); pools = new UniswapV4Pool[](1 + encodedPools.length);
pools[0] = firstPool; pools[0] = UniswapV4Pool(
firstToken, firstFee, firstTickSpacing, firstHook, firstHookData
uint256 encodedPoolsLength = 26; );
uint256 plePoolsTotalLength;
// Decode subsequent pools
for (uint256 i = 0; i < encodedPools.length; i++) { for (uint256 i = 0; i < encodedPools.length; i++) {
bytes memory poolsData = encodedPools[i]; bytes memory poolData = encodedPools[i];
address intermediaryToken; address intermediaryToken;
uint24 fee; uint24 fee;
int24 tickSpacing; int24 tickSpacing;
address hook;
uint16 hookDataLength;
// slither-disable-next-line assembly // slither-disable-next-line assembly
assembly { assembly {
intermediaryToken := mload(add(poolsData, add(0, 20))) let dataPtr := add(poolData, 0x20)
fee := shr(232, mload(add(poolsData, add(0, 52)))) intermediaryToken := shr(96, mload(dataPtr))
tickSpacing := shr(232, mload(add(poolsData, add(0, 55)))) fee := and(shr(232, mload(add(dataPtr, 20))), 0xffffff)
} tickSpacing := and(shr(208, mload(add(dataPtr, 20))), 0xffffff)
pools[i + 1] = UniswapV4Pool(intermediaryToken, fee, tickSpacing); hook := shr(96, mload(add(dataPtr, 26)))
plePoolsTotalLength += 2 + encodedPoolsLength; // 2 bytes prefix + data hookDataLength := and(shr(240, mload(add(dataPtr, 46))), 0xffff)
} }
hookData = remaining[26 + plePoolsTotalLength:]; if (poolData.length < 48 + hookDataLength) {
revert UniswapV4Executor__InvalidDataLength();
}
bytes memory hookData = new bytes(hookDataLength);
for (uint256 j = 0; j < hookDataLength; j++) {
hookData[j] = poolData[48 + j];
}
pools[i + 1] = UniswapV4Pool(
intermediaryToken, fee, tickSpacing, hook, hookData
);
}
} }
/** /**

File diff suppressed because one or more lines are too long

View File

@@ -24,8 +24,6 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor {
bool zeroForOne, bool zeroForOne,
RestrictTransferFrom.TransferType transferType, RestrictTransferFrom.TransferType transferType,
address receiver, address receiver,
address hook,
bytes memory hookData,
UniswapV4Pool[] memory pools UniswapV4Pool[] memory pools
) )
{ {
@@ -61,12 +59,16 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
pools[0] = UniswapV4Executor.UniswapV4Pool({ pools[0] = UniswapV4Executor.UniswapV4Pool({
intermediaryToken: USDT_ADDR, intermediaryToken: USDT_ADDR,
fee: pool1Fee, fee: pool1Fee,
tickSpacing: tickSpacing1 tickSpacing: tickSpacing1,
hook: address(0),
hookData: bytes("")
}); });
pools[1] = UniswapV4Executor.UniswapV4Pool({ pools[1] = UniswapV4Executor.UniswapV4Pool({
intermediaryToken: USDE_ADDR, intermediaryToken: USDE_ADDR,
fee: pool2Fee, fee: pool2Fee,
tickSpacing: tickSpacing2 tickSpacing: tickSpacing2,
hook: address(0),
hookData: bytes("0x12345")
}); });
bytes memory data = UniswapV4Utils.encodeExactInput( bytes memory data = UniswapV4Utils.encodeExactInput(
@@ -75,8 +77,6 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
zeroForOne, zeroForOne,
RestrictTransferFrom.TransferType.Transfer, RestrictTransferFrom.TransferType.Transfer,
ALICE, ALICE,
address(0),
bytes(""),
pools pools
); );
@@ -86,8 +86,6 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
bool zeroForOneDecoded, bool zeroForOneDecoded,
RestrictTransferFrom.TransferType transferType, RestrictTransferFrom.TransferType transferType,
address receiver, address receiver,
address hook,
bytes memory hookData,
UniswapV4Executor.UniswapV4Pool[] memory decodedPools UniswapV4Executor.UniswapV4Pool[] memory decodedPools
) = uniswapV4Exposed.decodeData(data); ) = uniswapV4Exposed.decodeData(data);
@@ -99,7 +97,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
uint8(RestrictTransferFrom.TransferType.Transfer) uint8(RestrictTransferFrom.TransferType.Transfer)
); );
assertEq(receiver, ALICE); assertEq(receiver, ALICE);
assertEq(hook, address(0)); assertEq(decodedPools[0].hook, address(0));
assertEq(decodedPools.length, 2); assertEq(decodedPools.length, 2);
assertEq(decodedPools[0].intermediaryToken, USDT_ADDR); assertEq(decodedPools[0].intermediaryToken, USDT_ADDR);
assertEq(decodedPools[0].fee, pool1Fee); assertEq(decodedPools[0].fee, pool1Fee);
@@ -107,6 +105,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
assertEq(decodedPools[1].intermediaryToken, USDE_ADDR); assertEq(decodedPools[1].intermediaryToken, USDE_ADDR);
assertEq(decodedPools[1].fee, pool2Fee); assertEq(decodedPools[1].fee, pool2Fee);
assertEq(decodedPools[1].tickSpacing, tickSpacing2); assertEq(decodedPools[1].tickSpacing, tickSpacing2);
assertEq(decodedPools[1].hookData, bytes("0x12345"));
} }
function testSingleSwap() public { function testSingleSwap() public {
@@ -121,7 +120,9 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
pools[0] = UniswapV4Executor.UniswapV4Pool({ pools[0] = UniswapV4Executor.UniswapV4Pool({
intermediaryToken: USDT_ADDR, intermediaryToken: USDT_ADDR,
fee: uint24(100), fee: uint24(100),
tickSpacing: int24(1) tickSpacing: int24(1),
hook: address(0),
hookData: bytes("")
}); });
bytes memory data = UniswapV4Utils.encodeExactInput( bytes memory data = UniswapV4Utils.encodeExactInput(
@@ -130,8 +131,6 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
true, true,
RestrictTransferFrom.TransferType.Transfer, RestrictTransferFrom.TransferType.Transfer,
ALICE, ALICE,
address(0),
bytes(""),
pools pools
); );
@@ -175,12 +174,16 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
pools[0] = UniswapV4Executor.UniswapV4Pool({ pools[0] = UniswapV4Executor.UniswapV4Pool({
intermediaryToken: USDT_ADDR, intermediaryToken: USDT_ADDR,
fee: uint24(100), fee: uint24(100),
tickSpacing: int24(1) tickSpacing: int24(1),
hook: address(0),
hookData: bytes("")
}); });
pools[1] = UniswapV4Executor.UniswapV4Pool({ pools[1] = UniswapV4Executor.UniswapV4Pool({
intermediaryToken: WBTC_ADDR, intermediaryToken: WBTC_ADDR,
fee: uint24(3000), fee: uint24(3000),
tickSpacing: int24(60) tickSpacing: int24(60),
hook: address(0),
hookData: bytes("")
}); });
bytes memory data = UniswapV4Utils.encodeExactInput( bytes memory data = UniswapV4Utils.encodeExactInput(
@@ -189,8 +192,6 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
true, true,
RestrictTransferFrom.TransferType.Transfer, RestrictTransferFrom.TransferType.Transfer,
ALICE, ALICE,
address(0),
bytes(""),
pools pools
); );
@@ -237,7 +238,9 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
pools[0] = UniswapV4Executor.UniswapV4Pool({ pools[0] = UniswapV4Executor.UniswapV4Pool({
intermediaryToken: WETH_ADDR, intermediaryToken: WETH_ADDR,
fee: uint24(500), fee: uint24(500),
tickSpacing: int24(1) tickSpacing: int24(1),
hook: hook,
hookData: bytes("")
}); });
bytes memory data = UniswapV4Utils.encodeExactInput( bytes memory data = UniswapV4Utils.encodeExactInput(
@@ -246,8 +249,6 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
true, true,
RestrictTransferFrom.TransferType.Transfer, RestrictTransferFrom.TransferType.Transfer,
ALICE, ALICE,
hook,
bytes(""),
pools pools
); );
@@ -295,15 +296,15 @@ contract UniswapV4ExecutorTestForEuler is Constants, TestUtils {
deal(RLUSD_ADDR, address(uniswapV4Exposed), amountIn); deal(RLUSD_ADDR, address(uniswapV4Exposed), amountIn);
address eulerProxy = 0xe1Ce9AF672f8854845E5474400B6ddC7AE458a10; address eulerProxy = 0xe1Ce9AF672f8854845E5474400B6ddC7AE458a10;
uint256 rlusdEulerBalanceBefore = RLUSD.balanceOf(eulerProxy); uint256 rlusdEulerBalanceBefore = RLUSD.balanceOf(eulerProxy);
uint256 rlusdBalanceBeforeSwapExecutor =
RLUSD.balanceOf(address(uniswapV4Exposed));
UniswapV4Executor.UniswapV4Pool[] memory pools = UniswapV4Executor.UniswapV4Pool[] memory pools =
new UniswapV4Executor.UniswapV4Pool[](1); new UniswapV4Executor.UniswapV4Pool[](1);
pools[0] = UniswapV4Executor.UniswapV4Pool({ pools[0] = UniswapV4Executor.UniswapV4Pool({
intermediaryToken: USDT_ADDR, intermediaryToken: USDT_ADDR,
fee: uint24(50), fee: uint24(50),
tickSpacing: int24(1) tickSpacing: int24(1),
hook: address(0xF87ACF8428F2f9403AAA0256A7272d6549ECa8A8),
hookData: bytes("")
}); });
bytes memory data = UniswapV4Utils.encodeExactInput( bytes memory data = UniswapV4Utils.encodeExactInput(
@@ -312,8 +313,6 @@ contract UniswapV4ExecutorTestForEuler is Constants, TestUtils {
true, true,
RestrictTransferFrom.TransferType.Transfer, RestrictTransferFrom.TransferType.Transfer,
ALICE, ALICE,
address(0xF87ACF8428F2f9403AAA0256A7272d6549ECa8A8),
bytes(""),
pools pools
); );
@@ -340,7 +339,9 @@ contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {
pools[0] = UniswapV4Executor.UniswapV4Pool({ pools[0] = UniswapV4Executor.UniswapV4Pool({
intermediaryToken: USDT_ADDR, intermediaryToken: USDT_ADDR,
fee: uint24(100), fee: uint24(100),
tickSpacing: int24(1) tickSpacing: int24(1),
hook: address(0),
hookData: bytes("")
}); });
bytes memory protocolData = UniswapV4Utils.encodeExactInput( bytes memory protocolData = UniswapV4Utils.encodeExactInput(
@@ -349,8 +350,6 @@ contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {
true, true,
RestrictTransferFrom.TransferType.TransferFrom, RestrictTransferFrom.TransferType.TransferFrom,
ALICE, ALICE,
address(0),
bytes(""),
pools pools
); );
@@ -385,12 +384,16 @@ contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {
pools[0] = UniswapV4Executor.UniswapV4Pool({ pools[0] = UniswapV4Executor.UniswapV4Pool({
intermediaryToken: USDT_ADDR, intermediaryToken: USDT_ADDR,
fee: uint24(100), fee: uint24(100),
tickSpacing: int24(1) tickSpacing: int24(1),
hook: address(0),
hookData: bytes("")
}); });
pools[1] = UniswapV4Executor.UniswapV4Pool({ pools[1] = UniswapV4Executor.UniswapV4Pool({
intermediaryToken: WBTC_ADDR, intermediaryToken: WBTC_ADDR,
fee: uint24(3000), fee: uint24(3000),
tickSpacing: int24(60) tickSpacing: int24(60),
hook: address(0),
hookData: bytes("")
}); });
bytes memory protocolData = UniswapV4Utils.encodeExactInput( bytes memory protocolData = UniswapV4Utils.encodeExactInput(
@@ -399,8 +402,6 @@ contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {
true, true,
RestrictTransferFrom.TransferType.TransferFrom, RestrictTransferFrom.TransferType.TransferFrom,
ALICE, ALICE,
address(0),
bytes(""),
pools pools
); );

View File

@@ -10,8 +10,6 @@ library UniswapV4Utils {
bool zeroForOne, bool zeroForOne,
RestrictTransferFrom.TransferType transferType, RestrictTransferFrom.TransferType transferType,
address receiver, address receiver,
address hook,
bytes memory hookData,
UniswapV4Executor.UniswapV4Pool[] memory pools UniswapV4Executor.UniswapV4Pool[] memory pools
) public pure returns (bytes memory) { ) public pure returns (bytes memory) {
require(pools.length > 0, "Must have at least one pool"); require(pools.length > 0, "Must have at least one pool");
@@ -19,7 +17,10 @@ library UniswapV4Utils {
bytes memory firstPool = abi.encodePacked( bytes memory firstPool = abi.encodePacked(
pools[0].intermediaryToken, pools[0].intermediaryToken,
bytes3(pools[0].fee), bytes3(pools[0].fee),
pools[0].tickSpacing pools[0].tickSpacing,
pools[0].hook,
bytes2(uint16(pools[0].hookData.length)),
pools[0].hookData
); );
bytes[] memory encodedExtraPools = new bytes[](pools.length - 1); bytes[] memory encodedExtraPools = new bytes[](pools.length - 1);
@@ -27,7 +28,10 @@ library UniswapV4Utils {
encodedExtraPools[i - 1] = abi.encodePacked( encodedExtraPools[i - 1] = abi.encodePacked(
pools[i].intermediaryToken, pools[i].intermediaryToken,
bytes3(pools[i].fee), bytes3(pools[i].fee),
pools[i].tickSpacing pools[i].tickSpacing,
pools[i].hook,
bytes2(uint16(pools[i].hookData.length)),
pools[i].hookData
); );
} }
@@ -37,10 +41,8 @@ library UniswapV4Utils {
zeroForOne, zeroForOne,
transferType, transferType,
receiver, receiver,
hook,
firstPool, firstPool,
pleEncode(encodedExtraPools), pleEncode(encodedExtraPools)
hookData
); );
} }

View File

@@ -189,23 +189,24 @@ impl SwapEncoder for UniswapV4SwapEncoder {
Ok(hook) => Address::from_slice(&hook), Ok(hook) => Address::from_slice(&hook),
Err(_) => Address::ZERO, Err(_) => Address::ZERO,
}; };
let mut hook_data = AlloyBytes::new();
if encoding_context.group_token_out == swap.token_out { let hook_data = swap
// Add hook data if it's only the last swap .user_data
hook_data = AlloyBytes::from(
swap.user_data
.clone() .clone()
.unwrap_or_default() .unwrap_or_default()
.to_vec(), .to_vec();
);
} let hook_data_length = (hook_data.len() as u16).to_be_bytes();
// Early check if this is not the first swap // Early check if this is not the first swap
if encoding_context.group_token_in != swap.token_in { if encoding_context.group_token_in != swap.token_in {
return Ok(( return Ok((
bytes_to_address(&swap.token_out)?, bytes_to_address(&swap.token_out)?,
pool_fee_u24, pool_fee_u24,
pool_tick_spacing_u24, pool_tick_spacing_u24,
hook_data, hook_address,
hook_data_length,
AlloyBytes::from(hook_data),
) )
.abi_encode_packed()); .abi_encode_packed());
} }
@@ -218,8 +219,15 @@ impl SwapEncoder for UniswapV4SwapEncoder {
let zero_to_one = Self::get_zero_to_one(token_in_address, token_out_address); let zero_to_one = Self::get_zero_to_one(token_in_address, token_out_address);
let pool_params = let pool_params = (
(token_out_address, pool_fee_u24, pool_tick_spacing_u24).abi_encode_packed(); token_out_address,
pool_fee_u24,
pool_tick_spacing_u24,
hook_address,
hook_data_length,
AlloyBytes::from(hook_data),
)
.abi_encode_packed();
let args = ( let args = (
group_token_in_address, group_token_in_address,
@@ -227,9 +235,7 @@ impl SwapEncoder for UniswapV4SwapEncoder {
zero_to_one, zero_to_one,
(encoding_context.transfer_type as u8).to_be_bytes(), (encoding_context.transfer_type as u8).to_be_bytes(),
bytes_to_address(&encoding_context.receiver)?, bytes_to_address(&encoding_context.receiver)?,
hook_address,
pool_params, pool_params,
hook_data,
); );
Ok(args.abi_encode_packed()) Ok(args.abi_encode_packed())
@@ -1249,15 +1255,17 @@ mod tests {
"01", "01",
// receiver // receiver
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
// hook address (not set, so zero)
"0000000000000000000000000000000000000000",
// pool params: // pool params:
// - intermediary token // - intermediary token
"dac17f958d2ee523a2206206994597c13d831ec7", "dac17f958d2ee523a2206206994597c13d831ec7",
// - fee // - fee
"000064", "000064",
// - tick spacing // - tick spacing
"000001" "000001",
// hook address (not set, so zero)
"0000000000000000000000000000000000000000",
// hook data length (0)
"0000"
)) ))
); );
write_calldata_to_file("test_encode_uniswap_v4_simple_swap", hex_swap.as_str()); write_calldata_to_file("test_encode_uniswap_v4_simple_swap", hex_swap.as_str());
@@ -1315,7 +1323,11 @@ mod tests {
// - fee (3 bytes) // - fee (3 bytes)
"000bb8", "000bb8",
// - tick spacing (3 bytes) // - tick spacing (3 bytes)
"00003c" "00003c",
// hook address (not set, so zero)
"0000000000000000000000000000000000000000",
// hook data length (0)
"0000"
)) ))
); );
} }
@@ -1414,8 +1426,6 @@ mod tests {
"01", "01",
// receiver // receiver
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
// hook address (not set, so zero)
"0000000000000000000000000000000000000000",
// pool params: // pool params:
// - intermediary token USDT // - intermediary token USDT
"dac17f958d2ee523a2206206994597c13d831ec7", "dac17f958d2ee523a2206206994597c13d831ec7",
@@ -1423,15 +1433,23 @@ mod tests {
"000064", "000064",
// - tick spacing // - tick spacing
"000001", "000001",
// hook address (not set, so zero)
"0000000000000000000000000000000000000000",
// hook data length (0)
"0000",
// Second swap // Second swap
// ple encoding // ple encoding
"001a", "0030",
// - intermediary token WBTC // - intermediary token WBTC
"2260fac5e5542a773aa44fbcfedf7c193bc2c599", "2260fac5e5542a773aa44fbcfedf7c193bc2c599",
// - fee // - fee
"000bb8", "000bb8",
// - tick spacing // - tick spacing
"00003c" "00003c",
// hook address (not set, so zero)
"0000000000000000000000000000000000000000",
// hook data length (0)
"0000"
)) ))
); );
write_calldata_to_file("test_encode_uniswap_v4_sequential_swap", combined_hex.as_str()); write_calldata_to_file("test_encode_uniswap_v4_sequential_swap", combined_hex.as_str());

View File

@@ -1247,22 +1247,28 @@ mod tests {
"01", "01",
// receiver // receiver
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
// hook address (not set, so zero)
"0000000000000000000000000000000000000000",
// first pool intermediary token (ETH) // first pool intermediary token (ETH)
"0000000000000000000000000000000000000000", "0000000000000000000000000000000000000000",
// fee // fee
"000bb8", "000bb8",
// tick spacing // tick spacing
"00003c", "00003c",
// hook address (not set, so zero)
"0000000000000000000000000000000000000000",
// hook data length (0)
"0000",
// ple encoding // ple encoding
"001a", "0030",
// second pool intermediary token (PEPE) // second pool intermediary token (PEPE)
"6982508145454ce325ddbe47a25d4ec3d2311933", "6982508145454ce325ddbe47a25d4ec3d2311933",
// fee // fee
"0061a8", "0061a8",
// tick spacing // tick spacing
"0001f4" "0001f4",
// hook address (not set, so zero)
"0000000000000000000000000000000000000000",
// hook data length (0)
"0000",
)) ))
); );
} }

View File

@@ -357,7 +357,7 @@ fn test_single_encoding_strategy_usv4_grouped_swap() {
let expected_swaps = String::from(concat!( let expected_swaps = String::from(concat!(
// length of ple encoded swaps without padding // length of ple encoded swaps without padding
"000000000000000000000000000000000000000000000000000000000000009c", "00000000000000000000000000000000000000000000000000000000000000b4",
// Swap data header // Swap data header
"f62849f9a0b5bf2913b396098f7c7019b51a820a", // executor address "f62849f9a0b5bf2913b396098f7c7019b51a820a", // executor address
// Protocol data // Protocol data
@@ -366,18 +366,21 @@ fn test_single_encoding_strategy_usv4_grouped_swap() {
"00", // zero2one "00", // zero2one
"00", // transfer type TransferFrom "00", // transfer type TransferFrom
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver "cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
"0000000000000000000000000000000000000000", // hook address
// First pool params // First pool params
"0000000000000000000000000000000000000000", // intermediary token (ETH) "0000000000000000000000000000000000000000", // intermediary token (ETH)
"000bb8", // fee "000bb8", // fee
"00003c", // tick spacing "00003c", // tick spacing
"0000000000000000000000000000000000000000", // hook address
"0000", // hook data length
// ple encoding // ple encoding
"001a", "0030",
// Second pool params // Second pool params
"6982508145454ce325ddbe47a25d4ec3d2311933", // intermediary token (PEPE) "6982508145454ce325ddbe47a25d4ec3d2311933", // intermediary token (PEPE)
"0061a8", // fee "0061a8", // fee
"0001f4", // tick spacing "0001f4", // tick spacing
"00000000" // padding "0000000000000000000000000000000000000000", // hook address
"0000", // hook data length
"000000000000000000000000" // padding
)); ));
let hex_calldata = encode(&calldata); let hex_calldata = encode(&calldata);