Skip to content

Instantly share code, notes, and snippets.

@Philogy
Created December 18, 2025 13:51
Show Gist options
  • Select an option

  • Save Philogy/cfe8245b5abd6de3c830d2770999c1a9 to your computer and use it in GitHub Desktop.

Select an option

Save Philogy/cfe8245b5abd6de3c830d2770999c1a9 to your computer and use it in GitHub Desktop.
Hook to let you insert swaps into position manager modify liquidities batch
// SPDX-License-Identifier: MIT
pragma solidity =0.8.30;
import {IHooks, PoolKey, ModifyLiquidityParams, BalanceDelta} from "v4-core/interfaces/IHooks.sol";
import {Hooks} from "v4-core/libraries/Hooks.sol";
import {IPoolManager, SwapParams} from "v4-core/interfaces/IPoolManager.sol";
import {toBalanceDelta} from "v4-core/types/BalanceDelta.sol";
/// @author philogy <https://github.com/philogy>
contract SwapBackdoorHook {
using Hooks for IHooks;
error NotValidHookAddress();
error InvalidHookCall();
IPoolManager internal immutable UNI_V4;
uint256 internal constant POOL_KEY_CALLDATA_SIZE = 0xa0;
uint256 internal constant SWAP_PARAMS_CALLDATA_SIZE = 0x60;
constructor(IPoolManager uniV4) {
require(
IHooks(address(this)).hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_FLAG),
NotValidHookAddress()
);
require(
IHooks(address(this)).hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG),
NotValidHookAddress()
);
require(
IHooks(address(this)).hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG),
NotValidHookAddress()
);
require(
IHooks(address(this)).hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG),
NotValidHookAddress()
);
UNI_V4 = uniV4;
}
function afterAddLiquidity(
address,
PoolKey calldata,
ModifyLiquidityParams calldata,
BalanceDelta,
BalanceDelta,
bytes calldata hookData
) external returns (bytes4, BalanceDelta) {
require(msg.sender == address(UNI_V4), InvalidHookCall());
BalanceDelta delta = _swap(hookData);
return (this.afterAddLiquidity.selector, delta);
}
function afterRemoveLiquidity(
address,
PoolKey calldata,
ModifyLiquidityParams calldata,
BalanceDelta,
BalanceDelta,
bytes calldata hookData
) external returns (bytes4, BalanceDelta) {
require(msg.sender == address(UNI_V4), InvalidHookCall());
BalanceDelta delta = _swap(hookData);
return (this.afterRemoveLiquidity.selector, delta);
}
function _swap(bytes calldata input) internal returns (BalanceDelta inverseSwapDelta) {
require(
input.length >= POOL_KEY_CALLDATA_SIZE + SWAP_PARAMS_CALLDATA_SIZE, InvalidHookCall()
);
PoolKey calldata key;
SwapParams calldata params;
assembly {
key := input.offset
params := add(input.offset, POOL_KEY_CALLDATA_SIZE)
input.offset := add(
input.offset,
add(POOL_KEY_CALLDATA_SIZE, SWAP_PARAMS_CALLDATA_SIZE)
)
input.length := sub(
input.length,
add(POOL_KEY_CALLDATA_SIZE, SWAP_PARAMS_CALLDATA_SIZE)
)
}
BalanceDelta delta = UNI_V4.swap(key, params, input);
inverseSwapDelta = toBalanceDelta(-delta.amount0(), -delta.amount1());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment