import {
  ParlayProvider,
  useTakerClient,
  useParlaySlip,
  useSubmitParlay,
  useParlayPositions,
  useCashOut,
} from "@parlays-live/taker/react";
Headless React bindings for wagmi v2 + react-query. No components, no styles: the hooks own the state machines and your app renders the UI. Peer dependencies: react >= 18, wagmi >= 2, viem >= 2, @tanstack/react-query >= 5.

ParlayProvider

<ParlayProvider client={createTakerClient({...})}>{children}</ParlayProvider>
Wrap the subtree once, inside your WagmiProvider and QueryClientProvider. All hooks read the client from this context.

useTakerClient

function useTakerClient(): TakerClient
Returns the bound client. Throws if called outside a ParlayProvider. Use it for anything the higher-level hooks do not cover, e.g. a debounced preview quote in a slip drawer.

useParlaySlip

function useParlaySlip(initial?: Picks): {
  picks: Picks;                                      // marketId -> outcome (0 NO / 1 YES)
  legs: PickLeg[];                                   // memoized array form, ready for quote/submit
  count: number;
  sideOf: (marketId: number) => number | undefined;  // selected-state for outcome buttons
  toggle: (marketId: number, outcome: number) => void;
  remove: (marketId: number) => void;
  clear: () => void;
}
Headless slip state. toggle semantics: tapping an outcome adds the leg, tapping the same outcome again removes it, tapping the other side flips it. One leg per market by construction. The underlying pure helpers (toggleLeg, removeLeg, toLegs, legCount) are exported from @parlays-live/taker if you keep slip state in your own store.

useSubmitParlay

type SubmitStatus = "idle" | "approving" | "quoting" | "signing" | "submitting" | "done" | "error";

function useSubmitParlay(cb?: ParlayCallbacks): {
  submit: (legs: PickLeg[], stake: bigint) => Promise<SubmitResponse>;
  status: SubmitStatus;
  error: string | null;
  result: SubmitResponse | null;      // {txHash, parlayId} once done
  lastQuote: QuoteResponse | null;    // the quote used for the last submit attempt
  reset: () => void;                  // back to "idle"
}
The full taker flow in one call, walking status through each stage:
  1. Chain guard: cb.ensureChain() if provided, else wagmi switchChain to client.config.chainId (failure swallowed).
  2. approving: reads the USDC allowance; if below stake, sends an approve(maxUint256) transaction and waits for the receipt (the only gas the taker ever pays, once).
  3. quoting: client.quote(legs, stake, address); the relayer prices from live HL mids and signs the maker side. Sets lastQuote.
  4. signing: the taker signs the identical order via EIP-712.
  5. submitting: client.submit(...); the relayer relays on-chain.
  6. done: result holds {txHash, parlayId}.
submit rejects (and sets status: "error" + error) if the wallet is not connected, the quote is refused, the signature is declined, or the relay fails. A failed event carries the exact stage. Options and the event union are documented in Analytics.

useParlayPositions

function useParlayPositions(opts?: {refetchMs?: number; enabled?: boolean}): {
  rows: ParlayRow[];                                          // every parlay on the escrow, newest first
  count: number;                                              // nextParlayId (total ever opened)
  isLoading: boolean;
  mine: (taker: Address | undefined | null) => ParlayRow[];   // profile-page selector
  onMarket: (marketId: number) => ParlayRow[];                // market-page selector
}
refetchMs
number
default:"8000"
Poll interval for parlay tuples. Leg data refetches at max(refetchMs, 30000) since legs are immutable.
enabled
boolean
default:"true"
Gate the reads entirely, e.g. on an isConfigured flag for networks whose contracts are not deployed yet.
Reads nextParlayId, then batches getParlay and getLegs via wagmi useReadContracts (cached, deduplicated). mine and onMarket are memoized selectors over rows; render both surfaces with the same row component (see the positions guide). The pure selector forms (positionsOf, positionsOnMarket, openPositions) and the non-React fetchParlays are exported from @parlays-live/taker.

useCashOut

type CashoutStatus = "idle" | "quoting" | "quoted" | "cashing" | "done" | "error";

function useCashOut(cb?: ParlayCallbacks): {
  status: CashoutStatus;
  quote: CashoutQuote | null;                                        // set while "quoted"
  error: string | null;
  getQuote: (parlayId: number, taker: Address) => Promise<CashoutQuote | null>;
  execute: (parlayId: number, q: CashoutQuote) => Promise<void>;
  reset: () => void;                                                 // clears status, quote, error
}
Two-step early close:
  • getQuote fetches the quoter-signed buy-back price (status: quoting -> quoted). Returns null and sets error on failure instead of throwing.
  • execute runs the chain guard, sends ParlayEscrow.cashOut from the taker’s wallet, and waits for the receipt (status: cashing -> done). Execution errors are truncated to one line, 140 chars.
The quote expires 120 seconds after issuance; re-call getQuote if the user waits too long. Full walkthrough in the cash-out guide.

ParlayCallbacks

Both write hooks accept the same callbacks object:
type ParlayCallbacks = {
  onEvent?: (e: ParlayEvent) => void;   // analytics tap for every funnel step
  ensureChain?: () => Promise<void>;    // custom wallet-network guard; default wagmi switchChain
};
See Analytics for the full ParlayEvent union and a PostHog mapping.