Complete protocol · deployed · audited · launch-staged

RAI Dollar, rebuilt from scratch —
ready to fire on mainnet.

A full, faithful reimplementation of the RAI Dollar protocol — the 8-collateral, ungoverned, zero-admin CDP stablecoin. Built from the public docs and ancestor code, proven with 935 tests and a 2.46M-call invariant suite, hardened by a three-lens audit, deployed live on Sepolia, and packaged as an executable launch runbook whose only remaining inputs are addresses your team holds.

testnetLIVE · Sepolia · 161/161 contracts
mainnet packageSTAGED
awaiting9 external inputs
161 /161
contracts live on Sepolia, all with code
935 /935
tests passing · 0 failures
2.46M calls
invariant suite · 12/12 green
9
fail-closed inputs · deploy reverts until set
Fire order

The launch sequence.

Ten ordered steps from a frozen commit to an open market — ./launch.sh, the executable form of LAUNCH-RUNBOOK.md. Each step is one command with a machine-checkable post-condition and a written abort path; each is idempotent and records itself in .launch_state, so go --from <step> resumes cleanly after an abort. Two of them are HARD GATES: the protocol renounces every admin key inside the deploy, so a misconfigured launch cannot be patched — only redeployed. Every gate below exists because of that.

SAFETY INTERLOCK

Every broadcasting step refuses to run unless RAIDOLLAR_CONFIRM=LAUNCH is in the environment — it prints the exact command it wanted and exits. ./launch.sh dry prints the entire runbook and broadcasts nothing; status shows what has completed. Dry is the default, firing is the exception.

MARKET OPENS LAST

There is no "open market" button — it is structural, not a step. The deploy lands inside a 14-day bootstrap: redemptions revert, the controller is frozen at its biases, per-branch bootstrap debt ceilings hold. The market opens on a timer, at bootstrapEnd = deploy + 14 days, with no admin key involved.

GAS BUDGET

Genesis is ≈ 315,833,529 gas across 319 transactions on mainnet — the measured anvil rehearsal excluding mocks, not an estimate. Fund the deployer with ≥ 8 ETH through ≥ 2 aged, non-identity-linked hop wallets.

raidollar — ./launch.sh mainnet · 8 branches · zero admin
01

Predict the canonical pool address — and pin it

$ ./launch.sh predict_pool # read-only. RUN THIS FIRST — its output is what you pin.
does
Computes factory.getDeploymentAddress(ctorArgs, salt) from POOL_CREATOR — the CREATE2 address of the canonical RD-USDC-USDT-USDS Balancer-v3 pool, knowable before the oracle exists because a v3 pool's address does not depend on its hook. Cross-checks it, and you paste it into MainnetConfig.CANONICAL_POOL_ADDRESS. This is the front-run gate (OPS-B1).
verify
The address reproduces deterministically from the pool-creator account; re-run forge test after pinning — must stay 935 / 0.
abort
Cannot reproduce the address (salt scheme differs) → STOP. Never fall back to an unpinned deploy: DeployLib reverts with EXPECTED_POOL unset (OPS-B1 oracle front-run gate) anyway.
02

Pre-flight — every gate, zero gas

$ ./launch.sh preflight # no tx. Must be GREEN, twice, on the frozen commit.
does
Checks env, chainId, balances, build, every Class-A sentinel, LaunchTunables.requireSane() on Class B — then simulates the real phase-1 script without --broadcast, so any remaining gap surfaces as its exact revert string at zero cost.
verify
forge test → 935 passed / 0 failed · node spec/derive-params.mjs → 69 checks / 0 failures · SystemInvariants ci-deep 12/12 · MainnetConfig.requireLaunchReadyPhase1 does not revert · deployer ≥ 8 ETH, keeper ≥ 0.5 ETH, ops seeder ≥ 0.2 ETH.
abort
Any gate red → STOP. There is no post-deploy fix; pre-flight is the safety net, not a ceremony.
03

Phase 1 — deploy the full stack

