DOCS/Specification
Mechanics
A token with its own clearing house. Multilateral netting and T+0 delivery-versus-payment settlement on Avalanche C-Chain. Every number on this page is a constant in the contracts, fixed at deploy.
01Overview
No buy or sell of NETT executes on the spot. Orders wait for their session, then clear together.
- 1Orders collect during a 60-second session, 1,440 a day.
- 2When the session ends, a clearer calls
clear(). Buys and sells offset each other at the reference price. - 3Only the net balance is swapped against the AVAX/NETT pool.
- 424 seats, one per UTC hour, hold the exclusive right to clear the sessions of their hour and collect their fee.
- 5Seats are taken by locking NETT as margin, and outbid at 110%.
- 6A holder who does not clear in time fails: anyone buys in and takes part of their margin.
02Architecture
NettToken (ERC-20, ERC20Burnable, fixed supply, no mint)
│
ClearingHouse ── SeatRegistry (24 seats, margins, fails)
│
Uniswap v4 PoolManager ── NETT / native AVAX pool ── NettHook (beforeSwap)| NettToken | Plain ERC-20 with burn(). No transfer tax, no blacklist, no mint after deploy. |
|---|---|
| ClearingHouse | Takes orders, aggregates them per session, runs clear(), takes the tax, pays claims. |
| SeatRegistry | The 24 seats, margin bids, fails and slashes. |
| NettHook | v4 hook on beforeSwap. Reverts any swap whose sender is not the ClearingHouse. Liquidity stays open. |
Pool: NETT / native AVAX (currency0 = address(0)), static 0.30% LP fee, tick spacing 60.
Why there is no oracle
Only the ClearingHouse can swap the official pool, so its price moves only at clear(). Adding liquidity, removing it or donating never moves a v4 price. The spot price read at the start of clear() is therefore exactly the price left by the previous clear: it cannot be pushed, and every user knows it when placing an order.
Accepted limit
Nobody can stop a NETT pool from being opened on another DEX without restricting transfers, which NETT refuses to do. Those pools are tolerated: arbitrage against the official pool has to go through the sessions.
03Sessions & orders
| Session length | 60 s |
|---|---|
| sessionId | block.timestamp / 60 |
| Seat hour of a session | (sessionId * 60 / 3600) % 24 |
| End of session N | (N + 1) * 60 |
Orders
- 1
buy(minNettOut), payable: deposits AVAX into the current session. - 2
sell(amountNett, minAvaxOut): deposits NETT into the current session. - 3An order cannot be cancelled. A session only lasts 60 seconds.
- 4The ClearingHouse only stores per-session totals plus each user's deposit, so
clear()costs the same gas whatever the number of orders.
Clearing queue
Sessions clear in order. Only sessions with at least one order enter the queue. clear() always takes the next one; empty sessions are skipped and never count as a fail.
04The clear()
| B | AVAX deposited by buyers |
|---|---|
| S | Gross NETT deposited by sellers |
| S′ = S × (1 − 2%) | The sellable part of S, after tax |
| P | Reference price, AVAX per NETT, read from the pool at the start of clear() |
| D = B / P | Buyer demand in NETT |
| MAX_IMPACT | 2% per session |
Case 1 · more buying (D > S′)
- 1Sellers fill in full at P and receive S′ × P AVAX.
- 2Residual R = B − S′ × P AVAX is swapped against the pool, price limit P × 1.02.
- 3The pool takes r ≤ R AVAX and returns n NETT.
- 4Buyers receive S′ + n NETT minus tax, and pay S′ × P + r AVAX in total.
- 5Buyer fill rate fB = (S′ × P + r) / B. The rest is refunded at claim.
Case 2 · more selling (D < S′)
- 1Buyers fill in full at P and receive D NETT minus tax.
- 2Residual R = S′ − D NETT is swapped, price limit P × 0.98.
- 3The pool takes r ≤ R NETT and returns a AVAX.
- 4Sellers deliver D + r NETT net and receive B + a AVAX.
- 5Seller fill rate fS = (D + r) / S′. The rest is refunded at claim.
Case 3 · D = S′
Everyone fills at P. Nothing touches the pool.
Price rule
The minority side always fills at P. The dominant side, the one creating the impact, pays a blended price: the netted part at P, the residual at the pool price. The worst price for either side is known when the order is placed: P ± 2%.
Slippage
minNettOut and minAvaxOut are checked at claim on the executed amount. If a minimum is missed, that part is refunded in full and pays no tax.
Claims
claim(sessionIds[]) pays each user their share pro rata to their deposit (fill rate × deposit) plus any refund. Everything is pull: clear() never pushes payments to users.
05Tax & burn
Tax
2%
On the NETT leg of every executed order.
To the clearer
1.5%
Paid inside the same clear().
Burned
0.5%
NettToken.burn(), totalSupply goes down.
The tax is not in the token and not in the hook: the ClearingHouse takes it at settlement. The 0.5% burn sits inside the 2%. Per session: tax = 2% × (NETT executed on the buy side + NETT executed on the sell side). Plain transfers of NETT pay nothing.
06The 24 seats
| Seats | 24, hour 0 to 23 UTC |
|---|---|
| Empty seat | Minimum margin MIN_MARGIN |
| Outbid | At least 110% of the holder's margin, or of the best pending bid if higher |
| Takes effect | At the next hour change (block.timestamp multiple of 3600) |
Functions
- 1
bid(hour, amount)locks NETT. On a held seat it becomes the pending bid; an outbid pending bid is refunded. - 2Promotion is lazy: when the holder is read and the pending bid predates the current hour, the bidder becomes holder.
- 3A replaced holder takes their margin back with
withdrawMargin()and keeps every fee already paid. - 4
resign(hour)gives a seat back outside its active hour and returns the margin. - 5
topUp(hour, amount)adds margin to make a seat harder to outbid.
Hours are not worth the same: the Wall Street open at 14:30 UTC clears far more than 04:00. Bids price each hour on its own.
07Fails & buy-in
| Holder window | 10 s after the session ends |
|---|---|
| Buy-in reward | Session fee (1.5%) + 5% of the holder's remaining margin |
| Fails before loss | 3 in the same occurrence of the hour |
| Seat loss | Seat emptied. 50% of the remaining margin burned, 50% returned to the holder. |
holder = seat[hourOf(N)]
if holder == 0 -> anyone, reward = 1.5%
elif now < end(N) + 10s -> only the holder may call
elif caller != holder -> buy-in:
caller gets 1.5% + 5% of holder margin
fails[hour][dayIndex]++
if fails == 3 -> seat lost (50% burned / 50% returned)
else (holder, late, after 10s) -> may still call, no penaltyThe fail counter is keyed by (hour, dayIndex) and starts from zero at every new occurrence of the hour.
08Token
| Name / ticker | NETT / $NETT |
|---|---|
| Standard | ERC-20 + ERC20Burnable (OpenZeppelin) |
| Supply | Fixed. No mint. |
| Transfer tax | None |
| Liquidity | Uniswap v4 pool NETT / AVAX |
| Launch | No snapshot. Early advantage comes only from using the protocol: taking a seat, clearing. |
09Constants
uint256 constant SESSION = 60; // s
uint256 constant HOLDER_WINDOW = 10; // s
uint256 constant TAX_BPS = 200; // 2%
uint256 constant CLEARER_BPS = 150; // 1.5% (inside the 2%)
uint256 constant BURN_BPS = 50; // 0.5% (inside the 2%)
uint256 constant MAX_IMPACT_BPS = 200; // 2% per session
uint256 constant OUTBID_BPS = 11000; // 110%
uint256 constant BUYIN_SLASH_BPS = 500; // 5% of margin
uint256 constant MAX_FAILS = 3;
uint256 constant LOSS_BURN_BPS = 5000; // 50% of remaining margin
uint24 constant LP_FEE = 3000; // 0.30%No admin function can change them after deploy. Ownership is renounced once the pool and the hook are set up.
10Events
event OrderPlaced(uint256 indexed sessionId, address indexed user, bool isBuy, uint256 amount);
event SessionCleared(uint256 indexed sessionId, address indexed clearer, uint256 refPrice,
uint256 matchedNett, uint256 residualIn, uint256 residualOut,
bool netBuy, uint256 clearerFee, uint256 burned);
event Claimed(address indexed user, uint256 indexed sessionId, uint256 avaxOut, uint256 nettOut);
event SeatBid(uint8 indexed hour, address indexed bidder, uint256 margin);
event SeatTaken(uint8 indexed hour, address indexed holder, uint256 margin);
event SeatFail(uint8 indexed hour, address indexed holder, address indexed buyInBy, uint256 slashed);
event SeatLost(uint8 indexed hour, address indexed holder, uint256 burned, uint256 returned);These events feed this site directly: each session's book, the board of 24 seats, the burn counter and the fail feed.
11Security
- 1
nonReentranton clear(), claim(), bid() and withdrawMargin(). - 2The hook's only rule:
sender == ClearingHousein beforeSwap. - 3Every rounding favours the protocol; dust is burned.
- 4
clear()fits in one block whatever the order count, thanks to per-session totals. - 5Thin liquidity inside ±2% means a partial fill and a refund. That is intended.
- 6If nobody calls clear(), the queue grows and nothing is lost: the next call clears the oldest session, and the reward pays for it.
12Contracts
Avalanche · chain id 43114
- NettTokenNot deployed
- ClearingHouseNot deployed
- NettHookNot deployed
- Uniswap v4 PoolManager0x06380c0e0912312b5150364b9dc4542ba0dbbc85
Ready to clearOpen the clearing house →