feat: Support hooks (without special calldata)
Add hook address to encoded data and then use it in execution Add execution test for Euler Took 1 hour 19 minutes Took 2 hours 40 minutes Took 3 minutes Took 2 minutes
This commit is contained in:
committed by
Diana Carvalho
parent
7b48cab3cd
commit
a0581773cd
@@ -85,6 +85,7 @@ contract UniswapV4Executor is
|
||||
bool zeroForOne,
|
||||
TransferType transferType,
|
||||
address receiver,
|
||||
address hook,
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools
|
||||
) = _decodeData(data);
|
||||
bytes memory swapData;
|
||||
@@ -94,7 +95,7 @@ contract UniswapV4Executor is
|
||||
currency1: Currency.wrap(zeroForOne ? tokenOut : tokenIn),
|
||||
fee: pools[0].fee,
|
||||
tickSpacing: pools[0].tickSpacing,
|
||||
hooks: IHooks(address(0))
|
||||
hooks: IHooks(hook)
|
||||
});
|
||||
swapData = abi.encodeWithSelector(
|
||||
this.swapExactInputSingle.selector,
|
||||
@@ -112,7 +113,7 @@ contract UniswapV4Executor is
|
||||
intermediateCurrency: Currency.wrap(pools[i].intermediaryToken),
|
||||
fee: pools[i].fee,
|
||||
tickSpacing: pools[i].tickSpacing,
|
||||
hooks: IHooks(address(0)),
|
||||
hooks: IHooks(hook),
|
||||
hookData: bytes("")
|
||||
});
|
||||
}
|
||||
@@ -143,10 +144,11 @@ contract UniswapV4Executor is
|
||||
bool zeroForOne,
|
||||
TransferType transferType,
|
||||
address receiver,
|
||||
address hook,
|
||||
UniswapV4Pool[] memory pools
|
||||
)
|
||||
{
|
||||
if (data.length < 88) {
|
||||
if (data.length < 108) {
|
||||
revert UniswapV4Executor__InvalidDataLength();
|
||||
}
|
||||
|
||||
@@ -155,10 +157,11 @@ contract UniswapV4Executor is
|
||||
zeroForOne = data[40] != 0;
|
||||
transferType = TransferType(uint8(data[41]));
|
||||
receiver = address(bytes20(data[42:62]));
|
||||
hook = address(bytes20(data[62:82]));
|
||||
|
||||
uint256 poolsLength = (data.length - 62) / 26; // 26 bytes per pool object
|
||||
uint256 poolsLength = (data.length - 82) / 26; // 26 bytes per pool object
|
||||
pools = new UniswapV4Pool[](poolsLength);
|
||||
bytes memory poolsData = data[62:];
|
||||
bytes memory poolsData = data[82:];
|
||||
uint256 offset = 0;
|
||||
for (uint256 i = 0; i < poolsLength; i++) {
|
||||
address intermediaryToken;
|
||||
|
||||
@@ -24,6 +24,7 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor {
|
||||
bool zeroForOne,
|
||||
RestrictTransferFrom.TransferType transferType,
|
||||
address receiver,
|
||||
address hook,
|
||||
UniswapV4Pool[] memory pools
|
||||
)
|
||||
{
|
||||
@@ -37,10 +38,12 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
UniswapV4ExecutorExposed uniswapV4Exposed;
|
||||
IERC20 USDE = IERC20(USDE_ADDR);
|
||||
IERC20 USDT = IERC20(USDT_ADDR);
|
||||
IERC20 USDC = IERC20(USDC_ADDR);
|
||||
|
||||
address poolManager = 0x000000000004444c5dc75cB358380D2e3dE08A90;
|
||||
|
||||
function setUp() public {
|
||||
uint256 forkBlock = 21817316;
|
||||
uint256 forkBlock = 22689128;
|
||||
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
|
||||
uniswapV4Exposed = new UniswapV4ExecutorExposed(
|
||||
IPoolManager(poolManager), PERMIT2_ADDRESS
|
||||
@@ -73,6 +76,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
zeroForOne,
|
||||
RestrictTransferFrom.TransferType.Transfer,
|
||||
ALICE,
|
||||
address(0),
|
||||
pools
|
||||
);
|
||||
|
||||
@@ -82,6 +86,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
bool zeroForOneDecoded,
|
||||
RestrictTransferFrom.TransferType transferType,
|
||||
address receiver,
|
||||
address hook,
|
||||
UniswapV4Executor.UniswapV4Pool[] memory decodedPools
|
||||
) = uniswapV4Exposed.decodeData(data);
|
||||
|
||||
@@ -93,6 +98,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||
);
|
||||
assertEq(receiver, ALICE);
|
||||
assertEq(hook, address(0));
|
||||
assertEq(decodedPools.length, 2);
|
||||
assertEq(decodedPools[0].intermediaryToken, USDT_ADDR);
|
||||
assertEq(decodedPools[0].fee, pool1Fee);
|
||||
@@ -123,6 +129,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
true,
|
||||
RestrictTransferFrom.TransferType.Transfer,
|
||||
ALICE,
|
||||
address(0),
|
||||
pools
|
||||
);
|
||||
|
||||
@@ -180,6 +187,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
true,
|
||||
RestrictTransferFrom.TransferType.Transfer,
|
||||
ALICE,
|
||||
address(0),
|
||||
pools
|
||||
);
|
||||
|
||||
@@ -211,6 +219,42 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
);
|
||||
assertTrue(IERC20(WBTC_ADDR).balanceOf(ALICE) == amountOut);
|
||||
}
|
||||
|
||||
function testSingleSwapEulerHook() public {
|
||||
// Replicating tx: 0xb372306a81c6e840f4ec55f006da6b0b097f435802a2e6fd216998dd12fb4aca
|
||||
address hook = address(0x69058613588536167BA0AA94F0CC1Fe420eF28a8);
|
||||
|
||||
uint256 amountIn = 7407000000;
|
||||
deal(USDC_ADDR, address(uniswapV4Exposed), amountIn);
|
||||
uint256 usdcBalanceBeforeSwapExecutor =
|
||||
USDC.balanceOf(address(uniswapV4Exposed));
|
||||
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||
new UniswapV4Executor.UniswapV4Pool[](1);
|
||||
pools[0] = UniswapV4Executor.UniswapV4Pool({
|
||||
intermediaryToken: WETH_ADDR,
|
||||
fee: uint24(500),
|
||||
tickSpacing: int24(1)
|
||||
});
|
||||
|
||||
bytes memory data = UniswapV4Utils.encodeExactInput(
|
||||
USDC_ADDR,
|
||||
WETH_ADDR,
|
||||
true,
|
||||
RestrictTransferFrom.TransferType.Transfer,
|
||||
ALICE,
|
||||
hook,
|
||||
pools
|
||||
);
|
||||
|
||||
uint256 amountOut = uniswapV4Exposed.swap(amountIn, data);
|
||||
assertEq(amountOut, 2681115183499232721);
|
||||
assertEq(
|
||||
USDC.balanceOf(address(uniswapV4Exposed)),
|
||||
usdcBalanceBeforeSwapExecutor - amountIn
|
||||
);
|
||||
assertTrue(IERC20(WETH_ADDR).balanceOf(ALICE) == amountOut);
|
||||
}
|
||||
}
|
||||
|
||||
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {
|
||||
|
||||
@@ -10,6 +10,7 @@ library UniswapV4Utils {
|
||||
bool zeroForOne,
|
||||
RestrictTransferFrom.TransferType transferType,
|
||||
address receiver,
|
||||
address hook,
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools
|
||||
) public pure returns (bytes memory) {
|
||||
bytes memory encodedPools;
|
||||
@@ -24,7 +25,13 @@ library UniswapV4Utils {
|
||||
}
|
||||
|
||||
return abi.encodePacked(
|
||||
tokenIn, tokenOut, zeroForOne, transferType, receiver, encodedPools
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
zeroForOne,
|
||||
transferType,
|
||||
receiver,
|
||||
hook,
|
||||
encodedPools
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +176,11 @@ impl SwapEncoder for UniswapV4SwapEncoder {
|
||||
EncodingError::FatalError("Failed to pad tick spacing bytes".to_string())
|
||||
})?;
|
||||
|
||||
let hook_address = match get_static_attribute(&swap, "hook") {
|
||||
Ok(hook) => Address::from_slice(&hook),
|
||||
Err(_) => Address::ZERO,
|
||||
};
|
||||
|
||||
// Early check if this is not the first swap
|
||||
if encoding_context.group_token_in != swap.token_in {
|
||||
return Ok((bytes_to_address(&swap.token_out)?, pool_fee_u24, pool_tick_spacing_u24)
|
||||
@@ -199,6 +204,7 @@ impl SwapEncoder for UniswapV4SwapEncoder {
|
||||
zero_to_one,
|
||||
(encoding_context.transfer_type as u8).to_be_bytes(),
|
||||
bytes_to_address(&encoding_context.receiver)?,
|
||||
hook_address,
|
||||
pool_params,
|
||||
);
|
||||
|
||||
@@ -897,6 +903,8 @@ mod tests {
|
||||
"01",
|
||||
// receiver
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
||||
// hook address (not set, so zero)
|
||||
"0000000000000000000000000000000000000000",
|
||||
// pool params:
|
||||
// - intermediary token
|
||||
"dac17f958d2ee523a2206206994597c13d831ec7",
|
||||
@@ -1070,6 +1078,8 @@ mod tests {
|
||||
"01",
|
||||
// receiver
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
||||
// hook address (not set, so zero)
|
||||
"0000000000000000000000000000000000000000",
|
||||
// pool params:
|
||||
// - intermediary token USDT
|
||||
"dac17f958d2ee523a2206206994597c13d831ec7",
|
||||
|
||||
@@ -1253,6 +1253,8 @@ mod tests {
|
||||
"01",
|
||||
// receiver
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
||||
// hook address (not set, so zero)
|
||||
"0000000000000000000000000000000000000000",
|
||||
// first pool intermediary token (ETH)
|
||||
"0000000000000000000000000000000000000000",
|
||||
// fee
|
||||
|
||||
Reference in New Issue
Block a user