Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Commands

Everything the bazaar command does. bazaar keeper <command> runs the keeper; bazaar wallet and bazaar mock-prices are shared tools. Every command has --help.

CommandWhat it does
keeper initthe setup wizard
keeper doctorchecks the RPC, the factory’s wiring, the subgraph, prices, wallets and jobs
keeper startruns the enabled jobs until stopped
keeper statuswhat a running keeper is doing
keeper marketsevery market with its label, status and open positions
keeper earningsrewards, gas and net from the ledger
keeper opportunitiesmanual operations available now
keeper runone operation now
walletcreate, import or list wallets
mock-pricesa mock Pyth Pro price endpoint for a local chain

Common Options

OptionMeaning
-c, --config <path>the keeper’s config file; default bazaar-keeper.yaml in the current directory (~/ works). Every keeper command and wallet list take it
--debug, --verboseprint the whole error with its stack trace when a command fails (bazaar --debug keeper start, or at the end of the line)
-h, --helpthe command’s usage

Errors print one readable line, with URLs and keys masked. Exit codes:

CodeMeaning
0done
1the command failed (an unreachable RPC, a failed doctor check), or setup was cancelled
2a usage, config or wallet problem: an unknown option, a missing --market, an invalid config, a wrong keystore password
130cancelled at a prompt, or stopped by a second Ctrl-C

keeper init

bazaar keeper init [-c bazaar-keeper.yaml]

Asks for the network, factory, RPC, subgraph, price endpoint, wallet, jobs and markets, checking each answer, and writes the config and a .env beside it (secrets and URLs only in .env), a new keystore in keys/ beside them, and state.dir as state/ beside them. Needs a terminal. Every question is explained in Setting Up a Keeper.

keeper doctor

bazaar keeper doctor [-c bazaar-keeper.yaml]

Checks everything start relies on. Exits 0 when nothing failed, 1 otherwise.

