- A Combine action on market cards and in the trade panel
- A parlay drawer sliding in from the right with the slip
- Parlay rows in the existing positions table (profile + market pages, one component)
- Cash out on live parlay rows
- Analytics through your existing pipeline
Stand up the environment (dev prices HL testnet HIP-4)
The SDK is config-injected, so the app code is identical across environments.
What differs is the deployment behind it:
| Piece | Dev env | Notes |
|---|---|---|
| HyperEVM chain | 998 (testnet) | contracts live here |
| HIP-4 pricing source | Hyperliquid TESTNET | relayer + keeper flag HL_TESTNET=true |
| Relayer | your own worker deploy | relayer/ from the parlays.live repo, wrangler deploy |
| Keeper | your own worker deploy | settles from the same HL environment it priced from |
| Escrow / vault / USDC | your own testnet deploy | one-time forge deploy, addresses into config |
config/parlay.ts
Vendor the packages
No npm publish needed. Copy
packages/taker and packages/sdk from the
parlays.live repo into your workspace’s packages/ (both are source-shipped
TypeScript, no build step; a packages/* pnpm workspace glob picks them up).
Peer ranges are react >=18 and viem >=2 - both satisfied by a catalog setup.
wagmi stays optional and unused in this recipe.Bind the wallet: the Privy adapter
Privy exposes an EIP-1193 provider per connected wallet. The adapter turns
that plus the client’s call builders into the full money flows - no wagmi:One adapter per active wallet; rebuilding on wallet change is cheap. The
lib/parlay/use-parlay-adapter.ts
onEvent union is identical to the wagmi hooks’, so analytics mapping is
portable (see the analytics guide).Slip state, shared app-wide
Market cards and the drawer must see the same slip, so hold it in a context
using the pure helpers (no wagmi hook needed):Mount it once in your app providers, next to the Privy and QueryClient
providers.
lib/parlay/slip-context.tsx
The Combine action (market cards + trade panel)
Add a small affordance per outcome row on the market card, and an
“Add to combo” secondary action in the trade drawer/panel. Both just call
Re-tapping the same outcome removes the leg; tapping the other side flips it -
that is the
toggle:components/market-card/combine-action.tsx
toggleLeg contract, so selected-state stays trivially in sync.The parlay drawer (right side)
Reuse your existing drawer primitives (the same container/animation your trade
drawer uses). Inside: slip rows, stake input, a debounced preview quote, and
the submit button driven by the adapter through a react-query mutation:For fine-grained button copy per step (approving / quoting / signing /
submitting), pass
components/parlay-drawer/parlay-drawer.tsx
onStatus in the adapter options and mirror it into state -
the same status machine as the drawer guide.Positions: one component, two surfaces
Wrap the adapter’s Interleave with your existing single-market position rows via a
positions() in react-query, then reuse your existing
positions-table component by adding a parlay row variant (discriminated
union). The profile page filters with positionsOf, a market page with
positionsOnMarket - same component, same data hook:lib/parlay/use-parlay-positions.ts
kind: "single" | "parlay" union - full pattern in
the positions guide.Cash out on live rows
Flag it and QA
Ship behind your feature-flag infra. QA checklist against dev HL-testnet
markets:
- two-leg combo quotes, signs (one wallet prompt for approve when needed, one signature), lands on-chain, appears in the drawer-cleared state
- correlated legs show shortened odds vs the naive product; mutually exclusive legs are refused with a clear error
- positions rows appear on profile AND the involved market pages, settle states update, cash-out pays out
- analytics events flow (
parlay.quote_requested…parlay.confirmed)

