All-or-nothing composite bets

A parlay combines several Hyperliquid HIP-4 outcome legs into one wager that pays only if every leg wins. There is no parlay primitive on HyperCore: buying three legs as HIP-4 orders would be three independent bets. The parlay product (combining legs, escrowing both sides, all-or-nothing payout) lives in the ParlayEscrow contract on HyperEVM, and Hyperliquid is used for what it is authoritative on: pricing and resolution. Each leg is a {marketId, outcome} pair, where outcome is 0 (NO) or 1 (YES) on a HIP-4 outcome market.

Taker, maker, escrow

RoleWhoWins when
TakerThe bettor (your user)Every leg hits
MakerThe pooled MakerVaultAny leg loses
In RFQ terms the maker is the passive side that quotes a price and stands ready, like a sportsbook setting the line; the taker accepts that quote. It only feels backwards because the bettor emotionally “makes a bet.”

The escrow model

When a parlay opens, ParlayEscrow.submitParlay pulls two amounts and locks both until settlement:
  • stake: the taker’s gross stake in USDC (fees come out of this side)
  • makerCollateral: the vault’s downside, sized so the taker’s win pays the quoted odds
pot = stake + makerCollateral
The winner takes the pot minus fees. Every parlay is fully collateralized on-chain: the vault physically locks its worst case per parlay, so payouts never depend on vault solvency math. The SDK exposes this arithmetic directly:
import {potOf, bookedOddsBps} from "@parlays-live/taker";

potOf(row);         // row.stake + row.makerCollateral
bookedOddsBps(row); // pot / stake in bps, e.g. 34200n = 3.42x

The gasless taker flow

The order is a single EIP-712 struct (ParlayOrder) that both sides sign byte-for-byte; the relayer submits both signatures in one transaction and pays the gas.
1

Quote

The client sends only which legs and the stake (POST /quote). The relayer prices each leg from live HL mids, applies the correlation engine and risk limits, builds the order with maker = vault, and signs the maker side with the vault’s quoter key.
2

Taker signs

The taker signs the identical order. client.takerSigningPayload(order) produces the exact signTypedData payload (domain {name: "Sparrow", version: "1", chainId, verifyingContract: escrow}).
3

Relay

POST /submit carries the order plus both signatures. The relayer simulates, then submits submitParlay on-chain. The escrow verifies both signatures, pulls stake from the taker and makerCollateral from the vault, and records the parlay.
The taker pays gas exactly once, ever: the first USDC approve for the escrow (the useSubmitParlay hook approves maxUint256 so it never recurs). Quotes carry a 10-minute deadline; a stale order simply cannot be submitted.

Settlement

Resolution is pluggable behind IResolutionOracle; the live oracle is optimistic: a publisher proposes HL outcomes, anyone can challenge a wrong proposal against the HyperCore mark-price precompile, and it finalizes after a dispute window. A scheduled keeper worker mirrors Hyperliquid’s settledOutcome onto the oracle and calls settle(id) automatically once legs are final (settlement is also permissionless, so anyone can). The escrow then reads each leg and applies, in precedence order LOST > VOID > WON:
  • any leg lost -> maker takes the pot (fees realized); a decisive loss settles immediately
  • else any leg void -> full refund to both sides, no fees
  • else all legs won -> taker takes the pot minus fees
Funds are credited to pull-payment balances; the vault sweeps winnings back into NAV. Your app renders the settled flag from ParlayRow and never touches settlement itself.
Before settlement, the taker can also exit early at fair value: see Cash-out.