Trust boundaries
| Edge | Trusted | Validated at the edge |
|---|---|---|
| Caller → controller | Nothing about the caller’s intent. | require_auth on the acting address; pause state; account ownership where required; all risk invariants. |
| Governance → controller | Governance is the controller owner in production. | Timelock delay before admin mutations execute; proposal-time input validation on governance. |
| Controller → pool | The pool is the protocol’s own contract, owner-set to the controller. | Every mutating pool method is #[only_owner]. The pool re-checks reserves, caps, and utilization itself. |
| Controller → oracle | Reflector and RedStone as price sources. | Every response: staleness, future skew, deviation bands, dual-source agreement, and sanity bounds, under a per-flow policy. Fail-closed. |
| Controller → aggregator | The aggregator address (governance-set) to execute a swap. | The swap payload is opaque Bytes, forwarded verbatim. The controller enforces amount > 0, non-empty bytes, input not overspent, and positive output delta. |
| Controller → Blend pool | Governance-approved Blend pool addresses only. | is_blend_pool_approved check; balance-delta reconciliation on debt repay refunds. |
| Pool → token | Listed SAC / SEP-41 tokens behave as standard transfer assets. | Input-side flows credit measured balance; output-side flows rely on standard transfer semantics. |
| Pool → flash receiver | The receiver runs arbitrary callback logic. | The pool snapshots its balance before the callback and requires repayment of amount + fee; reentry is blocked by the shared guard. |
Authorization
The controller is paused by default after construction. User and strategy entrypoints carry#[when_not_paused].
Governance boundary
| Class | Auth | Examples |
|---|---|---|
| Emergency | Governance owner | pause, unpause (immediate). |
| Bootstrap | Governance owner | deploy_controller (one-time, immediate). |
| Scheduling | PROPOSER | All propose_* entrypoints. |
| Execution | EXECUTOR (optional) | execute on ready operations. |
| Cancellation | CANCELLER | cancel on pending operations. |
Controller boundary
| Class | Auth | Examples |
|---|---|---|
| User actions | caller | supply, borrow, withdraw, liquidate. |
| Strategy actions | caller / account owner | multiply, swap_debt, swap_collateral, repay_debt_with_collateral, migrate_from_blend, flash_loan. |
| Maintenance | caller (no role) | update_indexes, update_account_threshold, clean_bad_debt, claim_revenue, add_rewards. |
| Oracle emergency | ORACLE role | disable_token_oracle. |
| Owner config | Owner (= governance) | Pool deploy/upgrade, market creation, spoke risk config, governance scheduling, and global addresses. Reached via governance timelock in production. |
repay does not require the account owner (anyone may repay any account; overpayment is refunded), and liquidate is open to any liquidator on an eligible account (self-liquidation is rejected, #13).
Ownership transfer is two-step on both contracts: transfer_ownership(new_owner, live_until_ledger) then accept_ownership(). Controller accept_ownership syncs the access-control admin and ORACLE role grants.
Reentry guard
A shared single-flight guard,FlashLoanOngoing, blocks reentry during external code execution:
- Flash-loan callbacks.
- Strategy swaps through the aggregator.
- Blend
submitcalls during migration.
#400 FlashLoanOngoing.
Oracle risk
The oracle path is fail-closed: a provider trap reverts the whole transaction. Risk-increasing flows and liquidation run under strict policies that reject staleness, unsafe deviation, and degraded dual-source agreement. Risk-decreasing flows and views run under permissive policies. See Oracles for the five policies and tolerance math.Token assumptions
Listed tokens must be standard SAC / SEP-41 contracts with fixed-balance, 1:1 transfer semantics. Do not list fee-on-transfer, rebasing, or hook-bearing tokens without a coordinated migration.Pool trust
The pool is deliberately narrow:- It performs no account-level solvency decisions.
- Its mutating methods are owner-only.
- It never calls another pool.
- It emits no events.
reserves(asset) returns protocol-tracked cash, not live token balance. Live balance is used only for flash-loan settlement checks.
Upgrade model
Controller and pool upgrades are governance-timelocked in production. The controller’supgrade auto-pauses first. Pool rate-model updates accrue at the old rate before applying new parameters. There is no generic storage-migration framework; layout-changing upgrades require a coordinated migration.
Recommended procedure: governance pause → schedule upgrade → execute after delay → re-run required configuration → smoke-test views → unpause.
Strategy router and accumulator risk
The aggregator is governance-set and external. Slippage (total_min_out) is enforced inside the aggregator, not the controller. The accumulator is address-only trust: claimed revenue forwards to it, so verify the address before enabling claims.
Operational monitoring
Watch for assets missingAssetOracle(asset) config; oracle staleness and deviation errors; protocol_revenue rising while claim_revenue returns zero; pool reserves below withdrawal demand; supply or borrow caps near saturation; account and shared-state TTL approaching archival; token-issuer upgrades; aggregator contract changes; and timelock operations approaching expiry.
Audit status
The protocol is verified in-repo with Certora formal specifications and is pre-audit. Mainnet launch is gated by ADR 0009 and the acceptance matrix in the architecture reference.Next
Governance
Timelock roles and emergency controls.
Deployment
Build, deploy, and bring-up sequence.
Configuration
Validation rules for risk, oracle, and spoke parameters.

