What it needs
- Two funded keypairs. The keeper wallet must be
market.keeper_authorityon every market it operates, and pays for price pushes and settlements. The CLP authority signs book shapes and inventory moves and pays rent for new pool accounts. On devnet it is also each market’s adminauthority, which fee posting needs. - RPC endpoints. Market discovery uses
getAccountInfo. The commit settler uses a filteredgetProgramAccountsand websocket subscriptions, which some paid RPC tiers disable, so at least one endpoint must allow them. - The mint-redeem program ID. Without
DEVNET_MINT_REDEEM_PROGRAM_IDorMINT_REDEEM_PROGRAM_ID, market discovery fails and the keeper runs QQQ only, with a warning. - Storage for the transaction journal. Every transaction that moves funds is journaled first, in Cloudflare R2 or under a persistent
DATA_DIR. Without a working journal the keeper disables those transactions; price pushes still go out.
RUST_LOG=info and UPDATE_INTERVAL_MS=5000 and exposes port 8484. The process exits with a non-zero code as soon as any of its loops ends, so it runs under a supervisor that restarts it on failure.
Environment variables
The keeper loads.env from its working directory, or the file named by KEEPER_ENV_FILE (which must come from the process environment). Per-network settings, such as the RPC URL, collateral mint and program IDs, are read with a DEVNET_ or MAINNET_ prefix first, then without it.
Networks and keys
Price source
A print more than 10% from the last accepted price is held, and an operator releases it by writing an R2 object, as described in CNBC price holds. The updater also pushes nothing for a market after its scheduled close plus 15 minutes.
When the fallback source prices a market, the confidence band comes from a GJR-GARCH volatility model; with Pyth, the keeper uses the wider of Pyth’s band and the model’s. Mainnet will price from Pyth (Pyth Pro).
Book manager and parameter posting
Off-hours book
Committed orders
Liquidity reallocator
Treasury withdrawal rate
Imbalance control
Short rebate
Redemption settler
Devnet treasury trim
Health and alerts
Storage, dashboard and logs
Collateral yield
The allocator’s limits come from the stress assumptions below and the treasury balance, which it reads on chain, rather than from fixed percentages. See Keeper → Yield allocator.Off by default
Primary and standby
Several instances can run with the same keys. SetKEEPER_PEERS on each to the dashboard URLs of the others. Every 30 s each instance probes /api/status/<network> on its peers, and the one with the oldest start time is primary. Standby instances still push prices, which is harmless to repeat, but skip the loops that move funds, such as the book manager and the commit settler. When the primary stops answering, the oldest remaining instance takes over at the next probe.
Each market has one keeper_authority; the market admin can rotate it with update_keeper_authority to split markets between operators. Bots without either key can run alongside: cancel_swap and claim are permissionless, and anyone can trade the books. settle_swap needs clp.authority or market.keeper_authority.
Logging
The binary crate is namedkeeper, so log targets are its module paths: keeper::oracle, keeper::clmm_pool, keeper::commit_settler, keeper::sol_health, keeper::tx, keeper::rpc. A filter for continuum_keeper matches nothing and silences the keeper.
keeper::clmm_pool=debug logs every reposition, refill and posting decision, and keeper::commit_settler=debug logs committed-order discovery and settlement. keeper::rpc=warn keeps only RPC failures.
A healthy devnet start logs lines like these (timestamps omitted):
/healthz, /api/status/<network>, /api/sol-health/<network> and /api/pool-state/<network>.
Common issues
The keeper refuses to start
RemoveCLMM_GAMMA_DECAY_ENABLED if it is set, and check that GAMMA_DECAY_COEF is a number in (0, 1]. On mainnet, also set the collateral mint and the oracle, mint-redeem and CLP program IDs; there is no fallback to devnet values.
It runs only QQQ, skips markets, or fails with UnauthorizedKeeper
- Set
DEVNET_MINT_REDEEM_PROGRAM_IDorMINT_REDEEM_PROGRAM_ID. Without it, discovery fails and the keeper falls back to QQQ. - Set the collateral mint to cUSDC on devnet (see the warning above).
- Check that
market.keeper_authorityis the keeper wallet’s public key. The admin may have rotated it withupdate_keeper_authority. - On insufficient-lamports errors, check both wallets. Rent for new pool accounts comes from the CLP authority.
”Financial transactions paused” or UNCONFIRMED_TX_MAY_STILL_LAND
An earlier send ended with an unknown outcome, so the keeper stopped every transaction that moves funds. It re-checks the journaled transaction every 30 s. Once the log shows “Reconciled financial transaction … restart keeper to rebuild plans and resume”, restart it. If the journal is reported unavailable or already owned, configure R2 or a persistent DATA_DIR, and make sure no other process holds the same journal.
RPC rate limits
List several endpoints. After 3 consecutive retriable failures (HTTP 429, 503 or a transport error) an endpoint is skipped for 30 s, then probed again.A book sits far from NAV
If the underlying market is closed, this is free float by design, and the first fresh price re-centres the book. If the market is open, checkCLMM_POOLS_ENABLED and the keeper::clmm_pool logs, then the CLP vault balance if the book’s depth is exhausted. A stale price while the market is open means the source is down or Hyperliquid is vetoing it; check the keeper::oracle logs.
Leftover L or S in the keeper wallet
The keeper no longer sweeps it at boot. Redeem matched amounts withredeem_paired, or a single leg with keeper_redeem_single, signed by the keeper wallet.
See also
Keeper overview
What the keeper runs and which keys it holds.
Peg maintenance
Why the venues stay near NAV and what bounds drift.
Book management
Reposition loop, free float, refill, trim and bid cap.

