# USDR — Audit Preparation Notes **Scope:** 9 contracts in `src/` implementing White Paper v3.2. ~1,400 LoC of Solidity. **Compiler:** 0.8.24, optimizer 200 runs. OpenZeppelin v5 (SafeERC20, ReentrancyGuard, ERC20Permit). ## Trust model - **No owner on the token.** Minter set (PSM, CDPVault, LiquidationEngine-burn) finalized at deployment, irreversibly. `USDR.sol` has no other privileged function. - **Immutable core:** `SolvencyGuard` enforcement, `ReserveManager` escrow-first accounting, `SettlementEscrow` access control — none are governable after `finalize()`. - **Timelock (48h) powers:** oracle configs, collateral ratios/ceilings, liquidation params, buffer target, capped RAIN backstop, emergency settlement trigger. - **Guardian powers:** bounded pause (≤14 days) of PSM only. Cannot mint, move funds, or change the invariant. ## Whitepaper → code map | WP requirement | Contract / mechanism | |---|---| | §4.3 `Stress-MaxLoss ≤ Reserve` every block | `SolvencyGuard.reportExposure` reverts on breaching increase | | §4.1 netted, group-level MaxLoss | adapters report net figures; groups summed (conservative) | | §4.2 Settlement Escrow = Stress-MaxLoss(t) | `ReserveManager.rebalanceEscrow` (permissionless keeper op) | | §4.4 traders guaranteed / others best-effort | `SettlementEscrow.paySettlement` (adapters only) vs `redeemFromSlack` (PSM only, reverts beyond slack) | | §4.6 shortfall priced over breaker window | `LiquidationEngine.kick/take` → `reportCdpShortfall` | | §5.4 liquidity-derived ceilings + hysteresis | `CDPVault` per-asset + correlated-group ceilings; lowering blocks new mints only | | §6 no-reflexivity | CDPVault has zero stable-token code paths; grep `usdt|usdc` in CDPVault → none | | §7 waterfall 1–5 | overcollateralization → Dutch auctions → SurplusBuffer → capped backstop → EmergencySettlement | | §9 breaker partial/staggered, never frozen | per-window rate limit in `take()`; borrows pause, liquidations continue | | §10 no admin-mint | `USDR.finalizeMinters`; ceilings enforced in `borrow` | | §12 params | set via timelock in deployment runbook | ## Known open items (before mainnet) 1. ~~Uniswap v3 TWAP reader~~ **DONE**: `oracle/UniV3TwapReader.sol` — ≥30 min window enforced, pool-liquidity floor, canonical TickMath; fork-verified vs live ARB/USDC pool (Arbitrum One). 2. ~~Market adapter~~ **DONE (v1)**: `adapters/RainMarketAdapter.sol` computes net MaxLoss from live Rain pool views (rain-sdk-v2 ABI, verified on-chain: options 1-indexed, baseTokenDecimals returns the scale factor). Remaining: settlement wiring (paySettlement hook from resolution flow) + protocolShareBps policy per market. 3. **Escrow underfunding edge:** if the reserve cannot fully fund the escrow target, `rebalanceEscrow` tops up what it can; the guard blocks all new exposure in that state. Consider an explicit `escrowShortfall()` view + dashboard alert. 4. **USDT specifics:** SafeERC20 used throughout; USDT approval race handled by callers (approve 0 first in UI). Consider forceApprove where the protocol approves. 5. ~~Sequencer downtime~~ **DONE**: `OracleHub.checkSequencer()` — Chainlink uptime feed (0xFdB631F5EE196F0ed6FAa767959853A9F217697D) + recovery grace period; tested. 6. **Oracle decimals invariants:** MockAggregator covers 8-dec; fuzz other decimals. 7. **Economic review:** stress parameters (−50%, 35% depth) and rate-limit sizing need simulation against historical RAIN/ARB liquidity data. 8. **Emergency settlement funding path:** the governance action that moves pools into `EmergencySettlement` needs an explicit, tested migration script. ## Invariants for the auditors (formal targets) - I1: `totalStressExposure + cdpShortfallRisk ≤ reserveBalance()` after any adapter call that increases exposure (fuzz-tested: `testFuzz_invariantNeverBreached`). - I2: No call sequence transfers USDT/USDC out except `paySettlement` (adapters) and `redeemFromSlack ≤ slack` (PSM). - I3: `USDR.totalSupply` changes only via PSM (1:1 backed), CDPVault (over-collateralized, ceiling-capped), engine burn, and emergency claims. - I4: CDPVault never decreases a user's collateral except `withdraw` (health-checked), `seize` (engine), `close` (returns to owner). - I5: Lowering any ceiling never reverts operations on existing debt. ## Test status `forge test`: **28/28 passing** (+1 fork test), incl. 512-run fuzz of the invariant. Stress scenarios covered: S1, S2, S3, S4/S8 (correlated groups), S9 (one-sided book), S10. TODO: S4/S8 correlated-group scenarios, invariant-mode tests (`forge test --mt invariant`), long-horizon Dutch decay fuzz, Echidna/Medusa campaign, Slither/Aderyn static pass.