Documentation · v0.1 draft
Eclipse
Born from the Hook. Built for private execution.
Uniswap v4 Hooks made market execution programmable. Eclipse extends that capability into a private execution layer: combining private orders, matching them inside a Eclipse Wave, and settling only the remaining imbalance against public liquidity.
Overview
Eclipse lets an existing kind of market, a public Uniswap v4 pool, expose a second execution path. Traders who use it submit private orders into a short batch called a Eclipse Wave. Compatible buy and sell orders are matched with each other. Only the difference, the net imbalance, is traded against the pool.
The rule the whole design follows:
Do not rebuild liquidity. Make existing liquidity privately accessible.
Eclipse is protocol infrastructure. Specter is a planned first-party application that would use it, but the protocol must not depend on Specter. Wallets, terminals, launchpads and aggregators should be able to integrate directly.
Mental model
Same pool, two ways in.
PUBLIC MODE
trader → router → PoolManager.swap → EclipseHook (pass-through) → pool
DARK MODE
trader → private order → Eclipse Wave → match → net
→ Eclipse Executor → PoolManager.swap → EclipseHook (verify) → pool
→ settlement
Eclipse is not a mixer, a separate AMM, a new liquidity pool, a general privacy wallet or a new proof system.
Glossary
| Eclipse Wave | A discrete batch window. Orders accumulate while it is open, lock at cutoff, then match, execute and settle together. |
|---|---|
| Commitment | A hash that binds an order's terms without revealing them before execution. |
| Internal match | Buy and sell volume inside one wave that offsets each other and never touches the pool. |
| Net imbalance | What is left after internal matching. The only amount that trades against public liquidity. |
| Eclipse Executor | The contract that submits a wave's net trade to the PoolManager. |
| EclipseHook | The v4 hook on the pool that verifies dark executions and records their results. |
| Settlement root | A commitment to every user's final output for a wave. |
| Netting efficiency | Internally matched volume divided by gross private volume. |
Eclipse Wave lifecycle
While a wave is OPEN, orders accumulate. At cutoff the wave becomes LOCKED and no order can join or leave. Matching, proving, execution and settlement follow.
Wave length is a trade-off. Short waves feel faster but have a smaller privacy set. Long waves gather more orders but add latency and price movement. Research targets are 15, 30, 60 and 120 seconds, with 30 to 60 seconds as a testnet starting point. The demo on this site uses 30 second waves with accelerated settlement.
Order format
| Field | Visibility (target) |
|---|---|
commitment, waveId, expiry class | Public |
tokenIn / tokenOut, amountIn | Encrypted |
minAmountOut | Encrypted, always required |
owner, nonce | Encrypted |
// illustrative only, final scheme chosen by the cryptography engineer
commitment = Hash(poolId, tokenIn, tokenOut, amountIn,
minAmountOut, expiry, nonce, ownerSecret, randomness)
Authorization must prove the user created the order, owns the funds, and that the order is unexpired, not replayed and unmodified. V1 can use an EIP-712 intent signature plus encrypted transport before full shielded ownership.
Matching & clearing
Matching is deterministic. There is no operator discretion over who fills or at what price. Candidate price policies still under evaluation:
- A · Uniswap execution price reference
- B · midpoint from an oracle or external reference
- C · batch clearing price
- D · VWAP from external execution
The demo uses an illustrative model: matched volume clears at a simulated mid, and the net side shares the pool's price impact pro-rata. Every wave must reconcile:
BUY − SELL = NET // subject to fees and price conversion
gross = matched_buy + matched_sell + net
Partial fills & slippage
If not all volume can execute, the default is a pro-rata fill:
userFill = userRequested × totalFilled / totalRequested
Every order carries minAmountOut or a maximum price. If the aggregate execution would violate it, that order is not filled. The wave removes it, re-nets, re-proves and executes the remaining valid orders. You can trigger this in the demo terminal by setting 0.1% slippage on a large order.
Settlement invariants
total user inputs = internal matched inputs + external execution inputs
+ fees + refund / remainder
total outputs credited = actual outputs received
No synthetic balance creation. Every order, wave, settlement root and proof is replay-protected: a wave settles once and an order is consumed once.
EclipseHook
EclipseHook is the enforcement gateway between private order flow and public Uniswap v4 liquidity. It is attached to the pool when the pool is initialized. Every swap in that pool calls it, which is what lets the pool serve two paths on one liquidity source.
Public path
No Eclipse data in hookData. The hook returns immediately and the swap behaves like any v4 swap.
Eclipse path
The Eclipse Executor passes the wave reference in hookData. beforeSwap verifies it, the pool fills it, afterSwap records the result.
beforeSwap checks
| Check | Reverts with |
|---|---|
| Caller is the registered Eclipse Executor | NotDarkExecutor() |
| Pool is registered for Eclipse | PoolNotRegistered() |
| Wave is locked and not yet settled | WaveAlreadySettled(waveId) |
| Commitment root matches the locked wave | RootMismatch() |
| Swap amount equals the proven net imbalance | AmountMismatch(expected, got) |
| Execution deadline has not passed | DeadlineExpired() |
Never trust hookData blindly. Every field it carries is checked against state the hook already holds.
afterSwap accounting
On the eclipse path, afterSwap captures the actual swap delta, marks the wave as executed, takes the Eclipse fee and emits the data the public proof page reads.
function afterSwap(..., BalanceDelta delta, bytes calldata hookData)
external onlyPoolManager returns (bytes4, int128)
{
if (hookData.length == 0) return (selector, 0); // public path
Wave storage w = waves[waveId];
w.state = EXECUTED;
w.result = delta;
int128 fee = _fee(delta, FEE_BPS); // via afterSwapReturnDelta
emit DarkWaveExecuted(waveId, delta, w.commitmentRoot);
return (selector, fee);
}
Permissions
In v4 a hook's permissions are encoded in the low bits of its address and fixed for the pool's lifetime. Proposed set:
| Flag | Used | Why |
|---|---|---|
beforeInitialize | Yes | Only allow pools created through the Eclipse registry |
beforeSwap | Yes | Verify dark executions |
afterSwap | Yes | Record results, emit proof data |
afterSwapReturnDelta | Yes | Take the Eclipse fee from output |
| Liquidity and donate hooks | No | LPs use the pool exactly like any v4 pool |
Errors
A revert means the swap never happened: no balances move and the wave can be retried or failed safely.
NotDarkExecutor() | Someone other than the Eclipse Executor tried the eclipse path. |
|---|---|
PoolNotRegistered() | The pool is not enabled for Eclipse. |
WaveAlreadySettled(waveId) | Replay of an executed wave. |
RootMismatch() | The commitment root differs from the locked wave. |
AmountMismatch(expected, got) | The trade size differs from the proven net imbalance. |
DeadlineExpired() | The execution window closed. |
Pools with another hook
A v4 pool has exactly one hook, chosen at initialization. A pool that already runs a different hook, such as a graduated Pons pool, cannot add EclipseHook later.
For those pools the plan is an executor-only route: the Eclipse Executor performs the same checks before calling the pool, and the pool's own hook stays untouched. No liquidity migration is required, but enforcement lives in the executor rather than at pool level. V1 supports graduated Pons tokens only, never the pre-graduation bonding curve.
Architecture
| Layer | Role |
|---|---|
| Applications | Submit orders. Specter (planned first-party app), wallets, trading terminals, launchpads and aggregators. |
| Eclipse | Coordinates private execution: order gateway, Eclipse Wave scheduler, deterministic matcher, Eclipse Executor and settlement receipts. |
| Uniswap v4 + EclipseHook | Public liquidity, price discovery and swap execution. The hook enforces the eclipse path on the pool. |
Specter is a planned first-party application for private balances and portfolios, with the line "Your portfolio shouldn't be public." When a Specter user trades, the order routes through Eclipse. The protocol is designed to work without it.
Markets
Netting improves when orders share a wave, so V1 targets one to three liquid markets rather than many thin ones.
| Market | Route | Status |
|---|---|---|
| WETH / USDG | v4 pool with EclipseHook | In this demo, simulated |
| Graduated Pons token | Existing Pons pool, executor route | Planned |
| NVDA / USDG | Stock Token market | Research, gated on legal review |
SDK sketch
import { DarkMode } from '@eclipse/sdk' // not published
const order = await darkMode.createOrder({
pool, tokenIn: 'USDG', tokenOut: 'WETH',
amountIn: '10000', minAmountOut,
})
const receipt = await darkMode.submit(order)
// → { waveId, commitment, status: 'queued' }
Frontends must not send wallet, pair, amount, direction, order id or recipient to ordinary analytics providers.
Admin, pause & upgrades
Admin can (2-of-3 multisig)
- Register supported pools
- Pause new dark orders
- Update bounded fee parameters
- Add a verifier version or execution adapter
Admin cannot
- Steal user funds
- Change a settled wave or rewrite an order
- Forge a valid proof
- Redirect user output
Pause blocks new orders and new waves. It never blocks settlement of already locked valid waves, refunds or user exit. Prefer versioned deployments (EclipseHook V1, V2…) over silent upgrades. If upgradeability is required: multisig, timelock and public notice.
Threat model
Each actor needs a written answer for what they know, what they can do, what they cannot do, the worst case and the mitigation.
| Actor | Ideal failure mode |
|---|---|
| Matcher | Cannot choose prices or favour users; cannot steal funds |
| Relayer | Can delay, cannot change orders, recipients or minimums |
| Executor | Cannot exceed the proven net; the hook rejects it |
| MEV searcher | Sees only post-execution aggregates |
| Admin | Bounded powers, see above |
| Chain observer | Sees one aggregate trade per wave, plus deposits and payouts until funding is shielded |
Open questions before mainnet: can the operator map wallet to order, can the relayer correlate IPs, can an observer infer users from timing, can a user self-submit, and can a user exit if the service disappears. These answers decide every marketing claim.
Roadmap
- 0 · ResearchThreat model, hook design, matching model, ZK stack decision, pool matrix
- 1 · Transparent batch prototypeWaves, matching, netting and v4 execution, all visible
- 2 · Encrypted order layerCommitments and private gateway
- 3 · EclipseHookExecutor authorization, wave validation, execution recording
- 4 · ZK batch proofValid orders, correct netting, correct batch
- 5 · Private settlementSettlement commitments and claim proofs, if needed
- 6–9 · Specter, SDK, Pons, Stock TokensIntegrations, gated by legal review
- 10 · External security reviewContracts, circuits, matcher, relayer, privacy
Disclaimers
This is a concept prototype and working name. No contracts are deployed and no ZK verification, integration or audit is live. All prices, waves and balances on this site are simulated. Private execution and securities-linked assets raise market-structure, securities, AML and sanctions questions that require legal review before any mainnet launch. Nothing here is an offer of a product or service.