Skip to main content
A 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:
The account is an NFT. Each lending account is one token in the position-NFT collection: account_id is the token_id, and the NFT holder is the owner. The controller stores no owner address — it calls owner_of(account_id) on every authority check. Transferring the token therefore transfers the whole position, collateral and debt together, atomically, with no protocol-side handover step.See Position NFT for its callable surface and what a transfer carries over.
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:
Supply positions also store the collateral risk parameters used by LTV, health-factor, and liquidation math.

Spoke risk

The account’s spoke provides SpokeAsset(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), and no_seize (blocks only liquidation seizure).
Oracle configuration lives on the price aggregator, keyed by 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_delegate requires 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_delegate is 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 most POSITION_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. With has_risks = true it also reloads the debt side and reverts #102 HealthFactorTooLow if the account’s health factor falls below 1.05 WAD, 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 tagged ParamUpd; 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.