The whole thing, in four contracts.
Small enough to read in an afternoon, which is the only security property that survives contact with reality. Nothing here is deployed; everything here is specified.
What talks to what.
Three tiers. The arrows that matter are the ones that are absent: nothing in the control tier can reach depositor assets, and the exit path crosses no tier at all.
- Core — non-upgradeable, holds assets
- Control — replaceable, holds nothing
- Parameter-only path
A solver that proposes a bad route wastes a batch. A rebalancer that proposes a bad range makes worse fees. Neither can take anything, because neither is ever the recipient of a transfer — the settlement contract pays the signer of the intent and nobody else.
One rule, and it is arithmetic.
Anyone may call it. There is no privileged rebalancer and no keeper subscription; the function is permissionless and reverts when the condition is false. If nobody ever calls it, the range goes stale and fee capture falls — which costs holders yield and costs nobody their principal.
Why a cooldown at all
Without one, a volatile hour is an unbounded number of rebalances, each paying gas and slippage out of the Crucible. The cooldown is the cheapest possible defence: it converts an attack that drains the pool through its own maintenance into an attack that wastes the attacker's gas.
Why a band at all
A range that follows price exactly is a range that is always moving, and moving costs. The band is the width of not caring — inside it, being slightly wrong is cheaper than being right.
Every knob, and the bound it cannot be turned past.
A parameter without a hard bound is not a parameter, it is a permission. These bounds are compiled in — reaching a value outside the column on the right requires a new deployment that people have to choose to move to.
| Parameter | What it controls | Default | Hard bound |
|---|---|---|---|
| band | Drift tolerated before a rebalance is legal | ±3.0% | 0.1% – 25% |
| cooldown | Minimum interval between rebalances | 6 h | 1 h – 7 d |
| batchWindow | How long a Flux batch stays open | 12 s | 2 s – 120 s |
| maxSlippage | Worst fill the settlement contract will accept | 50 bp | 1 – 300 bp |
| protocolFee | Share of swap fees retained by the protocol | 0 bp | 0 – 200 bp |
| mintFee | Charged on casting Ingots | 0 bp | Fixed at 0 |
| redeemFee | Charged on burning Ingots | 0 bp | Fixed at 0 |
The last two rows are the load-bearing ones. Redemption fees are fixed at zero in the code rather than defaulted to zero in a config, because a redemption fee that can be raised later is a mechanism for trapping people who are already in.
There are none.
This table exists so that its being empty is visible. When something is deployed the addresses appear here, and the source is published at the same moment — not before, because unverified source against a live address is worse than none.
| Contract | Network | Address | Source |
|---|---|---|---|
| Crucible | — | Not deployed | — |
| Ingot | — | Not deployed | — |
| Settlement | — | Not deployed | — |
| Registry | — | Not deployed | — |
The spec is the product, for now.
Read what the protocol is structurally unable to do, or how the claim on a position is priced.