HALFHOOK
Documentation

How the halving works

Inspired by Bitcoin's issuance schedule, written as a Uniswap v4 hook. Every number on this page is read from the chain or fixed in the contract.

How it works

HALFHOOK is one Uniswap v4 hook, HalvingHook, on Robinhood Chain. A pool that uses it counts every swap as a block. The fee starts at 2.5%, halves every 210 blocks, and stops at a floor.

The fee is always taken in WETH. It piles up inside the hook, and anyone can call harvest to turn it into cbBTC (sats) and send it to the pool's registered recipient.

swapin a hooked pool fee HalvingHook height + 1 (block)pending += WETH feefee halves every 210 harvest recipient99% in cbBTC caller1% in cbBTC
One hook, one fee schedule, one exit: sats.

Schedule

Every 210 blocks the fee halves. In pips (millionths) it is 25000 >> n with n = height / 210, never below the floor of 1,562 pips. The contract counts eras from 0, so era 1 here is era 0 in the contract and the API.

Fee by era
EraBlocksPipsFee
11 to 21025,0002.50%
2211 to 42012,5001.25%
3421 to 6306,2500.625%
4631 to 8403,1250.3125%
5 and on841 and up1,5620.1562%

The floor is 25,000 shifted right four times and rounded down, so 1,562 pips, which is 0.1562%. After the fourth halving the fee stays at the floor for good; no further halving is announced. The swap that makes block 210 still pays the old fee; the next swap pays the new one. One swap, one rate.

What is a block

A block is one swap that pays a fee and has a WETH side worth at least 0.0001 WETH (MIN_BLOCK). Smaller swaps still pay the fee and are shown in the feed in grey, but they do not raise the height.

Anyone can mine blocks. That also means anyone willing to pay the fee and gas can bring a halving forward. That is how the rule works, not a bug.

The fee

The fee is charged on the WETH side of the swap, whichever way you trade and whether you set the input or the output amount. The hook only ever holds WETH.

Example in era 1 (2.5%): swapping 0.01 WETH pays a fee of 0.00025 WETH and the pool receives 0.00975 WETH. The same rate applies when you sell tokens and WETH is what comes out.

ETH
Fee now
—
After next halving
—
Fee as sats
—
Counts as a block
—

From a terminal:

curl -s "https://halfhook.pro/api/quote?eth=0.01"

The answer matches the hook's quoteFee view. Before the hook is on chain the box shows the constant schedule only.

Harvest

harvest(poolId, minSats) is open to anyone. It swaps up to 0.05 WETH (MAX_HARVEST) of the pool's pending fee into cbBTC through a fixed route, sends 99% to the pool's recipient and 1% to whoever called it. If the route returns fewer than minSats, the whole call reverts and the fee stays safe in the hook.

The route is our own demo pool (WETH / cbBTC), set once in the constructor and readable with harvestKey(). That pool holds very little liquidity, so harvests are small and show visible slippage: the sats you get are what the pool pays at that moment, and minSats protects you from a bad fill. If the owner of DemoLP withdraws the liquidity, harvest has no route and pending WETH stays in the hook until liquidity returns. Harvesting in small steps (the cap is 0.05 WETH per call) keeps the price impact down.

To call it yourself, use cast, or press the Harvest button on the home page:

cast send 0x8eF4141633549C5ffbBCf8E749818Af4bb3220cc "harvest(bytes32,uint128)" 0xc3c6e0b2ea6b697576aae8b84c133bed92fc71f7acf8e9f8170f5e10cf1d4d96 1 \
  --rpc-url https://robinhood-rpc.publicnode.com --account <your keystore>

The last argument is minSats; use at least 1. Pending amounts above 0.05 WETH take several calls. The source is on Sourcify.

Pools

One pool: WETH / cbBTC. It is live before the token and holds very little liquidity, so large swaps move its price a lot. Its fees go to the team wallet, in cbBTC. Its liquidity is held by a helper contract, DemoLP, and only the team's deployer wallet (its owner) can withdraw it. If that happens the pool has no liquidity and harvest has no route. The hook itself has no owner.

The token itself trades on Pons; there is no HALFHOOK pool with this hook in v1. Live numbers for the pool are on Pools.

