Uniperp turns a single Uniswap v4 pool into a full perp market: spot buys & sells, 3× leveraged longs & shorts, on-chain borrow/lend, and TWAP-based liquidation — all carried by the hook's callbacks (beforeInitialize, beforeSwap,afterSwap, plus return-delta variants). No external lender, no oracle, no funding rate. Pools are spun up by a permissionless factory, so anyone can list a new market against any whitelisted base asset and start trading it with leverage from the first block. This paper walks the hook architecture, the math, the live on-chain deployment, and the risks.
Each launched token mints a fresh per-launch hook (CREATE2, salt-mined so the low 14 bits of the address carry the v4 hook-permission flag bits). The full list of launched hooks is the directory on the main page. All contracts verifiable on OKLink.
Uniswap v4 lets a hook contract intercept the lifecycle of a pool — pool initialization, liquidity adds/removes, and every swap, both before and after the swap math runs, with the option to return a custom delta that the PoolManager applies. We use every one of those hooks to build a perp DEX on top of an honest v4 pool, with the bonding curve + leverage engine living inside the hook itself:
The judging axis the hackathon scores Innovation on — “novel mechanism on top of the v4 curve, not a port” — describes exactly this design.
The hook's address carries the v4 hook-permission flag bits encoded in its low 14 bits. Our flag value is 0x2ACC — seven bits set:
| Bit | Callback | Role |
|---|---|---|
| 0x2000 | beforeInitialize | Enforce that initialization runs at the exact tick the bonding curve dictates. |
| 0x0800 | beforeAddLiquidity | Block external LPs — only the hook itself can add liquidity. |
| 0x0200 | beforeRemoveLiquidity | Block external LP withdrawal. |
| 0x0080 | beforeSwap | Take the 1% spot fee, anti-snipe gate (first 3 blocks), per-block borrow accounting, and the leveraged-buy fast path. |
| 0x0040 | afterSwap | Update curveEth, observe TWAP, rebalance bands, run liquidation scan (rate-limited). |
| 0x0008 | beforeSwap returnsDelta | Return a custom delta so internal swaps (leveraged open / close) bypass the spot LP fee. |
| 0x0004 | afterSwap returnsDelta | Symmetric return-delta path for the post-swap leg. |
Because v4 enforces the flag bits at swap time by reading the hook address, the factory must mine a CREATE2 salt whose hook address has exactly those low bits. The frontend does this in a Web Worker; create() reverts if the salt is wrong. The token salt is mined to the same factory CREATE2 space with an ordering constraint (token > base) so the v4 pool key's currency ordering is fixed at launch.
Hot state during a swap (per-block borrow tally, reentrancy guard) lives in EVM transient storage (TSTORE/TLOAD) — cleared at the end of every tx and gas-free vs. SSTORE. The TWAP rides on v4's built-in observation buffer; the 5-minute window is the liquidation oracle (§6).
The curve is a constant product. Two reserves: a base-asset reserve and a token reserve. Their product is invariant:
E is the cumulative base bought into the curve, realTOKEN is the token still inside the curve, and V is a virtual base reserve that sets the launch price and damps early-buy impact. K = totalSupply × V, so at launch realTOKEN = 1,000,000 tokens (all supply starts in the curve).
The price of one token, in base units, follows from constant-product:
Price grows with the square of curve level. Total supply is fixed at 1,000,000 per launch. V and the band width W are admin-set per base, calibrated so every launch opens at the same USD FDV regardless of which base it's paired against:
targetUSD is the opening USD FDV the admin targets at whitelist time (≈ $7,500 across every base, so a launch is the same “size” in USD whether you pair against WOKB or USDC). The audited W/V = 10/7 ratio keeps band geometry self-similar across bases; 10/7 ≈ 1.4286, so with current calibration: a WOKB launch's W ≈ 95.7 WOKB (≈ $10.7K at OKB ≈ $112); a USDC launch's W ≈ 10,696 USDC. The protocol's economic floors (minimum collateral, anti-flash-loan caps, bad-debt thresholds) all derive fromW, so they auto-scale per base without any per-base tuning.
A plain spot buy of ΔE base moves the curve level from E toE + ΔE and pays out the difference in token reserves:
Selling reverses it: feed token back, curve level drops, you receive base. Because price is convex, you always sell into a falling price — the bigger the sale, the worse the average fill. A 1% spot fee, taken in the base asset, applies to every direct spot swap routed through the v4 pool (via the hook's beforeSwap callback). Swaps the protocol performs internally for leverage (the leveraged buy on open, the sell-back on close, the forced sale on a liquidation) bypass this fee via the custom-delta return path (§2) — leverage has its own fee schedule (§9).
Open a position with two inputs: collateral C (in base) and leverage L ∈ {2, 3}. The hook then (long shown; short is the mirror — borrow token, sell for base):
Exposure is roughly L × collateral, financed by a one-time origination fee — no funding rate. The position's value at any later price P is just H · P. Safety is tracked by a health ratio:
Ignoring fees: at open H ≈ L·C / Pentry and D = (L−1)·C, so
Higher leverage = thinner buffer between your entry health and the liquidation line.
A position is liquidated the moment health falls to 1.05 (105%):
Solving for the price at which that happens gives a clean result depending only on leverage:
In words — the percentage move from entry that triggers liquidation:
| Leverage | Entry health | Liq. factor | Price move to liq. |
|---|---|---|---|
| 2× long | 200% | 0.525 | −47.5% |
| 3× long | 150% | 0.700 | −30.0% |
| 2× short | 200% | 1.905 | +90.5% |
| 3× short | 150% | 1.429 | +42.9% |
The health check uses a 5-minute TWAP, not instantaneous spot. A single-block price spike — a flash dump, a sandwich — moves spot but barely budges a 5-minute average, so it cannot manufacture liquidations out of healthy positions. Liquidation does not fire-sell — the position is seized whole into a protocol reserve (rate-limited per block), so no forced-sale cascade can spiral.
Partial closes make positions safer. Closing part of a position repays debt first, which pushes the live Pliq away from current price:
Bad debt. In a severe drawdown a liquidation sale can recover less base than the debt owed. The shortfall is a realized loss to the protocol — recorded openly on-chain (a public bad-debt counter) rather than hidden — and is healed over time from the insurance fund and seized-collateral reserve, never from other users' funds.
On close: the hook sells the requested fraction of your token back into the curve (no spot LP fee — internal swap), repays your debt first, credits the surplus minus a 1% close fee. You withdraw what's credited with a separate claim call. Profit on a full close is approximately:
The only frictions are the 1% origination fee at open (on the borrowed amount) and the 1% close fee at exit (on the surplus). Setting profit to zero, the favorable price move just to recover collateral works out to roughly:
About the same at every leverage because round-trip friction is ~1% of the position notional regardless of L. A losing close pays no close fee at all. For an asset that routinely moves tens of percent, this is a small tax — but a position that drifts sideways bleeds it.
The smooth curve is realized as 300 stacked v4 LP positions — bands— each covering a W-wide window of cumulative base flow (band icovers [i·W, (i+1)·W)). Each band is born holding only token; as buyers push the curve level through a band's window, that band converts from token into base. A band the curve level has already moved past is therefore pure base — and that idle base is what leveraged longs borrow. Shorts are the mirror: they borrow token from bands the price has not yet reached, and sell it.
A borrow draws the protocol reserve first, then bands. No band is ever drained more than 40% (long) / 25% (short), and a hard per-blockborrow cap of W base-equivalent (anti-flash-loan) bounds how much can be borrowed in any single block regardless of source. On close, repaid funds go back to bands (refill first, then deepen the curve) — never to the reserve; the reserve is fed only by liquidation seizes.
Borrowing and refilling only ever touch fully-passed (base-only) or fully-ahead (token-only) bands, never the live band straddling the current price — so the curve's price function stays exactly intact and leverage never distorts the published price.
Three fees, each on a different event. No transaction ever pays more than one of them.
| Fee | Rate | Charged on | Goes to |
|---|---|---|---|
| Spot fee | 1% | Each direct spot buy/sell (in base). Not the leveraged buy or close sell-back. | protocol fee recipient |
| Borrow origination | 1% | The borrowed amount, once at open. | leverage-fee recipient |
| Close fee | 1% | Surplus on close (proceeds after debt repayment). A losing close pays nothing. | leverage-fee recipient |
A spot trader pays one fee. A leverage trader pays one on the way in (origination on the borrowed amount) and one on the way out (on the surplus, if any). The leveraged buy and the close sell-back are themselves fee-free (custom-delta path, §2). No funding rate.
| Total supply (per launch) | 1,000,000 tokens, fixed, all in the curve at genesis |
| V (virtual base reserve) | WOKB base: 67.02 WOKB · USDC base: 7,487 USDC (both target ≈ $7,487 opening USD FDV) |
| K | TOTAL_SUPPLY · V → WOKB: 67,023,136 · USDC: 7,487,130,000 (raw, base units) |
| W (band width) | V · 10/7 (audited W/V ratio) → WOKB: 95.75 · USDC: 10,696 |
| Bands | 300 × W-wide LP positions covering the curve range → WOKB curve top ≈ 28,725 WOKB · USDC curve top ≈ 3.21M USDC |
| Genesis price | V / TOTAL_SUPPLY → WOKB: 0.0000670 WOKB/token (≈ $0.0063 at OKB $94) · USDC: 0.00749 USDC/token |
| Sides | leveraged longs and shorts |
| Leverage | 2× – 3× |
| Per-band borrow cap | 40% (long) / 25% (short) |
| Per-block borrow cap | = W base-equivalent (anti-flash-loan, counts reserve draws) → WOKB ≈ 95.75 WOKB (~$9K) · USDC ≈ 10,696 USDC |
| Min collateral | W / 500 (≈ $20 USD-equivalent on every base) → WOKB ≈ 0.192 WOKB · USDC ≈ 21.4 USDC |
| Liquidation health | 105% — liquidate below it |
| Liquidation oracle | 5-minute TWAP (v4 observations) |
| Liquidation action | seize whole position → reserve (no fire-sale) |
| Close cooldown | 2 blocks after opening |
| Anti-snipe | no external trades/opens for 3 blocks post-launch |
| Hook flags | 0x2ACC (7 callbacks, including return-delta on both swap legs) |
| Spot fee | 1% per direct spot trade, in base → protocol fee recipient |
| Borrow origination fee | 1% of borrowed amount, once at open → leverage-fee recipient |
| Close fee | 1% of close surplus → leverage-fee recipient (losing close pays 0) |
| Funding rate | none — one-time fees, not per-hour |