RAIDOLLAR_CONFIRM=LAUNCH $ ./launch.sh deploy_phase1 # BROADCAST · ~316M gas · 319 txs
does
Deploys and wires every contract except the LPStaking↔BPT link, writes the manifest to script/out/deployment.json, and renounces every Ownable but LPStaking. Nonces serialized with --slow. Any unresolved external input has already reverted in pre-flight, by name.
verify
=== PHASE 1 COMPLETE === · marketOracle.EXPECTED_POOL() == the pin · aggregator.owner() == 0x0 · lpStaking.owner() == deployer · rdToken.addressesSet() == true · rateParControl.lastUpdateTime() == bootstrapEnd.
abort
Mid-broadcast halt → resume with forge script … --resume, never re-run from scratch (double-deploy). If --resume cannot reconcile, the run is dead: the half-deployed contracts are orphaned with no admin — fix the config and redeploy from a fresh nonce space.
◆ HARD GATE 1 of 2 — operator pool-create, between the phases

Create the canonical pool at exactly the predicted address

The pool — and therefore its BPT — cannot exist until after RD and the MarketOracle deploy, so a mainnet launch cannot be one atomic broadcast. This gate sits between the phases, and it is the window in which an adversary could capture an immutable oracle. Do it in the same operator session, immediately after phase 1. The script will never create the pool for you — it prints the exact instructions and then verifies what you did.

$ ./launch.sh predict_pool # again — confirm the LIVE oracle's pin == what you are about to create $ ./launch.sh create_pool # GUIDED MANUAL GATE: canonical factory, MarketOracle as poolHooksContract, # the exact salt from step 01, same creator account, tokens [RD, USDC, USDT, USDS]
verify
marketOracle.pool() == EXPECTED_POOL — the vault-driven onRegister fired and bound the oracle permanently. Record the BPT: on Balancer v3 the pool contract is the BPT, and phase 2 asserts BPT_TOKEN == EXPECTED_POOL. Seed the pool per POOL_SEED_* so TWAL clears the liquidity floor.
abort
Oracle_UnexpectedPool → the pool did not land at the pinned address → STOP, recompute the salt, do not proceed.
rule
Never ramp the pool amplification parameter. The oracle caches amp at onRegister; a ramp desynchronizes the cache and corrupts the invariant-derived TWAP/TWAL. Set the final amp at creation. This is the single most dangerous external action against the live system, and it is on the watch list from minute one.
04

Phase 2 — wire LPStaking, verify the LIVE graph, renounce

RAIDOLLAR_CONFIRM=LAUNCH $ ./launch.sh deploy_phase2 # BROADCAST · FINAL RENOUNCE · immutable from here
does
Wires LPStaking.setAddresses(BPT, …), then runs DeployLib.verifyWiring against the live deployed system — every cross-branch reference, every branch parameter against the spec table, pool == EXPECTED_POOL, the LPStaking BPT — and only then renounces the last Ownable (OPS-I2). The BPT is checked equal to the live EXPECTED_POOL before it is wired one-shot.
verify
=== PHASE 2 COMPLETE === · lpStaking.owner() == 0x0 · lpStaking.bptToken() == BPT · marketOracle.getResultWithValidity()(≈1e18, true) after 60s of observations.
abort
verifyWiring reverts → the system is mis-wired and now unusable → fresh redeploy. This is precisely why the gate runs before the final renounce.
05

Verify the live system, independently

$ ./launch.sh verify # no tx
does
Re-reads the deployed system from outside the deploy transaction: code at every manifest address, owner() == 0 across the one-shot Ownables, genesis-parameter spot-checks, and the oracle pool binding.
verify
cast code non-empty on every manifest entry · weth.borrowerOperations.MCR() == 1100000000000000000 · keeperRewards.isPayer(marketOracle) == true · globalFeeRouter.aggregator() == aggregator.
abort
Any mismatch → the deploy is unusable and unfixable → fresh redeploy.
◆ HARD GATE 2 of 2 — zero-staker seeds, before the first fee distribution

Seed all three staking pools before the first 6h GlobalFeeRouter run

Fee distribution into a pool with zero stakers cannot move the index. The code was hardened so empty buckets carry forward instead of mint-then-strand — no funds are lost — but emission attribution for an unseeded window is economically muddy and the flywheel stays dormant. All of these are permissionless user actions; nothing on-chain forces them. They were proven end-to-end on the rehearsal broadcast. seed_fee is a separate step because the FEE it stakes has to accrue first.

