Skip to main content
PredictStreet is built around a deliberate split: the hot path is off-chain for sub-second trading latency, and custody and settlement are on-chain so nothing moves without a user’s EIP-712 signature against a dedicated vault contract they control.

System diagram

Off-chain services

core-api

Client-facing HTTP gateway. Partner traffic authenticates with X-Api-Key on core.api.dev.predictstreet.sde.adifoundation.ai; retail user sessions (SIWE) live on a separate surface, app.predictstreet.io, and are out of scope for this documentation. Rate limits, geo and compliance guards, KYC gating. Every request enters here before being routed to the appropriate back-end. Owns compliance screening (Global Ledger), sanctions, banned-wallet checks, and cleared deposit-sources enforcement. See Authentication overview and API keys.
Orders, balances, trades, fees, withdrawals. PostgreSQL-backed single source of truth for off-chain state. Verifies EIP-712 signatures, locks balance, calls matching-core over gRPC, persists results, publishes events to NATS JetStream.
In-memory central-limit orderbook engine (Go). One engine per market. Implements FIFO priority within a price level; supports GTC / IOC / FOK time-in-force and LIMIT / MARKET order types. Stateless from a client perspective — exchange-service holds authoritative PG state; matcher state is warm-restartable.
Polls three independent sports data providers (Stats Perform primary + API-Football + Sportmonks), evaluates consensus (3-of-3 auto-proposes; 2-of-3 blocks unless the discrepancy is explainable against the primary source), and posts outcomes on-chain via PredictStreetOracle.proposeOutcome. Handles the 2-hour challenge window, override, void, and delayed-data paths. See Settlement overview.
Broadcasts matched trades on-chain in batches. Maintains a pool of pre-funded operator EOAs (whitelisted via CTFExchange.addOperator() on both binary and neg-risk exchanges), an atomic per-wallet nonce manager, and a tx-tracker that polls receipts and reclassifies stuck or dropped transactions. A gas-refiller cron tops up operator wallets from a treasury address. On a full revert, trades are marked settlement_failed; per-order failures come in via MatchFailed events from chain-watcher.
WebSocket fan-out. Consumes NATS JetStream events from exchange-service and oracle-service and multiplexes channels. Handshake auth accepts both X-Api-Key (partners) and Bearer JWT (retail SIWE) on /ws/user AND /ws/market — same two schemes as HTTP, same scope rules. Neither gateway is open: a handshake without a key or token closes 1008 unauthorized. See WebSocket overview.
Ponder-based indexer for every PredictStreet contract (Exchange, ConditionalTokens, NegRiskAdapter, VaultFactory, Oracle). Persists events in durable outbox tables and publishes them to NATS JetStream (chain.> subjects) with at-least-once delivery. Handles seq-gap recovery and reorg rewind. Internal — partners consume confirmed state through core-api / WebSocket, not directly from chain-watcher.

On-chain contracts

User Vault (EIP-1167 clone)

One minimal-proxy clone per user, deployed through VaultFactory on first deposit. Holds the user’s ERC-20 collateral (USDC) and ERC-1155 outcome positions. Non-upgradeable — the implementation is pinned and never swapped under existing vaults.Custody model: withdrawals, split / merge, and neg-risk convertPositions require a dual EIP-712 signature (vault owner
  • factory owner). The backend cannot move user funds unilaterally. An emergency-withdraw path gives the owner unilateral access with a 7-day on-chain timelock.
Matches and settles signed orders. Implements the PS-QUADRATIC-V1 taker-fee curve fee = k × P × (1−P) per Fees. Admin-gated for pause / unpause / registerToken / setVaultFactory; operator-gated for fillOrder / matchOrders.
Polymarket-compatible ERC-1155 position tokens. prepareCondition registers a new market condition; position IDs are deterministic from (collateral, conditionId, indexSet). Oracle-service calls prepareCondition as part of market deployment.
Separate deployment path for multi-outcome categorical markets (e.g. 3+ exclusive outcomes). Reuses the same EIP-712 order shape as the binary exchange; differences are in the position-token derivation and convertPositions for NO-basket → collateral conversions.
Single on-chain oracle contract. Oracle-service is its only authorized writer for proposeOutcome / finalizeOutcome / resolveChallenge* / voidMarket / markDelayed. Enforces a 10 USDC challenger bond and a 2-hour challenge window; emergency proposal clear is gated by a 7-day admin timelock. See Settlement flow.

The hot path in one paragraph

A partner calls POST /api/orders/place with an EIP-712-signed order. core-api verifies the X-Api-Key header, runs compliance guards, and forwards to exchange-service. exchange-service verifies the EIP-712 signature against the expected signer EOA (matching the vault owner for SignatureType.VAULT), locks the required quote notional (available → locked), persists the order row, and calls matching-core over gRPC. matching-core runs the book, returns fills synchronously. exchange-service writes the trade rows + fee ledger in a single PG transaction, publishes events to NATS, and returns the response. No on-chain transaction happens here. Trades are picked up from the trades table by match-submitter, which batches them into fillOrder / matchOrders calls against CTFExchange (or the neg-risk exchange), signed by an operator EOA from its wallet pool. chain-watcher sees the resulting OrderFilled / MatchFailed events and notifies exchange-service to finalize the trade state.

Strict vs optimistic settlement

PredictStreet uses a strict settlement model: a trade row is persisted immediately after match, but the user’s balance is only decremented from locked after on-chain confirmation from chain-watcher. The upside is simpler revert semantics (a reverted chain tx simply refunds locked → available) and no need for an unsettled balance bucket. The tradeoff is a small settlement delay between match and the balance update being visible as “available” again.

What partners own vs what PredictStreet owns

ConcernWho owns it
User custody of USDC + outcome tokensUser (via their vault)
EIP-712 keyUser (or their delegated signer)
API-key issuance + session lifecyclePredictStreet (core-api)
Balance bookkeeping off-chainPredictStreet (exchange-service)
Orderbook state (hot)PredictStreet (matching-core, in-memory)
Final settlement ledgerOn-chain — ConditionalTokens / CTFExchange / Vault
Oracle resolution proposalPredictStreet (oracle-service)
Oracle challenge (dispute)User (via on-chain bond)
Fee configurationPredictStreet (admin-api — changes require audit trail)
The rule of thumb: anything that moves money is on-chain with a user signature. Everything else is off-chain for speed.

Next

Authentication

X-Api-Key format, scope taxonomy, and rotation.

Order lifecycle

State machine and transition rules.

Contracts reference

Deployed addresses, ABIs, invariants.

Environments

Testnet, staging, mainnet endpoints.