Builders

Any pool that has a WETH side can use the hook. There is no UI for this yet; it is three calls. Currencies must be sorted ascending by address, the LP fee is static, and the pool key must name this hook.

# 1. register: first caller sets the recipient, forever
cast send $HOOK "register((address,address,uint24,int24,address),address)" \
  "($CURRENCY0,$CURRENCY1,3000,60,$HOOK)" $RECIPIENT --rpc-url $RPC --private-key $KEY

# 2. initialize the pool on the PoolManager (reverts NotRegistered without step 1)
cast send 0x8366a39CC670B4001A1121B8F6A443A643e40951 \
  "initialize((address,address,uint24,int24,address),uint160)" \
  "($CURRENCY0,$CURRENCY1,3000,60,$HOOK)" $SQRT_PRICE_X96 --rpc-url $RPC --private-key $KEY

# 3. add liquidity with any v4 position tool; then swaps count as blocks

Registering a pool without a WETH side reverts with QuoteMissing. A pool registered by someone else belongs to their recipient; you cannot change it.

Risks

  • The contract cannot be changed or paused, so a bug cannot be fixed. Nobody outside the team has reviewed it; read the verified source.
  • Fees wait in the hook as WETH until someone harvests. A thin route can return less than expected, then the call reverts and the WETH stays put.
  • The recipient of each pool is fixed at registration.
  • Tokens sent straight to the hook are stuck for good. Do not send anything to it.
  • cbBTC is issued by Coinbase. Robinhood Chain fees and liquidity can change at any time.
  • The cbBTC contract on Robinhood Chain can be paused by its issuer. While it is paused, harvest reverts and fees keep waiting in the hook as WETH; nothing is lost, it just can't turn into sats.
  • Because the demo pool is tiny, a harvest can be sandwiched: someone pushes the price, calls harvest() with a low minSats, then trades back. The most they can take is the WETH waiting in the hook (cents today). minSats only protects whoever calls harvest honestly.
  • Anyone can register a new pool on this hook with themselves as recipient. If you build on it, register and initialize your pool in the same transaction so nobody can claim it first.
  • The demo pool's liquidity sits in DemoLP, which its owner (the team's deployer wallet) can withdraw at any time; the hook has no such power. Withdrawn liquidity means no pool and no harvest route.
  • The pool's liquidity is tiny (about 0.0015 WETH plus cbBTC), so a swap of any size moves the price visibly. Holding the token pays nothing.
  • Anyone can mine blocks cheaply: at the smallest counted swap (0.0001 WETH) the fee is about 0.000525 WETH for a full era 1, plus gas. A halving can be brought forward by anyone willing to pay that.

Contract

DemoLP (holds the demo liquidity; owner can withdraw)
0x3a95…0C06
PoolSwapTest (swap router)
0x755A…7214
PoolManager
0x8366…0951
Quote currency (WETH)
0x0Bd7…AD73
Constants
ConstantValue
START_PIPS25,000 (2.5%)
FLOOR_PIPS1,562 (0.1562%)
HALVINGS4
BLOCKS_PER_ERA210
MIN_BLOCK0.0001 WETH
MAX_HARVEST0.05 WETH per call
CALLER_BPS100 (1%)

The hook has no owner, no pause, no upgrade, no withdraw and no setter; check the verified source (Sourcify, exact match). Proofs and transactions are on Proof.

FAQ

Is this Bitcoin?

No. The schedule borrows Bitcoin's halving idea. The sats are cbBTC, which is issued by Coinbase.

Does holding the token pay anything?

No. Fees go to the pool's registered recipient, which is our team wallet.

Can the fee or recipient be changed?

No. Both are fixed in the contract.

Why do the numbers load without the server?

The pages read the chain directly from your browser. The server only caches and keeps the block ledger; if it is down you still see the live height and the latest blocks.

What counts as a block?

A swap whose WETH side is at least 0.0001 WETH. Smaller swaps pay the fee but do not raise the height.

Where is the ticker?

The token launches on Pons on 31 Oct 2026 at 16:00 UTC. The token trades on Pons; its contract address appears on the home page and in token.json at that moment.