Docs
What a keeper can and cannot do.
Keepers are permissionless and open source. Anyone can run one; the tip pays them. Their only discretion is the route.
Five lines
- A keeper cannot choose the amount. The program computes the slice from on-chain state.
- A keeper cannot omit the check. begin_sweep reads the instructions sysvar and refuses unless a finish_sweep for the same book and release id follows in the same transaction.
- A keeper cannot redirect the output. The owner’s own token account is the destination the program verifies, before and after.
- A keeper’s only discretion is the route, bounded by the owner’s tolerance against Pyth’s price net of confidence.
- A keeper’s only reward is the fixed tip, 0.0005 SOL, plus the rent it advanced for the receipt, paid from the owner’s float.
The sweep transaction, atomic without a Jupiter CPI
A PDA can only sign inside a CPI, so a top-level Jupiter instruction cannot draw from a program-owned escrow. The slice therefore passes through the keeper’s own USDC account inside one atomic transaction, and the program guarantees — through instruction introspection — that the verifying instruction runs at the end. If it does not, the first instruction refuses; if verification fails, everything reverts, including the delegate transfer.
0 ComputeBudget unit limit; unit price 1 begin_sweep compute the slice; delegate-transfer USDC → the keeper 2 Jupiter setup if any 3 Jupiter swap USDC → asset, ExactIn = slice, destination = the owner's account 4 Jupiter cleanup if any 5 finish_sweep delta ≥ Pyth min-out; receipt; tip — or everything reverts
The price bound
finish_sweep reads a Pyth price account for the book’s asset, fully verified, under ten minutes old, with a confidence band under 1%. The minimum that must arrive is the slice divided by the price plus its confidence, less the owner’s tolerance, in raw units. For a feed that prices one share rather than one token, the minimum is divided by the mint’s live scaled-UI multiplier. Below the minimum, the whole transaction reverts.
Where the price comes from
Hermes has required an API key since 26 August 2026, and the on-chain SPYX/USD account was not being kept fresh when we looked. So a keeper posts its own fully verified update from Hermes when the on-chain one is stale, and closes it after. A stale feed pauses sweeps; nothing is lost by waiting.
Running one
SCRIP_KEEPER_KEYPAIR=keeper.json PYTH_API_KEY=… NEXT_PUBLIC_SOLANA_CLUSTER=mainnet-beta npm run keeper
It watches every Book with the rule on, subscribes to each owner’s USDC account, syncs watermarks after spends, and reports the last sweep and the last reason per book on a health endpoint the app reads.