RAIDOLLAR_CONFIRM=LAUNCH $ ./launch.sh seed # FLX stake · first SP deposit (opens a small trove for RD) · LPStaking BPT seed RAIDOLLAR_CONFIRM=LAUNCH $ ./launch.sh seed_fee # once SpIssuance FEE has accrued: claim it, stake it into FEEStaking
verify
flxStaking.totalFLXStaked() > 0 · lpStaking.totalBPTStaked() > 0 · feeStaking.totalWeightedStake() > 0 — all three before DISTRIBUTION_FREQ = 6h elapses.
abort
Do not walk away between the deploy and these seeds: an unseeded launch also leaves the Gate-1 pool-binding window open. "Fire and forget" is the one operating mode this design cannot tolerate — which is why the sequence is paced, gated, and operator-driven end to end.
06

Bootstrap watch — the market opens itself

$ ./launch.sh bootstrap_watch # no tx. Prints bootstrapEnd + exactly what auto-enables.
does
Nothing on chain. At bootstrapEnd redemptions enable by the clock and the controller begins stepping as soon as a keeper feeds it a valid oracle. The operator's job in the 14-day window is watching: amp-ramp alert, per-branch isShutdown(), the quorum shutdown clock, keeper budget trend, redemption-quota convergence.
verify
Post-bootstrap a redemption executes and primes baseRate — exercised end-to-end on the rehearsal at deploy + 15 days.
abort
No admin exists, so there is no pause, no upgrade, no clawback. The only stops are rule-triggered and permissionless: branch shutdown on TCR < SCR or oracle failure, controller shutdown on a 7-day unrecovered quorum failure, liquidation below MCR.
07

Keeper cadence

$ ./launch.sh keepers # permissionless; the keeper earns RD from KeeperRewards
does
Aggregator.drip() every 3h (full ramp 8h) · MarketOracle.checkpoint() every 1h (cap 3h) · RateParControl.update() every 3h (cap 8h) · Aggregator.updateDebtEmas() opportunistically. Fund the keeper before user funds arrive: the reward budget starts empty and only fills reflexively from fee flow.
verify
Keeper transactions land and the reward budget starts filling; getResultWithValidity() stays true — a checkpoint gap past the 6h staleness window silently freezes peg control.
abort
Not an abort condition — absence degrades rather than bricks. Lazy getters hold at their last values, so no keeper means interest stops accruing and the controller stops stepping; the hot path never bricks.
The explicit ask

The placeholder register.

Everything a mainnet run still needs, in two classes, with nothing hidden between them. Class A cannot silently deploy wrong — every unknown address is an address(0) sentinel and the deploy fail-closes with a revert naming the item. Class B is every uncertain number, each with a labelled default, a written rationale, and exactly one file to change. Full register: LAUNCH-PLACEHOLDERS.md.

Class A — external addresses, fail-closed

13 rows · 9 external-input IDs · blocks deploy until set

These are things that do not exist until someone creates them: feeds, pools, wallets. A guessed address is indistinguishable from a correct one at deploy time and would mis-bind an immutable system — so it is designed out rather than warned about. MainnetConfig.requireLaunchReadyPhase1 runs before any broadcast, and ./launch.sh preflight executes the real mainnet script without --broadcast, so you read the exact revert string with zero gas spent. There is no plausible-but-fake address anywhere in the config.

