1. v4 Hook Permission Flags
A Uniswap v4 hook contract declares which lifecycle callbacks it implements via a 14-bit permission mask. The mask lives in the lowest 14 bits of the hook's deployment address — it is not stored separately. The PoolManager reads address(hook) & 0x3FFF and only calls the methods whose bits are set.
Unitone's required mask: (1 << 11) | (1 << 9) | (1 << 6) = 0x8C0 = 2240 decimal.
The hook contract must be deployed (via CREATE2 salt mining) so its address ends in …0x8C0. v4-core enforces this in Hooks.isValidHookAddress:
uint160 internal constant ALL_HOOK_MASK = uint160((1 << 14) - 1); // 0x3FFF
(uint160(address(self)) & ALL_HOOK_MASK > 0 || fee.isDynamicFee())If the address bits and the implemented methods disagree, the pool fails to initialize.
2. Hook Function Signatures
Copied verbatim from v4-core/src/interfaces/IHooks.sol:
/// @notice The hook called after a swap
/// @return bytes4 selector, int128 hook's delta in unspecified currency.
/// Positive: hook is owed/took currency. Negative: hook owes/sent.
function afterSwap(
address sender,
PoolKey calldata key,
SwapParams calldata params,
BalanceDelta delta,
bytes calldata hookData
) external returns (bytes4, int128);
/// @notice The hook called before liquidity is added
function beforeAddLiquidity(
address sender,
PoolKey calldata key,
ModifyLiquidityParams calldata params,
bytes calldata hookData
) external returns (bytes4);BalanceDelta is a packed int256 carrying (amount0, amount1) as two int128s — the signed net flow of each pool token for a given action. Positive = pool owes the actor, negative = actor owes the pool. Unitone reads delta in afterSwap to compute the LP-fee portion that should be skimmed into the drip buffer for that block, then settles via IPoolManager.take / IPoolManager.settle inside the v4 lock.
Return selectors must equal IHooks.afterSwap.selector / IHooks.beforeAddLiquidity.selector, or the call reverts.
3. Hook Address Encoding (CREATE2 Mining)
The deploy script picks a salt such that:
address = keccak256(0xff ‖ deployer ‖ salt ‖ keccak256(initCode))[12:]
require(uint160(address) & 0x3FFF == 0x8C0)For Unitone (3 bits set out of 14), expected mining cost is ~2^14 / 8 ≈ 2,048 CREATE2 simulations — sub-second on commodity hardware. Tools: HookMiner.sol (v4-periphery) or foundry's vm.computeCreate2Address in a loop.
4. Per-Second Drip Math
State variables maintained by the hook per pool:
bufferBalance // accumulated fees waiting to drip
dripWindow // 7 days = 604_800 seconds
dripStart // unix ts when current buffer started draining
totalShares // sum of LP shares subscribed to drip
share[user] // user's share count
lastClaim[user] // unix ts of user's last claimDrip rate (token/second, scaled):
drip_rate = bufferBalance / dripWindowClaimable for user at time t:
claimable(user, t) = (t - lastClaim[user]) * drip_rate * share[user] / totalSharesWorked Example
Buffer = $10,000 USDC. Window = 7 days = 604,800 s. User holds 5% of totalShares. Time since last claim = 1 hour = 3,600 s.
drip_rate = 10_000 / 604_800 ≈ 0.01653 USDC/sec (pool-wide)
user_rate = 0.01653 * 0.05 ≈ 0.000827 USDC/sec
claimable(1h) = 0.000827 * 3600 ≈ 2.976 USDCSo a 5%-share LP can pull ~$2.98 after one hour, ~$71.43 after 24h, ~$500 if they wait the full window — without producing a single swap.
afterSwap adds new fees to bufferBalance and, when the previous window expires, rolls the unclaimed remainder forward. Because v4 settles via a singleton PoolManager and EIP-1153 transient storage (TLOAD/TSTORE at 100 gas each) carries the deltas within a transaction, the per-swap accounting overhead is ~5–8k gas — an order of magnitude below an ERC-4626 wrapper running on top of v3.
5. Unichain Deployment Context
Official Uniswap v4 deployments on Unichain (chain 130):
Unitone hooks register against the Unichain PoolManager above. Because Unichain inherits OP-Stack call-data compression and 1 s blocks, per-second drip claims are economically rational: a 21k-gas claim at Unichain's typical ~0.001 gwei costs fractions of a cent, versus L1 mainnet where the drip granularity would be swallowed by base fee.
6. References
- Uniswap v4 hook concepts
https://developers.uniswap.org/contracts/v4/concepts/hooks
- v4-core IHooks.sol
https://github.com/Uniswap/v4-core/blob/main/src/interfaces/IHooks.sol
- v4-core Hooks.sol (flag constants + isValidHookAddress)
https://github.com/Uniswap/v4-core/blob/main/src/libraries/Hooks.sol
- v4 deployment addresses by chain
https://developers.uniswap.org/contracts/v4/deployments
- Unichain network information
https://developers.uniswap.org/docs/unichain/technical-information/network-information
- Unichain block explorer
https://uniscan.xyz
- EIP-1153 (transient storage, TLOAD/TSTORE)
https://eips.ethereum.org/EIPS/eip-1153