Smart contracts overview

Every Protocol Layer contract: purpose, key invariants, role gates.

Contract reference

Contract Purpose Key invariant
PLUSD ERC-20 dollar receipt totalSupply ≤ cumulative LP deposits + cumulative yield minted − cumulative LP burns. Reserve invariant checked on every mint. Transfers require both endpoints whitelisted or one to be a system address.
sPLUSD ERC-4626 yield-bearing share Share price moves only on YieldMinter mints landing in the vault. No emissions, no rebases.
LoanRegistry ERC-721 NFT loan book Origination data immutable. Lifecycle state mutable. Trustee writes lifecycle. setDefault and write-down closures gated by RISK_COUNCIL via AccessManager. Informational only — not a NAV source.
DepositManager Two-step screened deposit deposit parks USDC in the Intake Wallet and creates a ticket; claim verifies a Relayer EIP-712 ClaimAttestation, enrols the lender on the whitelist, moves USDC from Intake to Capital, and calls mintForDeposit 1:1. Holds the only DEPOSITOR role on PLUSD and WHITELIST_ADMIN on WhitelistRegistry (used inside claim).
YieldMinter Two-party yield mint gate Mint requires verified signatures from both the Trustee attestor (EIP-1271) and the Relayer attestor. Mint destinations hard-constrained to sPLUSD vault or Treasury Wallet.
WithdrawalQueue User-pulled FIFO exit claimAmount ≤ totalClaimable enforced on every claim. The queue contract pulls from the Withdrawal Queue Wallet via the wallet’s standing allowance when a lender calls claim. Allowance is the permission ceiling; aggregate ledger is the spending discipline. Can carry an exchange coefficient < 1.0 during recovery.
WhitelistRegistry Compliance-screened allowlist Both endpoints of every PLUSD transfer must be whitelisted or a system address. 90-day KYT freshness window enforced via approvedAt per entry.
AccessManager OpenZeppelin v5 role hub Every privileged call routed through. Per-role timelocks: ADMIN 3-day standard / 7-day for upgrades, RISK_COUNCIL 3-day, GUARDIAN 0. 14-day meta-timelock on the delay parameter itself.
ShutdownController Dormant in MVP. Reserved primitive for post-MVP terminal-mode scenarios. MVP loss handling uses the WithdrawalQueue exchange coefficient.  
RecoveryPool Dormant in MVP. Reserved primitive for post-MVP recovery flows alongside Pipeline Recovery Tokens (PRT).  

Privileged role catalogue

Role Holder Capability
DEPOSITOR DepositManager proxy address Calls PLUSD.mintForDeposit. Contract-held; no human key.
YIELD_MINTER YieldMinter proxy address Calls PLUSD.mintForYield. Contract-held; gated by the two-party signature check inside YieldMinter.
BURNER WithdrawalQueue proxy address Calls PLUSD.burn inside WithdrawalQueue.claim. Contract-held.
WHITELIST_ADMIN DepositManager proxy address Calls WhitelistRegistry.setAccess inside DepositManager.claim (auto-enrolment on a clean KYT).
WHITELIST_REVOKER Relayer EOA Calls WhitelistRegistry.revokeAccess for fast sanctions response. Narrow defensive on-chain role. GUARDIAN can revoke instantly.
TRUSTEE Trustee key (or EIP-1271 signer) Authorises LoanRegistry lifecycle writes (recordRepayment, closeLoan for non-default reasons, etc). GUARDIAN can revoke instantly.
PAUSER GUARDIAN MPC Pauses any pausable contract.
UPGRADER ADMIN MPC Schedules UUPS upgrades through AccessManager under the 7-day delay.

setDefault, write-down closures, and exchange-coefficient changes on the WithdrawalQueue are RISK_COUNCIL-gated function selectors via AccessManager — not separate role grants. kytAttestor and relayerYieldAttestor are signing-key addresses configured on the relevant contracts via setters under the 3-day ADMIN timelock (48-hour timelock for attestor rotation under proposeYieldAttestors); they are not role grants.