#ValuePlaceholder todayWhat breaks if it is wrongGate
A-1EXT-1Chronicle ETH/USD Scribe feedMainnetConfig.sol : CHRONICLE_ETH_USDaddress(0)Primary leg of the WETH, wstETH, rETH and weETH branches. A wrong-but-live feed prices half the collateral book off the wrong asset.blocks deploy
A-2EXT-1Chainlink ETH/USD fallbackMainnetConfig.sol : CL_ETH_USDalready setVerify it is still the live proxy and re-read its heartbeat on launch day. Losing the fallback leg means a Chronicle outage shuts four branches.pre-flighted
A-3EXT-2Chronicle BTC/USD Scribe, unit-scaledMainnetConfig.sol : CHRONICLE_BTC_USDaddress(0)Must serve USD per raw 8-dec unit (per-BTC USD × 1e10). Wiring a whole-token feed here mis-prices BTC collateral by 1e10. Tied to B-3.blocks deploy
A-4EXT-3Chronicle USDS/USDMainnetConfig.sol : CHRONICLE_USDS_USDaddress(0)sUSDS branch base pair.blocks deploy
A-5EXT-3Chainlink USDS/USD fallbackMainnetConfig.sol : build() → cfg.usdsUsdaddress(0)A gap we closed. This used to fail mid-broadcast, inside branch 6 of 8, after most of a 316M-gas deploy — orphaning everything already on chain. Now pre-flighted by name.blocks deploy
A-6EXT-4Chronicle sUSDS/USD market feedMainnetConfig.sol : CHRONICLE_SUSDS_USDaddress(0)sUSDS market leg.blocks deploy
A-7EXT-5sUSDS SSR rate providerMainnetConfig.sol : SUSDS_SSR_RATE_PROVIDERaddress(0)Must expose getConversionRate() in RAY (27 dec). A provider with different decimals mis-scales the branch by 1e9.blocks deploy
A-8EXT-6Canonical Balancer-v3 StablePool factoryMainnetConfig.sol : CANONICAL_POOL_FACTORYaddress(0)The ACCESS-01 allow-list. The MarketOracle constructor has never been able to deploy blank; a wrong factory means the canonical pool can never register.blocks deploy
A-9EXT-6 · OPS-B1Canonical pool CREATE2-predicted addressMainnetConfig.sol : CANONICAL_POOL_ADDRESSaddress(0)The front-run gate. Unpinned, an attacker mints a genuine pool from the real factory and registers it first, permanently mis-binding the immutable oracle. Filled from ./launch.sh predict_pool before phase 1.blocks deploy
A-10EXT-6Canonical pool BPT (phase-2 leg)BPT_TOKEN env · CANONICAL_POOL_BPTderived at launchA gap we closed. Phase 2 used to accept any non-zero address and wire it one-shot immediately before the final renounce. Now asserted equal to the live EXPECTED_POOL — on Balancer v3 the pool contract is the BPT.asserted
A-11EXT-8TeamVesting beneficiaries + amountsMainnetConfig.sol : teamBeneficiaries · teamAmountsempty arrays35% of total FEE supply, immutable at construction — no revoke, no reassignment, no claw-back, ever. The sum must be exactly 35,000,000 FEE; now asserted pre-broadcast as well as in the constructor.blocks deploy
A-12EXT-9FLX genesis distributionMainnetConfig.sol : flxRecipients · flxAmountsempty arraysFLX is minted once, in the FLXToken constructor. The ops seeder must be among these recipients or the day-0 FLXStaking seed cannot be performed.blocks deploy
A-13Collateral + stablecoin tokens, vault, Chainlink secondariesMainnetConfig.sol : WETH…PAXG · USDC/USDT/USDS · BALANCER_V3_VAULTalready setThe only Class-A values shipped pre-filled, because they are canonical and publicly verifiable. Pre-flight asserts each is non-zero — but it cannot tell you an address is the wrong token. Read them yourself at sign-off.verify at sign-off

Class B — economic numbers, one file

14 rows · 10 TEAM IDs · all in LaunchTunables.sol

Things that exist but whose right value is a judgement call. A number can be defended, and a wrong-but-reasonable number is corrected by market behaviour rather than being catastrophic — so each ships with a default, a label (PLACEHOLDER-DEFAULT = we chose it, DERIVED = traceable to the genesis sheet) and a rationale in the file itself. Every one lives in protocol/script/LaunchTunables.sol and nowhere else: the deploy compiles against it, launch.sh reads its values out of it, and this register cites it — change a number there and all three move together. LaunchTunables.requireSane() runs inside pre-flight and rejects inconsistent combinations.

