Skip to content

Under the hood

Contracts

Addresses, the powers table, invariants, the changes from the reference contract and how to verify each one.

Addresses

Every address the venue uses comes from one file, deployments/robinhood-mainnet.json, which the site, the keeper and the README all read. Each links to Blockscout.

Price feeds

How they fit together

Contract map
                    Safe (owner / guardian / treasury)
                      │ setFeed, setOpener        │ setEntriesPaused (enter only)
                      ▼                           ▼
 keeper (opener) ─► HunchMarketFactory ──create──► HunchVPM  ◄── bettors: enter / (relayed) enterWithAuthorization
                      │                 (seed legs    │           claim / withdrawRefund
                      │ register spec    handed back  │ ◄── anyone: claimFor / withdrawRefundFor
                      ▼                  to opener)   │            finalizeVintage / sweepFees
               StockRoundResolver ──resolve / void────┘
                      │ getRoundData / latestRoundData
                      ▼
          Chainlink stock feed proxies (NVDA/USD, TSLA/USD, …) on Robinhood Chain
  • HunchVPM holds every stake, books every bet and pays every winner. It has no owner, no upgrade and no price input.
  • StockRoundResolver settles each market from two proven Chainlink rounds. It has no owner and no admin.
  • HunchMarketFactory lists a market in one transaction: it takes the opening seed from the lister, creates the market, registers its settlement spec, hands the seed positions to the lister and keeps nothing.

Solidity 0.8.28, optimizer at 200 runs, EVM version cancun, no via-IR, and no upgradeable proxies. Production contracts use no external libraries beyond minimal local interfaces.

Powers

Stated once, verbatim, the same table the README carries:

  • Safe (guardian of HunchVPM)

    Can
    pause and resume new entries and new markets; name or remove the pauser
    Cannot
    pause or block claims, refunds, resolution; move any stake; set any price
  • Pauser (one key the Safe names)

    Can
    pause new entries and new markets
    Cannot
    resume them; anything else
  • Safe (owner of factory)

    Can
    allow-list a feed, its Stock Token and its staleness bounds; add/remove an opener
    Cannot
    change a listed market's feed, times, bounds, seed, fee or caps
  • Opener (keeper hot wallet)

    Can
    list a new market through the factory (the only creator HunchVPM accepts), paying the seed itself; owns the seed legs it paid for
    Cannot
    change or close an existing market; touch anyone else's position
  • Anyone

    Can
    resolve with the two proven rounds; void on proven staleness, a proven out-of-range price or a 24 h oracle pause; relay a bettor's signed entry; deliver claims and refunds to owners; sweep fees to the treasury
    Cannot
    choose the outcome; send anyone's funds anywhere but to their owner
  • StockRoundResolver

    Can
    settle its registered markets per the spec
    Cannot
    anything else (it has no owner)

Invariants

Properties the contracts are built to keep, checked by the test suite over random sequences of bets, settlements and payouts:

Invariants
IdPropertyIn plain words
INV-1SolvencyThe contract always holds at least everything it owes: open stakes, unclaimed payouts and refunds, leftovers and fees.
INV-2ConservationA settled market pays out exactly its pool (plus a rounding leftover); a refunded one returns exactly what was accepted.
INV-3ExitsMoney leaves only as a payout or refund to its owner, a leftover to its named owner, or fees to the treasury.
INV-4Pause scopeWhile new bets are paused, only new bets fail.
INV-5Only goes upAn open position's win payout never decreases, whatever comes after it.
INV-6Reference equivalenceWith the fee and limits switched off, it behaves exactly like the reference contract.
INV-7Settlement soundnessOnly the one valid pair of rounds can settle a market; any other pair is rejected.
INV-8Signed betsA signed bet with a different market, side, amount or salt fails, and a used signature cannot be replayed.

Changes from the reference

HunchVPM is the paper’s reference contract, VestedParimutuel.sol, changed by these ten diffs and nothing else. The literal diff against the reference is kept with the source as contracts/DIFF.md. The payout arithmetic, the batching, the settlement semantics and the storage layout are untouched.

The ten changes
ChangeWhy
D1A fee on winners' gains (at most 5%, 2% on this venue), taken at claim; swept to the treasury separately.The business model, with no fee on stakes, refunds or losses.
D2claimFor and withdrawRefundFor: anyone can deliver a payout or refund, always to its owner.The keeper pushes every payout, so nobody has to come back to claim.
D3Minimum and maximum bet per market, fixed at listing.A guarded beta that bounds the damage of any bug.
D4The guardian can pause new bets. Nothing else is pausable.An emergency brake that cannot trap anyone’s money.
D5enterWithAuthorization: a bet from a signed USDG transfer bound to market, side and amount.Gasless bets; the bettor needs no ETH.
D6Read views: accrued, marketPositions, previewFee (and marketTerms).What the site needs to show a position and a book.
D7Events: FeeAccrued, FeesSwept, EntriesPaused.So indexers and the Proof page can follow fees and pauses.
D8Settlement finalizes the last batch of bets even in the same Ethereum block as the last bet.On Robinhood Chain one Ethereum block spans many chain blocks; without it a market could be drained.
D9At most 200 bets per batch, and a cap on capacity.Settling a batch always fits in a block, so no market can be locked.
D10Only the market factory can create markets; the pause also stops new markets; a pauser key can pause but never resume; a claim checks its bet was batched.One escrow holds every market, so nobody else may open one with odd settings, and the brake is fast.

The settlement contract

StockRoundResolver settles on the Chainlink price in effect at each bell, proven by round id, so neither the time of the call nor who makes it can change the answer. Its functions:

  • resolve(specId, strikeRound, finalRound): anyone, after the bell. Verifies both proofs, then settles UP, DOWN, or refunds on a flat price. Never refunds for staleness.
  • voidStale(specId, strikeRound, finalRound): anyone, after the bell, only if the proven rounds break an age limit. A market with a good answer cannot be refunded this way.
  • voidBadAnswer(specId, strikeRound, finalRound): anyone, after the bell, only if a proven round’s price is out of range (not a real price). A market with a good answer cannot be refunded this way.
  • voidPaused(specId): anyone, 24 hours after the bell, if Robinhood’s corporate-action flag on the token is still set.
  • preview(specId, strikeRound, finalRound): read-only; the status and both prices, for the keeper and for you.

Each market’s spec (settler, market id, feed, Stock Token, both bell times, both age limits) is hashed into its specId when it is registered, and cannot change. Details: round proofs.

The market factory

openUpDown can be called only by an allowed lister (the keeper’s wallet). It checks the feed is allow-listed, the market is listed before its opening bell, the window is at most 8 days, the seed is at least 1 USDG per side and any age limit asked for is tighter than the feed’s own, never looser. It lists every market with the same constants: capacity 30, fee 2% of gains, refund timeout 72 hours, and leftovers and fees to the treasury Safe. The Safe, as owner, can only allow-list feeds (with their Stock Token and age limits) and listers; it cannot change a listed market.

Verify them yourself

Each contract is verified on Blockscout, with Sourcify as the fallback:

Blockscout verification (Robinhood's documented command)
forge verify-contract <address> src/HunchVPM.sol:HunchVPM \
  --chain-id 4663 --rpc-url $RH_RPC_URL \
  --verifier blockscout --verifier-url https://robinhoodchain.blockscout.com/api/

The reference contract and the paper: The Vested Parimutuel (opens in a new tab), 2nd edition, conformance suite 1.2.0 with 118 vectors.