Skip to main content
The keeper is an off-chain Rust async bot that runs Continuum’s operational loops:
  1. Oracle updater - pushes Hermes price + confidence on-chain every ~15 s, and withholds when the underlying market is closed.
  2. CLMM pool manager - repositions the books to NAV, sizes the spread, refills/trims inventory, and posts the dynamic buffer and vol-informed fees.
  3. Commit settler - cranks committed-order settlement (which is permissionless - anyone can settle).
  4. Yield router - moves deployed collateral to the best lending venue and harvests yield.
It is not in your call path. User mints, redeems, and trades go directly to on-chain programs; the keeper provisions and prices around them.

Task inventory

Oracle updater (~15 s)

Fetches Pyth Hermes price + confidence per market and pushes both on-chain via mint_redeem::update_risk_state. On devnet, Hermes is the oracle and every market runs in ProxyMode - the on-chain Pyth accounts are not consulted. See Oracle. Closed-market aware: if the Hermes feed’s own publish_time is stale (> 120 s, HERMES_STALE_SECS), the keeper withholds the push entirely. The on-chain TWAP then ages past 300 s, mint/redeem freezes itself, and the books stop repositioning and float at their standing band - off-hours price discovery inside the band, re-anchor to NAV at reopen.

CLMM pool manager (30 s)

Per market, each tick:
  • Feeds the vol state with the latest print (ignoring frozen/repeated closed-hours prices).
  • Repositions the books when pool price drifts past the per-market gate (QQQ/SPY/XAU 20 bps, VXX 40 bps), posting the vol-scaled shape with protective skew via set_pool_shape.
  • Refills and trims bidirectionally: drained asks restock (sweep bids → vault_mint_pairs → fund both sides, delta-neutral); bids cap at ~$5k/side with excess swept to the vault; asks trim to ≤1.5× bids.
  • Posts the dynamic buffer target (set_buffer_target), the vol-informed fee, and the vol-scaled committed spread (set_commit_spread, floored at 10bps in settle_swap) when they move meaningfully.
  • Optionally posts the short-leg volatility decay (set_s_gamma_index, gated by CLMM_GAMMA_DECAY_ENABLED, off by default): ratchets the short NAV down by realized per-cycle variance, banking choppiness-convexity as surplus. Ratchet-down only, floored at γ = 0.5. See NAV → Volatility decay.
  • Runs the cross-market collateral rebalance (only excess above the source’s own dynamic target).
RPC-lean: ~3 reads per market per tick in steady state.

Commit settler (20 s idle / 5 s while orders pend)

Discovers pending Order accounts with one filtered getProgramAccounts, provisions inventory (sells first, since they need cUSDC from vault_redeem_pairs), and settles up to 10 orders per tick, largest first. Settlement is permissionless - the keeper is a crank, not a gatekeeper.

Yield router

Routes deployed collateral across Kamino, Save (Solend), and Jupiter Lend (MarginFi is wired but dormant — DefiLlama doesn’t index its lending rate) using 30-day-mean supply APYs from a DefiLlama-backed cache, with switch hysteresis so it doesn’t churn between near-equal venues. Harvests land in the treasury vault and reach the collateral ratio via donate_to_vault. With COLLATERAL_YIELD_RATE_AWARE (default on), the router uses a rate-impact “water-fill” allocator: it models each venue’s marginal supply rate as it absorbs a deposit (a·T/(T+x)) and splits the deploy so every funded venue lands at the same marginal rate — the allocation that maximizes the blended aggregate yield. Diversification across venues becomes emergent (deeper/higher-rate pools take more, overflow spills to the next venue) rather than a fixed per-venue cap. Devnet: a yield emulator mints real cUSDC at the live top-venue APY through the real harvest_collateral_yield instruction hourly, so devnet economics mirror mainnet (hard devnet-only gate). Note: the collateral token on devnet is cUSDC, and yield deployment is off by default (COLLATERAL_YIELD_ENABLED).
Remaining gap: the allocator models its own rate impact (above) but does not yet enforce venues’ hard deposit caps — a venue at its cap would reject the leg, which the router treats as a failed deploy and retries elsewhere next cycle.

Housekeeping

SOL health (auto-airdrop on devnet), inventory monitor, and a local operator dashboard.

The spread engine (model-free)

The half-spread that shapes every book is not a forecasting model - there is no trained model in the live path. (A linear-quantile forecaster was measured net-negative in research: inside a max() with the floors it could only widen, taxing flow without adding protection.) The live spread is a max-of-floors stack:
Two post-processing steps:
  • Freeze: above freeze_trigger, the book stops repositioning and floats rather than chasing a disorderly tape.
  • Protective drift skew: the trend-adverse side widens by ×(1 + z), where z is a slow ~1-day return z-score; the other side never tightens. Backtested, this fixes trend bleed (e.g. XAU went from −233 to +257 bps/yr) - the classic symmetric inventory skew was falsified.
Vol state seeds at boot from 60 days of Pyth Benchmarks history, so the floors are warm despite restarts; closed-hours frozen prices are ignored.

Listing without model training

Per-market config (min_bps / floor_mult / fee_mult / window) lives in the keeper config JSON. Listing a new asset needs no training: floors plus the ratchet carry both safety and competitiveness. The recipe is steep-wing geometry sized to the asset’s vol class, min_bps ≥ ~2× its 5-minute σ, and fee_mult ~1.0-1.5 for high-vol single names.

Configuration

All keeper behaviors are env-gated kill switches, default ON: Key tunables: Full list: keeper running guide.

Can I run my own keeper?

The reference implementation is public in the protocol repo. What’s open vs privileged:
  • Settling committed orders is permissionless. Anyone can crank settle_swap - no authority needed.
  • Book shaping is privileged. set_pool_shape, vault plumbing, update_risk_state, and set_buffer_target check the keeper/CLP authority. One canonical authority per market; two keepers signing as the same pubkey will collide.
  • Paired arb is open. Ordinary mint_paired / redeem_paired plus venue trades need no privilege at all.

Dashboard

The reference keeper exposes a local HTTP dashboard at http://localhost:8484 (mainnet) / 8485 (devnet): oracle freshness per market, risk state, book positions and drift, pending committed orders, vault balances, and yield-venue status. This is for the operator - integrators read state directly from on-chain accounts.

Read more

Keeper overview

Architecture, loops, and operational detail.

Run a keeper

Config, keypairs, dashboard, troubleshooting.

CLP and the venues

The books and vaults these loops manage.

Solvency

What the protocol enforces independently of the keeper.