#KnobDefaultRationale — and what breaks if it is wrong
B-1aTEAM-4LIQUIDITY_FLOOR100,000 RDBelow this depth the TWAL is a zero-utilization sample and controller authority is 0. Too high and the controller HOLDs at genesis and never steers; too low and it acts on a manipulable thin market.
B-1bTEAM-4LIQUIDITY_TARGET2,000,000 RDDepth at which authority q = 1; linear between floor and target, floored at 5% by the audit's CTRL-2 fix. Too high and the controller is permanently under-powered.
B-2TEAM-8Feed staleness windows4h / 48hPublished heartbeat plus slack. Too tight → spurious oracle-down shutdowns; too loose → the protocol trades on stale prices. Re-read every heartbeat on launch day — feeds get re-parameterised.
B-3EXT-7ACK_NON18_DEC_COLLATERALfalse — fail-closedWBTC and tBTC are 8-decimal and the branch layer books raw units, so their feeds must serve USD per raw unit. The one Class-B row that is a hard launch blocker — see the box below.
B-4TEAM-2SUSDS_HCR_USE_MIDPOINTfalse → HCR 130%The committed rule gives sUSDS HCR 130% > CCR 115% — the only branch where the ordering breaks. Our proposed HCR = (MCR+CCR)/2 = 110% reproduces the committed value byte-equal on the other 7 branches. Not unsafe, but it makes shielding on the one stablecoin branch need 25pp of headroom versus 20pp elsewhere. Flipping it also updates one expected-HCR formula in the deploy test.
B-5aTEAM-10POOL_SEED_RD500,000 RD5× the liquidity floor and 25% of the target → genesis authority q ≈ 21%, safely above the 5% floor and ramping to 1.0 as real LPs arrive. Below the floor, controller authority is zero at genesis; requireSane() rejects it.
B-5bTEAM-10POOL_SEED_USDC / USDT / USDS166,666 / 166,667 / 166,667Balanced 50/50 against the RD side so the pool opens at par. An unbalanced seed opens off $1 and hands the first arber the difference — resize both sides together.
B-6aTEAM-9SEED_FLX_STAKE1 FLXOnly non-zero-ness matters mechanically, so it is deliberately tiny. Zero FLX staked when the 2M FEE stream starts strands those early emissions forever.
B-6bTEAM-9SEED_TROVE_DEBT_RD2,500 RDAbove the 2,000 RD minimum net debt (2,200 composite, including 200 RD gas comp). Below it, openTrove reverts and the ops wallet never obtains genesis RD.
B-6cTEAM-9SEED_SP_DEPOSIT_RD1,000 RDThe first StabilityPool depositor — the only genesis source of liquid FEE, since all other FEE vests or streams. No SP depositor means the FEEStaking seed is impossible.
B-6dTEAM-9SEED_LP_BPT1 BPTNon-zero-ness only. Zero BPT staked at the first 6h distribution strands the LP bucket — mitigated by the audit's carry-forward guard, but not something to rely on.
B-6eTEAM-9SEED_FEE_STAKE_TIER0 — 7-day, 1.00×Shortest lockup; the seed's only job is to make totalWeightedStake > 0. A longer tier locks ops capital for 30–60 days for no benefit.
B-7aDEPLOYER_MIN_WEI8 ETHDERIVED: 315,833,529 gas measured on the anvil rehearsal × ~25 gwei. Under-funded, the deploy dies mid-broadcast; if --resume cannot recover it, everything already deployed is orphaned with no admin. Raise the gwei assumption on a busy day.
B-7bKEEPER_MIN_WEI / OPS_SEEDER_MIN_WEI0.5 / 0.2 ETHRunbook gate G-9. A stalled keeper does not brick the protocol (lazy getters hold), but interest stops accruing and the peg controller stops stepping.

Six further TEAM sign-off items are protocol/src constants rather than deploy-time tunables — MIN_NET_DEBT 2,000 RD (TEAM-1), the 5% drip reward fraction (TEAM-3), the SpIssuance split weight (TEAM-5), the TeamVesting schedule (TEAM-6), the MarketOracle quorum/staleness/checkpoint inferences (TEAM-7) and the feed deviation thresholds (TEAM-8). Each is listed in the register with its exact file and line, its default, and what changing it costs. They are confirm-only in practice; this launch package is script, config and docs only, with no protocol/src change.

