-
-
A swap settles in beforeSwap: the hook prices the trade on the torus and settles against its PoolManager claims.
-
The reserve sphere: an LP range is a plane on it, and x_min is capital the LP never has to hold.
-
Capital efficiency: 13.1×, 6.6× and 2.0× at the peg; the ranges trap near $0.90, $0.80 and $0.36.
-
Every range, one torus: interior ranges add up, boundary ranges add an offset, giving one invariant for the whole book.
-
Providing liquidity: add, remove and collect fees, each settled in a single PoolManager unlock.
-
The swap app: a Uniswap-style interface quoting live from the shared book, with the exact BigInt engine in the browser.
-
The docs site explains the protocol, including the mathematics behind the sphere, ranges and torus.
-
Landing page: one reserve book for n stablecoins, live on Unichain, Ethereum, Arbitrum Sepolia and Arc.
-
The Sandbox: tick planes, the two-asset curve and range states, updating as you quote and commit trades.
-
One book behind every pair: any coin swaps for any other, and LPs pick a range around $1 to earn from every pool.
Inspiration
Every stablecoin targets one dollar, yet AMMs trade them in pairs. Four coins need six separately funded pools and eight coins need twenty-eight, so depth sitting in USDC/USDT does nothing for a DAI/FRAX trade. When a coin depegs, flat pools keep quoting it near $1 and their LPs end up holding it.
Paradigm's Orbital paper proposed a better shape: put all n stablecoins on one n-dimensional sphere and let LPs concentrate liquidity with ranges around the peg. We wanted to know if that could run for real, on-chain, as a Uniswap v4 hook, with every pair pool drawing on one shared book.
What it does
Orbital is a stablecoin AMM built as a Uniswap v4 hook, live on Unichain Sepolia, Ethereum Sepolia, Arbitrum Sepolia and Arc Testnet.
- One reserve book, six pools. The six v4 pair pools of the 4-coin basket (USDC, USDT, DAI, FRAX) are only doors. A USDC→DAI trade and a USDT→FRAX trade move the same reserve vector, so every deposit deepens every route.
- Ranges instead of pairs. An LP picks a range, a plane on the sphere. The demo ranges are 13.1×, 6.6× and 2.0× as capital-efficient as a full-range position.
- Depeg protection. A range stops trading at its boundary. On a single-coin depeg the narrow ranges trap near $0.90 and $0.80, while the wide range keeps the book tradable.
- A full app. Uniswap-style swap and pools pages, live on-chain reads on all four networks, and a Sandbox that shows ranges trapping as a coin depegs.
How we built it
Maths first. The reserves live on a sphere, and each range is a plane on it:
$$\sum_{i=1}^{n} (r - x_i)^2 = r^2, \qquad \alpha = \frac{1}{\sqrt{n}} \sum_i x_i \le k$$
Interior ranges combine into one sphere and boundary ranges add a fixed offset, so the whole book is a single torus, whatever the number of ranges. We wrote an independent Python model in 80-digit Decimal to pin down the sphere, the planes, the torus and the crossing rules before writing any Solidity.
The engine is Solidity 0.8.30 in 18-decimal fixed point:
Sphere4holds the per-range geometry.Torus4holds the consolidated invariant and its bounded solver.SegmentedTorus4handles trades that cross range boundaries, up to 8 segments, flipping ranges mid-trade.
We fixed n = 4, so \( \sqrt{n} = 2 \) is exact in fixed point.
The v4 layer:
OrbitalV4Hookadmits only the six canonical pair pools and rejects native v4 liquidity.- It prices each exact-input swap inside
beforeSwapand settles it with a customBeforeSwapDelta, against ERC-6909 claims it holds in the PoolManager. RangeFeeBook4tracks LP shares and fees per range with Q128 checkpoints.
The frontend is React 19, TypeScript, Vite and viem. It runs a dependency-free BigInt port of the engine in the browser, so every quote exactly matches what the hook pays. The Python model, the Solidity engine (including settlement through a real PoolManager) and the JavaScript engine all agree to the wei on a shared vector file.
Challenges we ran into
- Solving the invariant on-chain. A swap means solving a torus equation in fixed point with bounded gas. We use an interval scan plus bisection with a tight residual bound. An ordinary swap costs about 1.2M gas.
- Crossing boundaries mid-trade. When a trade pushes the book across a range's plane, the engine must solve exactly to the plane, flip that range, rebuild the torus and continue.
- A real bug before submission. Our line-by-line security review found that a trade ending exactly on a range boundary could leave that range trading past its bound and freeze LP withdrawals. We reproduced it with failing tests and fixed it in Solidity, JavaScript and Python together. Then we redeployed and source-verified the hook on all four networks.
- Keeping three implementations in lockstep. Rounding direction matters everywhere: inputs round up, payouts round down, and liquidity rounds in the pool's favour.
Accomplishments that we're proud of
- The full Orbital geometry (sphere, planes, torus and crossings) priced on-chain inside a v4 hook.
- Wei-exact agreement between Python, Solidity and the browser.
- Tests at every layer: 74 Solidity tests (including invariant campaigns that check solvency), 32 Python, 13 simulator, 102 app and 4 end-to-end, all in CI.
- Live and source-verified on four testnets.
What we learned
Fixed-point geometry is mostly about rounding direction. Also, Uniswap v4 hooks are expressive enough to replace a pool's entire pricing and custody model while still settling through the real PoolManager.
What's next
- A production router in place of
PoolSwapTest. - A professional audit.
- Pause and fee governance.
- Support for larger n.
- Real stablecoins in place of the mocks.
Built With
- arbitrum
- arc
- ethereum
- foundry
- github-actions
- python
- react
- slither
- solidity
- typescript
- unichain
- uniswap-v4
- uniswap-v4-hooks
- vercel
- viem
- vite
Log in or sign up for Devpost to join the conversation.