Skip to main content
Summary: One LiquidityPool contract holds all listed markets, keyed by HubAssetKey { hub_id, asset }. The controller is its sole owner. The pool tracks scaled supply/debt, indexes, cash, revenue, and flash-loan settlement, and emits three events.
LiquidityPool is a single contract that holds pooled liquidity and accounting for every listed market, keyed by HubAssetKey (PoolKey::Params(key) / PoolKey::State(key)). The same token on two hubs is two independent markets. The controller is the pool’s owner; every mutator is controller-only. Types are in Data types. Pool events are in Events.

Lifecycle

create_market registers one market: it validates params, writes PoolKey::Params(key) and a fresh PoolKey::State(key) (indexes at RAY, zeroed totals), and raises #2 AssetAlreadySupported if the market already exists. update_params accrues at the old rate before replacing the model.

Accounting verbs

All the position-moving verbs are batched — they take a vector of entries and return a vector of mutations, one per market touched.

Flash loan

A single call, no begin/end split. It snapshots the pool balance, transfers amount to receiver, invokes receiver.execute_flash_loan(initiator, asset, amount, fee, pool, data), then pulls back amount + fee and asserts the final balance equals pre_balance + fee. The receiver must be a deployed Wasm contract (#412); any repayment shortfall raises #402. The fee is recorded as protocol revenue and returned to the caller.

Views

No auth. All take a HubAssetKey.
get_reserves reports the market’s cash figure. Reserves are not a separate quantity from cash. It is persisted PoolStateRaw.cash, the liquidity source for borrows, withdrawals, and revenue claims — direct token donations to the pool address are excluded. Flash-loan settlement is the one place that reads the live token balance; see Security model.

Maintenance and revenue

update_indexes accrues interest to now. No tokens move. claim_revenue does four things in order: sync the indexes, burn enough revenue shares (ceil-rounded) to cover the payout, cap the payout at available cash, and transfer. It always pays its owner, the controller, which forwards the proceeds to the configured accumulator.

Events

The pool publishes three events, contrary to older versions of these docs: PoolMarketStateBatchEvent (["market", "batch_state_update"]), PoolMarketParamsBatchEvent (["market", "batch_params_update"]), and StrategyFeeEvent (["strategy", "fee"]). See Events for the wire shapes.

Defense-in-depth checks

Each mutating path validates locally so a controller bug cannot silently corrupt pool state:
  • Rejects non-positive amounts (#14).
  • Panics #30 PoolNotInitialized if the market’s Params / State keys are absent.
  • Checks cash before any outgoing transfer (#112) and enforces the liquidation-buffer and max-utilization guards (#127).
  • Rejects a positive movement that would change zero shares (#47, #49, #50, #51, #52).
  • Guards solvency: supplier claims may not exceed cash plus outstanding debt (#123 PoolInsolvent).
  • Validates the rate model on create_market and update_params.
  • Verifies flash-loan repayment with a pre/post balance check.
The pool does not infer risk from token balances. It keeps its own cash book and market share totals; inbound transfers are credited at the amount actually received.

Controller dependency

The controller depends on the pool ABI, not the pool implementation crate. Runtime coupling is on the ABI only, which keeps the controller – pool trust boundary explicit. See Security model.

Next

Controller ABI

The public entrypoints that call this interface.

Storage

The HubAssetKey-keyed PoolKey layout, durability, and TTL.