u64 account holds supply and borrow positions keyed by HubAssetKey. Every
account is bound to one spoke at creation, and that binding never changes. The
spoke decides which assets the account may use and on what terms.
Every later call rechecks the binding, so passing a different spoke_id reverts
with #310 SpokeMismatch.
Read first: Markets.
Storage
Account state is split across three controller records:
Existing-account operations require the owner or an active delegate, except for
intentionally open flows:
repay, liquidate, clean_bad_debt, recapitalize,
and the maintenance verbs are permissionless. supply sits in between — a third
party may supply, but only into hub assets the account already holds a supply
position in, so it cannot consume the account’s supply-position slots.
Positions
Supply and debt positions store scaled RAY balances. The live token amount is reconstructed from the current pool index:Spoke risk
The account’s spoke providesSpokeAsset(spoke_id, HubAssetKey) configuration:
- collateral and borrow flags;
- LTV;
- liquidation threshold;
- liquidation bonus and protocol fee;
- spoke-level supply and borrow caps.
-
the three halt flags:
paused(blocks every verb),frozen(blocks entry, allows exit), andno_seize(blocks only liquidation seizure).
PriceKey::Token(asset). Spokes do not override prices. See
Oracles.
There is no account category boost mode in the current protocol.
Delegates
An owner may grant delegate authority for borrow, withdraw, and strategy calls.add_delegaterequires the delegate to be an active, governance-approved position manager at the moment of the grant. A dormant grant to an unapproved address would arm on later activation, so it is rejected outright.- Delegates are capped at
MAX_DELEGATES = 16(#45 RegistryCapReached). - A grant is bound to the owner who made it (
DelegateGrant.granted_by). Transferring the NFT deactivates the previous owner’s grants immediately; the stale entry is purged on the new owner’s next delegate write. No explicit cleanup call exists or is needed. remove_delegateis deliberately not pause-gated — revoking authority must never be blocked.
Position limits
An account can hold a bounded number of supply and borrow positions, at mostPOSITION_LIMIT_MAX = 5 each. Governance updates those limits through timelock.
Exceeding either side reverts #109 PositionLimitExceeded.
Risk gates
Every valuation-dependent mutation consumes a complete price snapshot. A
source failure, staleness, disagreement, or failed sanity rule reverts the whole
operation — the protocol halts risk-taking rather than acting on a questionable
price. There is no permissive per-flow policy.
Collateral and debt are valued conservatively in opposite directions: the gated
sums that back the risk checks floor collateral at every step and ceil debt, so
neither can be overstated in the account’s favour.
Risk-parameter refresh
Supply positions carry the risk parameters stamped onto them at supply time. Two paths restamp them:update_account_threshold(caller, has_risks, account_ids)— permissionless, pause-gated. Withhas_risks = trueit also reloads the debt side and reverts#102 HealthFactorTooLowif the account’s health factor falls below1.05WAD, so a keeper cannot use a threshold tightening to push accounts into liquidation. Accounts with no stored metadata or no supply positions are skipped rather than reverting. It emits a position batch with legs taggedParamUpd; no funds move.- Every strategy call, through
strategy_finalize, restamps listed collateral before applying the post-pool risk gates.
Position modes
PositionMode gates strategy entrypoints:
Next
Risk parameters
Units, ranges, and configured values for market and spoke risk parameters.
Health factor
Health-factor formula and WAD examples.
Liquidations
Liquidation rules after health factor drops below one.
Strategies
Strategy modes and route-driven account flows.

