VaultAssertion is a standalone assertion runner. It observes Strategy Vault, protocol, and caller-supplied state and returns a structured report you can use to decide whether to build, send, or skip a transaction.
It is complementary to VaultTransactionBuilder — caller-controlled, and entirely outside the transaction pipeline.
VaultAssertion does not build, mutate, or send transactions. It does not run a monitoring loop. It does not replace Squads policies or onchain validation hooks. It also does not require any transaction-builder input — you decide what to do with the report.Quick Start
The two most actionable conditions for most strategy flows areClmmPrice (live CLMM price/APY bounds) and KaminoLtv (Kamino obligation LTV bounds). The example below runs both in a single check and uses the result to gate the rest of the flow.
VaultAssertion.create accepts:
assertion.check accepts a VaultAssertionCheckPlan:
Invalid configuration throws
VaultAssertionConfigError before any RPC reads or condition evaluation. Missing or undecodable on-chain state becomes a warn or block entry inside the returned report instead.
Report Shape
checks only contain user-supplied conditions. Slot drift failures are surfaced through causes and timing; they do not create synthetic checks.
Timing
check() captures referenceSlot once at the start of the run. Each condition records the most recent slot observed through RPC, and the report tracks the maximum drift across the run.
maxSlotDrift is optional and disabled by default. When supplied, drift is checked before and after each condition. If drift exceeds the threshold, the report blocks and the remaining conditions are skipped.
Thresholds
Built-in conditions accept inclusive thresholds in two flavors: Basis-point thresholds — used for APY-style metrics:NumericValue accepts number | string | bigint | BN | Decimal.
At least one bound must be specified per threshold. Any of the following throws VaultAssertionConfigError before evaluation:
- empty threshold objects
- unknown threshold fields, or wrong-unit fields for a metric (e.g.,
warnAboveBpson a price threshold) - negative values, or non-integer BPS values
- block/warn ordering that makes the block threshold less severe than the warn threshold
breachedThresholds for inspection.
Built-In Conditions
VaultCoreState
Asserts strategy vault owner and status-flag invariants. With no inputs, it just records vault state in the audit trail.VaultPriceCoverage
Asserts that decodedExponentPrices covers all required price IDs (or pairs) and is within a freshness bound.
KaminoLtv
Asserts a Kamino obligation’s LTV. The calculation is:borrowingDisabled always blocks. A stale obligation warns when LTV and slot-age thresholds are otherwise passing.
AmmPrice
Asserts price evidence on a legacy AMM (Market Two) market. The market is loaded throughMarket.load(...).
impliedApy, ptPrice, or ptPriceInSy is required.
The loaded market’s
vault.selfAddress is recorded as sourceVault evidence. It identifies the market’s underlying source — it is not a check that the strategy vault owns the market.ClmmPrice
Asserts live CLMM price evidence. The evaluator fetches the market account, validates its program owner againstEXPONENTCLMM_PROGRAM_ID, decodes it, then fetches the linked ticks account and performs the same validation.
impliedApy, ptPrice, or spotPrice is required.
OrderbookPrice
Asserts top-of-book APY and derived prices on an Exponent Orderbook. The evaluator filters expired offers, offers with non-positive amount or APY, and (by default) the assertion owner’s own non-virtual offers. Virtual offers are kept by default.source === "mid", the mid is used; with one side only, the available side is used.
Like
AmmPrice, the loaded orderbook’s vault.selfAddress is recorded as sourceVault evidence. It is not a strategy-vault ownership check.SyExchangeRate
Asserts a core vault’s SY/base exchange rate, loaded throughCoreVault.load(...).
KaminoBorrowCapacity
Asserts that a Kamino obligation has the headroom to take on a new borrow at a target LTV. The evaluator loads the obligation, the collateral and borrow reserves, and computes the projected post-borrow LTV againstmaxLtvBps (with optional ltvBufferBps).
KaminoWithdrawCapacity
Asserts that a Kamino obligation has the headroom to withdraw collateral while still satisfyingmaxLtvBps. Symmetrical to KaminoBorrowCapacity on the withdraw side.
ClmmCapacity
Asserts that a CLMM swap ofamountInAtomic from inputMint to outputMint is executable against the live tick state.
SyBacking
Asserts that an SY mint is sufficiently backed by its underlying. Useful pre-flight before stripping or redeeming SY-denominated positions.PolicyCoverage
Asserts that the strategy vault’s policies cover a required list of programs. Useful for catching missing policies before a flow that depends on them.WithdrawalQueue
Asserts the state of the strategy vault’s withdrawal queue — useful for managers running fill/execute flows who want to refuse to act when there’s an unfilled or past-due withdrawal.Custom Conditions
Custom conditions let you express app-specific policy that doesn’t belong as a generic SDK condition. They share the same audit-trail and evidence semantics as built-in conditions.
ctx (VaultAssertionContext) gives the evaluator first-class RPC access and report helpers:
Helpers cache reads within a single
check() run. Evidence is normalized into JSON-safe report data — BigInt, BN, Decimal, PublicKey, Date, Buffer, Uint8Array, non-finite numbers, and cyclic objects are all handled.
Gating a Transaction
The expected integration is caller-controlled: assert first, decide second, build/send last.report.causes and report.checks are JSON-safe — log them, ship them to a dashboard, or surface them to a manager UI. The decision belongs to the caller.