Skip to main content
An RFQ (Request for Quote) goes through several stages from creation to on-chain settlement. This guide walks through the complete flow.

Status Flow

open → quoted → accepted → confirmed → executed → settled
  ↓       ↓        ↓
expired  cancelled  (MM fails to confirm → cancelled)

Step-by-Step Flow

1

User Creates RFQ

The user submits a parlay bet request with 2-5 legs, each referencing a Kalshi market ticker and a side (yes/no).
POST /rfqs
{
  "legs": [
    { "kalshi_market_ticker": "KXBTC-25FEB07-T100000", "side": "yes" },
    { "kalshi_market_ticker": "KXETH-25FEB07-T3500", "side": "no" }
  ],
  "bet_amount": 100,
  "expires_in_seconds": 300
}
The system validates that each market exists in our cache and is still active on Kalshi, then broadcasts the RFQ to all connected market makers via WebSocket.Status: open
2

Market Makers Submit Quotes

Market makers see the RFQ on the rfqs:open WebSocket channel and submit quotes with their payout odds.
POST /mm/quotes
{
  "rfq_id": "<rfq-uuid>",
  "payout_odds": 4.0,
  "valid_for_seconds": 60
}
The payout is calculated as:
  • total_cost = bet_amount (e.g., $100)
  • total_payout = bet_amount x payout_odds (e.g., $400)
  • mm_payout (MM’s risk) = total_payout - total_cost (e.g., $300)
Status: quoted
3

User Accepts Best Quote

The user reviews quotes (sorted by best payout odds) and accepts one.
PUT /rfqs/<rfq-id>/quotes/<quote-id>/accept
This rejects all other pending quotes and gives the market maker a 5-second confirmation deadline.Status: accepted
4

Market Maker Confirms

The market maker must confirm within 5 seconds, triggering the on-chain vault position creation.
PUT /mm/quotes/<quote-id>/confirm
Status: confirmed
5

On-Chain Vault Position Creation

The system executes a single atomic Solana transaction via the parlay_vaults program. The fee payer covers gas so users and MMs only need USDC in their vaults. User/MM signatures are obtained via Privy TEE wallets.create_position — Both the user’s stake and the MM’s collateral are locked atomically in their persistent vaults. The MM’s collateral is calculated via ILP (Integer Linear Programming) to reflect incremental worst-case exposure across their portfolio, not the full risk amount.The transaction signature and position PDA address are stored in the database and displayed in the UI with links to Solana Explorer.

Vault Architecture

Learn more about the vault architecture, Privy TEE wallet integration, and gas-sponsored transactions.
Status: executed
6

Settlement

A background service polls Kalshi every 30 seconds to check if all leg markets have settled. Settlement transfers funds between vaults and deducts a protocol fee on profit:
  • All legs win — MM’s risk amount (minus fee) is transferred from the MM vault to the user vault (settled_win)
  • Any leg loses — User’s stake (minus fee) is transferred from the user vault to the MM vault (settled_loss)
Status: settled

Background Services

Two background services manage the vault position lifecycle:
  • vault-job-service (every 5s) — Processes pending positions: resolves Privy wallets, calculates ILP exposure, executes create_position
  • vault-settlement-service (every 30s) — Polls market results, settles or cancels active positions based on outcomes

Validation Rules

ParameterConstraint
Legs per parlay2-5
Bet amount11 - 100 USDC
Payout odds1.01x - 1000x
RFQ expiration60 - 3600 seconds
Quote validityConfigurable (default 60s)
MM confirmation window5 seconds