B-3 in full — the 8-decimal question is a hard blocker, not a "launch six branches". Stated plainly, because it is the one thing that stops a fire today. WBTC and tBTC are 8-decimal; the branch layer books raw units and the published Chainlink BTC/USD feed prices a whole token, so wiring it directly mis-prices BTC collateral by 1e10. And there is no six-branch mode: DeployLib deploys all eight branches unconditionally and verifyWiring asserts the per-branch utilization targets sum to exactly 100%, so dropping WBTC (5%) and tBTC (20%) is not a config change — it is a genesis re-derivation of the target table plus a code change to the branch loop. The recommended path is one small contract, deployed twice: thin unit-scaled adapters that read the canonical BTC/USD feed and return price × 1e10, set as A-3 and the Chainlink BTC leg, then flip the flag. The alternative — an 18-decimal wrapper per BTC collateral — is more surface and re-opens the callback-token constraint that audit finding ACCESS-03 was accepted against. Do not flip the flag without shipping the adapters: it is a one-word change that would silently mis-price two branches by ten orders of magnitude, which is exactly why a boolean is fail-closed here.
Live proof

Deployed to Sepolia — the whole system, zero admin.

Not a demo contract: the entire protocol, all eight branches and every singleton, deployed through the real two-phase choreography and then driven through a genesis-seed → bootstrap → interest-drip → redemption lifecycle on chain. The deploy wallet was funded through anti-clustering hop routing.

DEPLOYED

161 / 161 contracts

Every address in the manifest carries code — asserted in-transaction at deploy, then re-verified independently with cast code.

IMMUTABLE

owner = 0x0

All 132 one-shot Ownables renounced — 131 in phase 1, LPStaking in phase 2 once its BPT was bound and the live graph verified. RDToken registry locked.

EXERCISED

seed → drip → redeem

319 transactions, the runbook's own seed steps, six time ticks past the 14-day bootstrap, then a real redemption that closed a trove and primed baseRate.

Deployment manifest is being written on-chain — addresses populate here once the broadcast confirms.

Network: Sepolia (chainId 11155111) · deployer 0x37542B49336514B16668535791297a0EE591cA74 (hop-funded, un-clustered). Full manifest: protocol/script/out/deployment.json. Contracts are deliberately left unverified on Etherscan — a verified testnet deploy fingerprints the mainnet build.

What the testnet run does and does not prove — plainly. Balancer v3 and Chronicle Scribe feeds do not exist on Sepolia, so the run uses a mock external stack: mock vault, mock pool and factory, mock price feeds. What Sepolia validates is everything that is ours — the deploy path, the full wiring graph, CREATE sizes, nonce sequencing, the gas profile, the renounce asserts, the seed choreography and the redemption lifecycle, all as real signed transactions. What it does not validate is the external addresses; those are exactly the Class-A inputs above, and on mainnet MainnetConfig wires the real ones and reverts if any is unset. We would rather state that than let a green testnet badge imply more than it earned.
The build

A protocol, not a prototype.

RAI Dollar is Liquity's trove model fused with Reflexer-style control theory: an autonomous PI controller steers an interest rate and an internal par price to hold $1, a redemption "shield" market lets borrowers buy redemption immunity, and eight isolated collateral branches (WETH, wstETH, WBTC, rETH, weETH, tBTC, sUSDS, PAXG) coordinate through a cross-branch aggregator. Nothing here is a mock of the idea — every mechanism is implemented, wired, and exercised.

CONTROL

Split-range PI + baton

A single controller drives both rate and par with a baton state machine, bumpless handoff, anti-windup and slew limits — ported constant-for-constant and differential-fuzzed against the reference.

SHIELD MARKET

Priced redemption immunity

A per-branch shield curve that spreads surcharge and discount around an 85% inflection, reaching a −50% APY borrow-rate floor (a protocol bound, not a yield) — every value pinned to on-chain test vectors.

ORACLE

Balancer-v3 hook TWAP/TWAL

Synthetic RD price from the StableSwap invariant, a finalized-observation ring buffer, three health gates, and a quorum-driven shutdown clock.

CROSS-BRANCH

