The curve is the product. Trader share is monotonically non-increasing in divergence.
Recaptures the arbitrage a swap creates and redistributes it through a bounded, published, non-extractive curve — instead of a hardcoded split anyone can farm.
§1.2 — distribution
Captured profit is paid strictly in order.
Each rank is paid only from what the previous ranks left. Rank 0 exists because in a fixed-split design, the trader who triggers the correction pays the full gas of an arbitrage that benefits everyone else — refunding it first makes “better trader economics” an honest claim rather than marketing.
- Rank 0
- Trigger gas refund — min(gasUsed × basefee × GAS_MULT, P × GAS_CAP_BPS / 10,000)
- ≤ 3.00% of P
- Rank 1
- Trader — R × traderShare(divergence, direction, tier, depth)
- curve-dependent
- Rank 2
- Liquidity providers — R × lpShare — weighted by in-range liquidity × position age
- curve-dependent
- Rank 3
- Protocol — Whatever ranks 0–2 left unpaid
- residual
Rank 0 boundary drawn to scale · the rest is order, not proportion
§1.3 — the curve
Scroll drives divergence. Divergence decides the split.
Every value below is computed from the same formula that ships in Curve.sol — not chosen to look good on a page. Scroll to sweep divergence from 0 to D_MAX_BPS and watch trader share fall.
I2 — traderShare(x₂) ≤ traderShare(x₁) for all x₂ > x₁. Monotonic, by construction. This is the product.
- Divergence
- 0 bps
- x (normalised)
- 0.000
- Base
- 80.0%
- Direction
- buy · 1.00×
- Tier
- 1.00×
- Depth gate
- open
- Trader share
- 80.0%
- Ceiling
- 80.0%
§2 — address mining
Permissions live in the address, not a config file.
v4 encodes hook permissions in the low bits of the deployed address, mined with CREATE2 before deploy. The bitmap is public. We do not request permissions the hook does not use — an unused flag is a legibility cost, not a convenience.
- Bit 12
- afterInitialize() — Auto-registers a pool with the Registry the moment it deploys with this hook
- enabled
- Bit 6
- afterSwap() — Capture + distribute — reads venues, executes the correction, runs the waterfall
- enabled
- Bit 2
- afterSwapReturnDelta() — The hook takes its cut via return delta inside the same unlock, not a second transfer
- enabled
- Bit 10
- afterAddLiquidity() — Position-age ledger for JIT-resistant LP weighting — gated behind D-2
- pending
14 bits, drawn 1:1 — 3 enabled, 1 pending, 10 unused
§2 — architecture
Four components, deliberately separated.
Curve.sol is a pure library. It must be callable off-chain by the simulator with identical results — the published curve and the deployed curve are the same code path. That is the whole credibility argument; the maths is never duplicated in TypeScript.
- Language
- Solidity ^0.8.26
- Testing
- Foundry — invariant + fuzz
- Chain
- Robinhood Chain (Arbitrum stack)
- Frontend
- Next.js, wagmi + viem
- Curve math
- Solidity, compiled to WASM — not reimplemented in TS
§3 — invariants
The test suite’s reason to exist.
v0 — pre-audit
Bounded at compile time. Impossible to quietly change.
Solidity ^0.8.26 · Foundry · v4-core, v4-periphery — no proxy, no admin fee switch, no pausable payout path