Skip to content

Under the hood

Keeper and operations

The jobs that list, settle and pay out markets, the refund policy, health checks, and how anyone can do each job.

A convenience, not an authority

The keeper is a small program that lists markets before the opening bell, settles them after the closing bell and pushes payouts to winners. Every action it takes, anyone can take: settle with the proven rounds, refund on a proven stale price, deliver a payout. If it stops, markets still settle, just later; after 72 hours anyone can refund a market outright.

It runs as scheduled route handlers on Vercel, each protected by a secret, and every job is idempotent: it reads the chain, decides, acts, and can run twice without harm.

The jobs

Keeper jobs and schedules
JobWhen (UTC, weekdays unless noted)What it does
openEvery 10 minutes, 12:00 to 13:59Makes sure today's daily markets exist for every allowed ticker (and the week's weekly markets), listed before 9:30 am ET, using the NYSE calendar. Skips a ticker with a corporate action in the window.
resolveEvery 2 minutes, 20:00 to 21:59; and hourly at :07 every dayFor every market past its bell and not settled: finds both rounds, previews, then settles or refunds per the policy below.
deliverEvery 5 minutes, every dayPushes every unclaimed payout and refund to its owner, one call per position; returns refused parts of bets; sweeps fees to the treasury when more than 5 USDG has built up.
relayOn requestChecks a bettor's signed bet, simulates it and sends it, paying the gas. See Gasless betting.
healthOn requestReports whether every job is keeping up (below).

Market hours are computed in New York time with a time-zone library, never a fixed offset. The bells are 13:30 and 20:00 UTC until November 1, 2026, and 14:30 and 21:00 UTC after it.

The refund policy

The keeper may refund a market automatically, because a refund here is based on proof, not on a timeout: the rounds in effect at the bells either break the market’s age limit or they do not, and an RPC outage cannot change that. It still waits:

  • Stale price: only after the bell plus 15 minutes, and only when two independent reads both say STALE.
  • Corporate-action pause: retried every 10 minutes; refunded only 24 hours after the bell if still paused.
  • Phase change on a feed (PhaseBoundary): never refunded automatically. The operator is alerted, and the 72-hour timeout remains the backstop.

Wallets and funds

Operational wallets
WalletHoldsRule
Keeper (lister and relayer), a hot walletETH for gas (its own calls, relayed bets, payout deliveries); the USDG float for opening seedsKeeps at least 0.001 ETH, and enough USDG (in its wallet plus the seeds in its open markets) for every market it is set to list, all open at once. Seeds come back to it at each settlement. Its key lives only in the hosting environment.
Treasury SafeFees and rounding leftoversSwept automatically; nothing to spend.
Guardian Safe (the same Safe)NothingOnly signs: pause or resume new bets and new markets, name the pauser, allow-list feeds, allow listers.
Pauser, one key kept offlineA little ETH for gasCan pause new bets and new markets in one transaction; cannot resume them or do anything else.

The keeper’s wallet can list markets with its own money and holds the seed float. It cannot touch anyone else’s position; if its key leaked, the Safe removes it as a lister and a new key takes over.

Health checks

GET /api/health answers 200 only if all of these hold, and 503 listing the ones that failed:

  • the last successful listing run is less than 26 hours old on a trading day, and today’s markets exist after 13:25 UTC;
  • no market is more than 30 minutes past its bell without being settled (unless it is waiting on a phase change);
  • no settled market has an undelivered payout older than 20 minutes;
  • the keeper holds at least 0.001 ETH, and its wallet plus the seeds in its open markets reach its USDG floor;
  • the Safe owns the factory (ownership accepted), HunchVPM’s only creator is the factory, the keeper is a lister, and new bets are not paused;
  • the RPC’s latest block is less than 60 seconds old;
  • every allowed feed has updated within 26 hours on a trading day;
  • the relayer has sent a bet successfully in the last trading day, or none was requested;
  • every open market’s page reads current numbers, through the same cache the page uses (market-reads);
  • the newest market’s entry times and transaction links can be read from the chain’s logs (market-logs).

An external monitor polls it every 5 minutes and alerts the operator.

Anyone can do it

Keeper jobs anyone can do
JobCallWho receives the money
Settle a marketresolve(specId, strikeRound, finalRound)Nobody; it records the result
Refund on a stale pricevoidStale(specId, strikeRound, finalRound)Nobody; it records the refund
Refund on an out-of-range pricevoidBadAnswer(specId, strikeRound, finalRound)Nobody; it records the refund
Refund after a long pausevoidPaused(specId)Nobody; it records the refund
Deliver a payoutclaimFor(positionId)The position's owner, always
Deliver a refundwithdrawRefundFor(positionId)The position's owner, always
Sweep feessweepFees(usdg)The treasury Safe, always

Step by step, with commands: resolve it yourself.

When something goes wrong

  • A bug is suspected: the pauser (or the Safe) pauses new bets and new markets. Payouts, refunds and settlement keep working; only the Safe can resume.
  • A price feed misbehaves: the Safe removes it from the allow-list, so no new market uses it; existing markets settle or refund on their own proofs.
  • The keeper’s key leaks: the Safe removes it as a lister and allows a new one; the float moves first.
  • The keeper is down: anyone settles and delivers; the operator can also run the keeper by hand.