Aggregator + fee routing

Redemption routing with a rate-limit quota, autonomous bad-debt repair via a credit ledger, per-branch utilization offsets, and a two-stage PI fee pipeline.

TOKEN LAYER

FEE emissions & staking

A 100M fixed FEE token, a 48-month ramp-and-terminate emission curve as packed checkpoints, tiered staking, vesting, and issuance — all exact to the published schedule.

IMMUTABLE

No admin, forever

Every Ownable renounces inside deployment. There is no upgrade path, no pause, no privileged key — verified by the access audit and re-verified on the live Sepolia system.

Start to end

The whole pipeline, one pass.

From a blank repo to a live, audited, deployed system — every stage gated, every artifact committed and reproducible.

1

Reconstruct the spec

Diffed their public October snapshot against its Liquity ancestor to isolate every RAI-specific change, then reconciled it with the current docs. Result: a full implementation spec with a 15-item divergence log.

DIFF-REPORTSPEC.md
2

Recover the hidden math

Their docs' interactive simulators turned out to be hand-written ports of the private contracts. Extracted the exact shield curve, baton controller, aggregator gains and emission table — verbatim, with test vectors.

SHIELD-CURVEEMISSIONS-CURVE
3

Build the contract set

Branch layer (14 contracts × 8 branches), 15 singletons, 8 price feeds — Solidity 0.8.24, one foundry repo, each bundle landing with its own unit and fuzz tests.

14 branch × 815 singletons8 feeds
4

Prove the money math

935 unit/fuzz tests plus a whole-system stateful invariant suite driving the real deployed system through 2.46 million randomized calls with zero reverts — supply identity, collateral conservation, controller bounds, no-stranded-RD partition.

12 invariantsci-deep 1024×200
5

Derive every constant

A genesis-parameter sheet: 110 constants, each re-derived from its generative formula and checked byte-equal (69 checks, 0 failures). No committed constant failed a correct derivation. Every constant carries a confidence class — 55 docs-exact, 19 recovered from the simulators, 14 inherited, 9 derived, 13 flagged as inferences needing your confirmation — and the 19 open inputs became the register above.

GENESIS-PARAMSLAUNCH-PLACEHOLDERS
6

Audit, three lenses + an ops gate

Independent adversarial reviews for money-conservation, control/oracle/economics, and access/immutability — plus a separate ops-readiness review that graded the launch layer and returned three blockers. Every finding fixed with a named regression test or accepted with written rationale.

money · control · accessops review
7

Rehearse, deploy, stage the launch

The two-phase choreography rehearsed as a real broadcast on a local node (319 txs, 327,904,989 gas, seeds and redemption included), then fired on Sepolia — and packaged as the runbook and launch sequence on this page.

REHEARSALLAUNCH-RUNBOOKlive on Sepolia
The differentiator

We recovered the private contracts' exact math.

The interactive simulators on the RAI Dollar docs site are labelled ports of the real contracts. That let us reconstruct the pieces a spec never spells out — not approximated, but exact, and turned into pinned test vectors that our implementation must reproduce to the wei.

InterestEngine._calcRates — shield curve, recovered
// priced shield share s, per-second branch delta d = collRate − RAY if (s <= S1) { // S1 = 0.85 inflection z = s / S1; v = d * z; // unshielded discount u = ALPHA * d * z; // shielded surcharge } else { z = (s − S1) / (1 − S1); vf = max(V_MAX, d); // V_MAX ≡ −50% APY floor v = d + vf * z; u = ramp(ALPHA*d → uGuard, z); } // at s = 1 : unshielded rate = −V_MAX, exactly. verified byte-equal.
shield curve → 10 RAY vectors baton controller → 6,240-step differential fuzz aggregator gains → recovered 48-month emission table → byte-exact
Adversarial review

Three audits — and seven bugs in the source lineage.

The money-conservation lens came back clean: zero critical, zero high. Across four reviews — three independent code lenses plus a separate launch-layer ops review — 19 findings: 13 fixed, 6 accepted with written rationale, 0 open, including one Critical and one High caught before they could ship. And porting their October snapshot surfaced real defects in the ancestor code — the kind that, if they still live in the private repo, matter today.