✔ RPC            chain 42161, latency 61 ms, eth_call state overrides supported
✔ Factory        0x0000000000000000000000000000000000000000 not an official deployment, 12 market(s)
✔ Wiring         lens and terminator both point back at this factory
✔ Subgraph       synced to block 271,402,118 (14 blocks behind)
✔ Prices         12/12 markets have a print; 4 not fresh right now (AAPL/USD, TSLA/USD, NVDA/USD, SPY/USD)
✔ Prices         the fixed_rate@200ms stream is delivering
✔ Wallet default 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955, 0.05000 ETH (roughly 8,333 calls at today's base fee)
✔ Wallet fast    0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f, 0.03000 ETH (roughly 5,000 calls at today's base fee)
⚠ Jobs           liquidation takes losses: up to $0.1 a call, $2 a day
✔ Jobs           liquidation, triggers, unload, adl, refresh, collect, terminalSettlement

“Not fresh right now” is normal for markets with trading hours outside them. The first Prices line is one request to the request API; the second opens the price stream for ETH/USD and waits up to 5 seconds for a print (skipped when prices.stream is off). Each line is explained in Setting Up a Keeper; each failure in Troubleshooting.

keeper start

bazaar keeper start [-c bazaar-keeper.yaml] [--dry-run] [--only <jobs>]
OptionMeaning
--dry-runplan and simulate every call, log it, send nothing (sets every job’s dryRun)
--only <jobs>comma-separated jobs to run, out of those the config enables; the rest are switched off for this run. Names in any style: liquidation,triggers, terminal-settlement, sweep_expired

Runs until Ctrl-C or SIGTERM. The first signal stops cleanly (in-flight transactions finish, collect runs if its onShutdown is set, the snapshot is saved); a second leaves at once.

bazaar keeper start --dry-run --only liquidation,triggers

keeper status

bazaar keeper status [-c bazaar-keeper.yaml]

Reads the status.json of the keeper running with this config (it connects to nothing), so it works from any terminal on the same machine:

Bazaar keeper · arbitrum-one · block 271,402,140 · indexed 271,402,139 · prices live · running
factory 0x0000000000000000000000000000000000000000 is not an official deployment
 JOB                 MARKETS  LAST ACTION                                                  TODAY EARNED    GAS     NET
 liquidation              12  ETH/USD liquidate 1 account(s), $2,050 notional (confirmed)         $0.35  $0.01   $0.34
 triggers                 12  BTC/USD execute 2 trigger order(s), up to $0.40 of bounty (confirmed)  $1.20  $0.02   $1.18
 unload                   12  -                                                                   $0.00  $0.00   $0.00
 collect                 all  ETH/USD claim $5.12 (confirmed)                                     $0.00  $0.00  $-0.00
 WALLET   ADDRESS
 default  0x14dC79964da2C08b23698B3D3cc7Ca32193d9955
 fast     0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f

With no status file yet: No keeper has run with this config yet. Start one with bazaar keeper start. A file more than 30 seconds old shows not running (last seen N min ago). A red line under the header says sending is halted. Monitoring lists every field of the file.

keeper markets

bazaar keeper markets [-c bazaar-keeper.yaml]

Every market of the factory, sorted by label. It connects without loading wallets; with no snapshot yet it builds the index first, which takes as long as a first start.

 MARKET    ADDRESS                                     STATUS      HOURS    POSITIONS  LIVE ORDERS  INVENTORY
 AAPL/USD  0x5FbDB2315678afecb367f032d93F642f64180aa3  live        session         41           63          0
 BTC/USD   0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512  live        24/7           388          912      0.012
 ETH/USD   0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0  live        24/7           521         1204          0
 ETH/USD   0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9  terminated  24/7             0            0          0

STATUS is live, adl, limbo, settling or terminated; HOURS is 24/7 or session (a market with trading hours); INVENTORY is the vault’s inherited position, in units. Two rows with one label are two markets (here a terminated one and its relisting): name them by address.

keeper earnings

bazaar keeper earnings [-c bazaar-keeper.yaml] [--since 7d] [--by job|market]
OptionDefaultMeaning
--since <period>7dhow far back: 30m, 24h, 7d; a bare number is days
--by <group>jobone row per job or per market (market label; - for calls on no market)
 MARKET    CALLS  REVERTED   EARNED      GAS      NET  CLAIMED
 -             1         0  $0.0000  $0.0002  $-0.0002    $0.00
 BTC/USD      22         2  $3.4100  $0.0410  $3.3690    $0.00
 ETH/USD      19         1  $1.9500  $0.0380  $1.9120   $12.40

Reads ledger.jsonl only: it works whether or not the keeper is running. No transactions in that period. when there are none. The Ledger explains the columns.

keeper opportunities

bazaar keeper opportunities [-c bazaar-keeper.yaml]

Lists the manual operations a dry run shows would go through now, or that a “too early” revert shows will open later, each with the command that runs it (naming the market by address):

finalizeTermination ETH/USD: every position is settled, or the escape hatch has opened (ready now) — bazaar keeper run finalize --market 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9
terminateScheduledPair TSLA/USD: its scheduled cutoff has passed (opens at 2026-11-09 14:30 UTC) — bazaar keeper run terminate-scheduled --market 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707

Or Nothing is waiting for a manual call. Manual Operations lists what it looks for.

keeper run

bazaar keeper run <operation> [--market <m>] [options]

Runs one operation now. Every call is simulated first; nothing that reverts in simulation is sent.

OptionMeaningUsed by
--market <m>a market’s label, address or pair id; comma-separated for collectevery per-market operation (required), collect (optional)
--accounts <addresses>comma-separated accountsliquidate, settle-terminal
--orders <ids>comma-separated order idsexecute-triggers, sweep-expired
--assertion <id>a UMA assertion id (32 bytes, with or without 0x)settle-termination, settle-listing, settle-identifier-upgrade (required)
--proposal <id>an insurer proposal idexecute-insurer-termination (required)
--pair-id <id>a listing’s pair idexpire-listing (required)
--dry-runsimulate and report, send nothingall
--forcesend even when the profit and loss rules would skip itthe automatic operations
-y, --yessend a manual operation without askingthe manual operations
--stored-price <policy>when a settlement at the market’s stored price is planned once its last resort is open: whenAbsent (default), always or neverterminate-scheduled
--accept-stored-pricesend a settlement at the stored price, which is otherwise shown and not sent, --yes or notterminate-scheduled
OperationCallsNeeds
liquidateliquidate on the accounts given, or every account below its requirement--market
execute-triggersexecuteTriggeredOrders on the orders given, or every ready one--market
unloadunloadVault--market
execute-adlexecuteAdl with the planner’s picks--market
refresh-pricerefreshPrice--market
collectclaimFees on every market (or those given) where a wallet holds a balance
settle-terminalsettlement-mode liquidate on the accounts given, or every open position--market
sweep-expiredsweepExpired on the orders given, or every expired or finished one--market
finalizefinalizeTermination--market
terminate-stalethe terminator’s terminateStalePair--market
terminate-scheduledthe terminator’s terminateScheduledPair, with the archived Pyth Pro updates its rule asks for--market
settle-terminationthe terminator’s settleTerminationProposal--assertion
execute-insurer-terminationthe terminator’s executeInsurerTermination--market, --proposal
settle-listingthe factory’s settleDeploymentProposal--assertion
expire-listingthe factory’s expireStuckDeploymentProposal--pair-id
settle-identifier-upgradethe factory’s settleIdentifierUpgradeProposal--assertion
expire-identifier-upgradethe factory’s expireStuckIdentifierUpgradeProposal
activate-identifier-upgradethe factory’s activateIdentifierUpgrade

The automatic operations (the first eight) keep their job’s profit and loss rules unless --force. The manual ones show what would happen and ask Send it? (default no) before sending; without a terminal they print Not sent: pass --yes to send without confirming. A missing required option is a usage error (liquidate needs --market, exit 2).

Each result prints as a status, the job, the market and a summary, then its reason, what it earned or would earn, its transaction, and when a “too early” call opens:

$ bazaar keeper run liquidate --market ETH/USD --dry-run
simulated  liquidation  ETH/USD  liquidate 1 account(s), $2,050 notional
   earns $0.0500 for $0.0019 of gas
   would earn $0.0500 for about $0.0019 of gas

$ bazaar keeper run refresh-price --market BTC/USD
skipped  refresh  BTC/USD  refresh price
   below the profit rule: earns $0.0000 for $0.0021 of gas, needs ×1.25 and $0.001 net (allowLoss is off)

$ bazaar keeper run finalize --market 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9
simulated  finalizeTermination  ETH/USD  finalize ETH/USD
   sent on request (profit and loss rules skipped)
   would earn $0.0000 for about $0.0031 of gas
? Send it? Yes
confirmed  finalizeTermination  ETH/USD  finalize ETH/USD
   sent on request (profit and loss rules skipped)
   earned $0.0000, gas $0.0029
   tx 0x8a3f…

The statuses: simulated (a dry run, or a preview), skipped (not sent, with why), confirmed, reverted (on chain), unknown (no receipt). Manual Operations covers each operation.

wallet

bazaar wallet new    [--name default] [--path <file>]
bazaar wallet import [--name default] [--path <file>]
bazaar wallet list   [-c bazaar-keeper.yaml]
OptionDefaultMeaning
--name <name>defaultthe keystore’s file name, and the name to put it under in wallets
--path <file>~/.bazaar/keys/<name>.jsonwhere to write the keystore

new creates a key and saves it as an encrypted keystore; import encrypts a private key you paste; both ask for a password twice and print the YAML to add. list loads the config’s wallets and prints each one’s ETH and claimable earnings. Wallets & Secrets.

mock-prices

bazaar mock-prices [--rpc http://127.0.0.1:8545] [--price <FEED_ID=USD>]... \
  [--host 127.0.0.1] [--port 8787] [--token-env <NAME>]
OptionDefaultMeaning
--rpc <url>http://127.0.0.1:8545the local chain, whose clock the updates follow
--price <FEED_ID=USD>ETH/USD at 2000a feed’s starting price; repeatable. The feed is its Pyth Pro number (2=3000 is ETH/USD) or the bytes32 a pair reports as its baseFeedId
--host <host>127.0.0.1the address to listen on. One other machines can reach (anything but localhost, 127.0.0.0/8 and ::1) is refused without --token-env
--port <port>8787the port
--token-env <NAME>nonethe environment variable that holds a token every client must present, the price controls included (the symbols registry needs none). It is read from the environment, never the command line, where other users’ process listings would show it

Serves a mock Pyth Pro endpoint until Ctrl-C: the price stream, the request API and the symbols registry. Its updates are signed with the public test key that only a local deployment’s mock verifier trusts, and stamped with the chain’s time. For local testing only: Testing Locally with Anvil.

mock Pyth Pro on http://127.0.0.1:8787 (stream ws://127.0.0.1:8787/v1/stream), on the clock of http://127.0.0.1:8545; feeds: 2