Architecture
RAI Dollar's contracts are organized in two layers: a per-branch layer that owns trove state and pools for a single collateral, and a singleton layer above that coordinates across branches. The diagram below mirrors the one in Aggregator.sol — hover any contract for its responsibility:
Per-branch contracts
A branch is everything needed to run one collateral type. Branches don't share state; they share singletons.
| Contract | Responsibility |
|---|---|
BorrowerOperations | User-facing API: open / adjust / close / shield-toggle. Enforces ICR/TCR/shield rules. |
TroveManager | Trove state machine: storage, ICR computation, liquidation orchestration entry-points. |
Liquidations | Branch-local liquidation logic, offset against SP, redistribute remainder, batch liquidate. |
Redemptions | Branch-local redemption walk over the base list and, during shutdown, the Redemption Shield cohort list. |
Rewards | Tracks pending redistribution rewards (debt and collateral) for active troves. |
StabilityPool | RD deposits that absorb liquidations. Tracks per-depositor collateral and FEE gains. |
InterestEngine | Drips branch debt interest. Maintains two per-second accumulators: accumulatedRate for the base book (branch_rate − v) and accumulatedShieldRate for the Redemption Shield cohort book (branch_rate + u), where the same shield-share curve produces the signed adjustment for each. |
ActivePool (base) | Custody of collateral backing troves without Redemption Shield. |
ActiveShieldedPool | Custody of collateral backing troves with Redemption Shield enabled. |
DefaultPool | Custody of redistributed collateral and debt (from liquidations that couldn't be fully offset). |
CollSurplusPool | Holds collateral surplus owed back to borrowers (post-full-redemption, force-close remainders). |
GasPool | Holds the per-trove 200 RD gas-compensation reserve. |
SortedTroves (base) | Doubly-linked list of troves without Redemption Shield, ordered by NICR. |
SortedTroves (Redemption Shield cohort) | Same, for troves with Redemption Shield enabled. |
PriceFeed | Branch-specific collateral USD price feed (Chronicle primary, Chainlink fallback; branch-specific composition for LSTs). |
FeeRouter | Routes fees from this branch: between the local Stability Pool and the singleton GlobalFeeRouter. |
MinTrove | Helper for opening a trove exactly at MIN_NET_DEBT + gas comp with ICR = MCR. |
Singleton contracts
| Contract | Responsibility |
|---|---|
Aggregator | Cross-branch control plane: redemption routing, drip orchestration, issuance quotas, per-branch debt EMAs, delta-rate offsets. |
RDToken | The RD stablecoin (ERC-20). Mint/burn restricted to the protocol's authorized branches and routers. |
FEEToken | The FEE governance/value-capture token. |
RateParControl | The PI controller that produces the system rate and par over time. |
MarketOracle | Balancer-hook TWAP/TWAL feed of RD/USD used by RateParControl. |
GlobalFeeRouter | Splits cross-branch fees between LP staking, FEE staking, keeper rewards, and bad-debt repayment. |
LPStaking | BPT staking; pays FEE (from LpIssuance) and RD (from direct inflows). |
FEEStaking | FEE staking with tiered lockups. |
FLXStaking | FLX staking; one-year linear FEE distribution. |
GlobalHintHelper | Off-chain-style hint computation across branches. |
KeeperRewards | Source of keeper rewards for drip/oracle/par operations. |
LpIssuance / SpIssuance | FEE emission curves for LP and SP rewards. |
Branch ↔ singleton relationships
- Mint/burn: only
BorrowerOperations,TroveManager,StabilityPool,Redemptions, andAggregatorare authorized to mint/burn RD. Authorization is role-based onRDToken. - Drip orchestration:
Aggregator.drip()iterates every non-shutdown branch and calls each branch'sTroveManager.drip(), which folds accrued interest intoaccumulatedRateviaInterestEngine. - Debt EMAs: every state-changing borrower op tells the
Aggregatorto refresh that branch's debt EMA. The Aggregator also keeps a per-branch base debt EMA for redemption basket weights. - Rate offsets: the
Aggregatoradds a per-branchdeltaRateOffseton top of the system rate fromRateParControl. The offset is driven by the branch's debt-utilization error. - Redemption: a single
Aggregator.redeemCollateralcall iterates all non-shutdown branches with non-zerounshieldedDebtEma, splits the requested RD across them by EMA weight, and calls each branch'sRedemptions. - Fees: each branch's
FeeRoutercollects fees, sends a (PI-controlled) fraction to the local SP, and forwards the rest toGlobalFeeRouter, which fans out to LP staking, FEE staking, keeper rewards, and bad-debt repayment.
Common message flows
Opening a trove (Redemption Shield disabled):
Redeeming RD (multi-branch):
Liquidating a trove:
Why this shape
- Branches are isolated. Adding a new collateral is a new branch deploy, not a global upgrade. Branches don't read each other's pools.
- The Aggregator is read-only with respect to branch internals. It calls into branches via well-typed interfaces; branches push debt-change notifications back via authorized calls. No shared storage.
- The controller is a singleton.
RateParControlproduces one system rate and one par for all branches. Per-branch adjustment happens via theAggregator's additive delta-rate offset, not by giving each branch its own PI loop. - Redemptions are multi-branch but per-branch internally. The Aggregator owns the basket-weight logic; each branch owns its own walk.
Where to read next
- Peg control: what
RateParControlactually does. - Interest model: what
InterestEnginedoes. - Redemption mechanism: full walk.
- Liquidation paths: offset/redistribute math.
- Fees,
FeeRouterandGlobalFeeRouter.