MONEY-CONSERVATION

0 critical · 0 high

12 high-risk value paths verified sound: the mint-equals-debt-delta identity, the bad-debt credit ledger, liquidation round-up safety.

CONTROL / ORACLE

1 high, fixed

A quorum shutdown-clock griefing vector that could force a terminal shutdown — reworked to a cumulative unrecovered-failed-time clock.

ACCESS / IMMUTABILITY

1 critical, fixed

An oracle-registration front-run — closed by pinning the canonical pool to its CREATE2-predicted address. Immutability otherwise verified everywhere.

Defects found while porting the ancestor code

FindingImpactStatus
Oracle synthetic-price inversionRD scarcity read as below-$1 — controller steers the wrong waypeg-breaking fixed
64× amplification-coefficient errorStableSwap derivative mispriced skewed poolspeg-breaking fixed
Reward-application debt inflationpending debt added in the wrong units, inflating actual debthigh fixed
Missing auth on snapshot resetanyone could zero reward snapshots and re-minthigh fixed
Shield-toggle stranded collateraltoggling shield moved debt but not the backing collateralhigh fixed
Stability-pool gain lock (F-J1)rounding dust could brick the last depositor's withdrawalhigh fixed
Chainlink future-timestamp bricka future round timestamp would revert the price fetchmed fixed

Every fix ships with a regression test named for its finding. Full reports: three lens audits, an ops-readiness review, and a consolidated register carrying the disposition of every finding. An external audit remains a launch gate (runbook G-2) — the reviews above are our own adversarial passes, and we do not present them as a substitute.

What you get

Everything, documented and reproducible.

The code

14 branch contracts × 8 branches, 15 singletons, 8 price feeds — Solidity 0.8.24, one foundry repo. 935 tests + a stateful invariant suite. Two-phase deploy scripts with a live wiring gate.

The reconstruction

Implementation spec, divergence log, and the recovered shield-curve / emission-curve / controller derivations with the extracted reference sources.

The genesis sheet

110 constants derived and byte-checked, per-branch parameters, and the 19 external inputs isolated as the placeholder register above.

The audit trail

Three independent lens reports, an ops-readiness review, a consolidated findings register, a frozen audit scope, and every fix as a named regression test.

The launch package

launch.sh — ten idempotent steps with a confirm interlock, a dry mode and resume; the two-phase runbook with hard gates, key/role matrix, keeper cadences and an incident-lever map for a no-admin system; and LAUNCH-PLACEHOLDERS.md, the operator's sign-off sheet.

The rehearsal

A full deploy choreography rehearsed as a real broadcast, with per-phase gas, a lifecycle smoke sequence, and the two broadcast-only issues it caught written up in full.

The case

Why this submission.

  • A complete protocol, not a prototype. Every mechanism — control, shield market, oracle, aggregator, token layer — implemented, wired, and exercised across 8 collateral branches.
  • The exact math, recovered from your own published sources. The shield curve, baton controller, aggregator gains and 48-month emission table reconstructed byte-equal from the docs' simulators and pinned as test vectors.
  • 935 tests and a 2.46M-call invariant suite. 12 whole-system invariants driving the real deployed system, ci-deep green, zero failures.
  • A three-lens audit plus an ops review, with the money lens clean. Zero critical and zero high on money-conservation; 1 Critical and 1 High found and fixed elsewhere, each with a named regression test; 19 findings closed — 13 fixed, 6 explicitly accepted with rationale rather than quietly dropped, none open.
  • Seven defects found in your own ancestor code. Including two peg-breaking oracle bugs — value delivered before a single line of ours shipped.
  • Deployed and rehearsed, not just compiled. 161 contracts live on Sepolia with every admin key renounced, plus a full broadcast rehearsal through seeds, bootstrap and a real redemption.
  • A launch package staged with fail-closed placeholders. Thirteen external-address rows that make the deploy revert rather than deploy wrong, fourteen labelled numeric defaults in a single file, and an executable ten-step fire sequence with two hard gates and written abort paths.

The remaining work is not engineering. It is a set of addresses, a set of confirmations, and two thin BTC adapters — and then the sequence above runs.