unitone
v4 hook · Unichain · Live spec

Technical Spec.

Hook permissions, function signatures, address encoding, per-second drip math, and Unichain deployment context for Unitone Protocol.

Unitone is a Uniswap v4 hook deployed on Unichain that converts pool fees into a per-second yield stream. Instead of LPs realizing fees only at swap time, accrued fees are deposited into a drip buffer on afterSwap and bled out linearly over a fixed window. New depositors are auto-subscribed on beforeAddLiquidity.

This page is the technical reference: hook permissions, function shapes, address encoding, drip math, and Unichain deployment context.

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.

BitFlagUnitone
13BEFORE_INITIALIZE_FLAG (1 << 13)
12AFTER_INITIALIZE_FLAG (1 << 12)
11BEFORE_ADD_LIQUIDITY_FLAG (1 << 11)✓ YES
10AFTER_ADD_LIQUIDITY_FLAG (1 << 10)
09BEFORE_REMOVE_LIQUIDITY_FLAG (1 << 9)settle pending drip✓ YES
08AFTER_REMOVE_LIQUIDITY_FLAG (1 << 8)
07BEFORE_SWAP_FLAG (1 << 7)
06AFTER_SWAP_FLAG (1 << 6)✓ YES
05BEFORE_DONATE_FLAG (1 << 5)
04AFTER_DONATE_FLAG (1 << 4)
03BEFORE_SWAP_RETURNS_DELTA_FLAG (1 << 3)
02AFTER_SWAP_RETURNS_DELTA_FLAG (1 << 2)
01AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG (1 << 1)
00AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG (1 << 0)

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:

SOLIDITY
uint160 internal constant ALL_HOOK_MASK = uint160((1 << 14) - 1); // 0x3FFF

(uint160(address(self)) & ALL_HOOK_MASK > 0 || fee.isDynamicFee())
v4-core/src/libraries/Hooks.sol — address validity check

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:

SOLIDITY
/// @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:

TXT
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:

SOLIDITY
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 claim

Drip rate (token/second, scaled):

MATH
drip_rate = bufferBalance / dripWindow

Claimable for user at time t:

MATH
claimable(user, t) = (t - lastClaim[user]) * drip_rate * share[user] / totalShares

Worked 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 USDC

So 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

ItemValue
Mainnet chain ID130
Testnet chain ID1301 (Unichain Sepolia)
Public RPC (mainnet)https://mainnet.unichain.org
Public RPC (sepolia)https://sepolia.unichain.org
Block time~1 s (200 ms Flashblock preconfs)
Explorerhttps://uniscan.xyz
Native gas tokenETH

Official Uniswap v4 deployments on Unichain (chain 130):

ContractAddress
PoolManager0x1f98400000000000000000000000000000000004
PositionManager0x4529a01c7a0410167c5740c487a8de60232617bf
Universal Router0xef740bf23acae26f6492b10de645d6b98dc8eaf3
StateView0x86e8631a016f9068c3f085faf484ee3f5fdee8f2
Quoter0x333e3c607b141b18ff6de9f258db6e77fe7491e0
Permit20x000000000022D473030F116dDEE9F6B43aC78BA3

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