Skip to content

Liquidity Provision

Oracle uses a pure Central Limit Order Book (CLOB) — no AMM, no shared liquidity pools, no LP vaults with share tokens. Liquidity comes from resting limit orders, and the protocol incentivizes LPs in two ways:

  1. Maker rebates — paid per fill, funded from the taker fee. Instant.
  2. Liquidity rewards — a daily USDC budget per market, awarded to wallets that held tight two-sided quotes. Extended quadratic scoring: multi-level depth, gold-band bonus, super-linear uptime weighting, anti-spoofing clamp, 40% per-wallet cap.

Both programs run independently. Any resting order is automatically eligible for both — no opt-in, no vault deposits.


1. Maker Rebates

Every fill on Oracle pays a rebate to the resting (maker) side. Rebates settle into the maker's usdc_balance at match time — spendable immediately, no claim step.

Fee split per fill

Party Flow
Taker Pays taker_fee_bps on notional (default 2%)
Maker Receives maker_rebate_bps of notional (default 0.5%)
Treasury Receives the remainder

Calculation

taker_fee    = floor(fill_size × fill_price × taker_fee_bps    / 10_000)
maker_rebate = floor(fill_size × fill_price × maker_rebate_bps / 10_000)

fill_price is in micro-USDC per outcome token (6 decimals). fill_size is outcome tokens.

Example — fill 1,000 YES @ $0.65, default bps:

  • Taker pays: 1,000 × 650,000 × 200 / 10,000 = 13,000,000 µUSDC = $13.00
  • Maker earns: 1,000 × 650,000 × 50 / 10,000 = 3,250,000 µUSDC = $3.25

Who earns it

Only orders that rest on the book and get matched by an incoming taker earn the rebate. A GTC limit order that sits and gets filled: rebate. A market order (IOC) that crosses the spread: no rebate — it's the taker. Partial fills pay pro-rata.

Changing fees

Fees are read live from FeeConfig on oracle-vault. Changes require an admin tx and are announced ≥24h in advance.


2. Liquidity Rewards

A daily per-market USDC budget is distributed to wallets that hold resting orders inside a configured spread band. The Oracle scoring formula extends a quadratic distance base with five mechanics that reward real depth, uptime, and two-sided balance — and punish spoofing and whale capture.

Per-sample scoring

Every 30 seconds the engine snapshots each market's order book. For each wallet with resting orders, compute:

(a) Per-order distance (quadratic base). For every resting order inside max_spread_bps:

order_score = size × ((max_spread − distance_from_mid) / max_spread)² × in_game_multiplier

A quote at mid earns size × multiplier. Halfway to the band → 25% (0.5²). At the boundary → 0.

(b) Multi-level depth. Sum across every resting order on the side, with a per-level decay by rank-from-mid. Rewards real depth, not just a single tight quote:

side_score = Σ order_score(o) × level_decay(rank(o))
level_decay(rank) = 1 / (1 + 0.5 × rank)      // 1.00 / 0.67 / 0.50 / 0.40 / …

(c) Gold-band bonus. Orders within the tightest 25% of max_spread get a 1.5× multiplier on top of the quadratic.

(d) Combined sides (single-sided penalty).

combined = max( min(bid_score, ask_score),  max(bid_score, ask_score) / c )
c = 2         // stricter than the c=3 used elsewhere; single-sided = 50% credit

Symmetry bonus: if |bid − ask| / max ≤ 0.20, multiply combined by 1.10.

Daily aggregate

uptime = active_samples / 2880        // active = non-zero combined score
daily_score = (Σ sample_scores) × uptime^0.8

Super-linear uptime penalty (uptime 95% → ×0.96, 80% → ×0.83, 50% → ×0.57).

Anti-spoofing clamp: a wallet's cancel_ratio over a rolling 5-min window = cancels / (cancels + fills). If > 0.50 with any cancels, every sample in that window is scored ×0.5.

Daily distribution

At 00:00 UTC, pro-rata by daily_score, then cap at 40% per wallet:

raw_payout(w)   = daily_score(w) / Σ daily_scores × daily_budget_usdc
max_share       = daily_budget_usdc × 0.40
final_payout(w) = min(raw_payout(w), max_share)

Any undistributed remainder from cap enforcement rolls into the next day's budget.

Credits accumulate in a wallet-level claimable_micro_usdc — a single balance across every market.

Per-market configuration

Each market has its own max_spread_bps, min_size, daily_budget_usdc, in_game_multiplier. See GET /v1/rewards/config. Markets without a config earn nothing.


3. Claim Flow

Reward credits are distinct from wallet balance. Claiming moves USDC from the fee treasury (on Fogo) to the user's proxy wallet USDC ATA.

On-chain plumbing

  • Vault instruction: claim_rewards on oracle-vault (Fogo)
  • Signer: the vault PDA [b"vault"] (CPI-signed transfer)
  • Authority: operator only (relayed — user doesn't pay gas)
  • Source: fee_treasury USDC token account
  • Destination: ATA of the user's proxy_wallet PDA [b"proxy", user]

API

POST /admin/rewards/claim
X-Admin-Key: <admin key>

{
  "wallet": "<bs58 user pubkey>",
  "amount_micro_usdc": 5000000         // optional; defaults to full claimable
}

Response (200):

{
  "claimed_micro_usdc": 5000000,
  "remaining": 400000,
  "signature": "5Kx8..."
}

The signature is the Fogo tx. remaining reflects claimable_micro_usdc after the decrement; the decrement is atomic and clamps at zero (never negative, even on over-claim).

Failure mode: tx succeeds, Redis decrement fails

If the on-chain tx lands but the Redis decrement errors, the response is still 200 with remaining: null and a warning field flagging manual reconciliation. The funds are delivered on-chain; only the accounting counter is out of sync. Operator must reconcile manually.

Public self-service endpoint

Not yet shipped. Today all claims are operator-relayed and admin-key-gated. Market makers running continuous strategies should arrange scheduled sweeps with the Parti team.


4. Running a Market Maker

The reference market-making bot is oracle-lp (Rust). It:

  • Subscribes to the order-book WebSocket
  • Maintains symmetric two-sided quotes around mid, scaled by spread_bps and size
  • Cancels and re-posts when mid moves > requote_bps
  • Tracks inventory per market, skews the constrained side on drift

Typical loop (pseudocode)

while True:
    book = GET /v1/markets/{id}/book
    mid  = book["yes_price"]                   # micro-USDC per token

    # Cancel existing resting orders
    POST /v1/orders/cancel-all  { market_id, user, signature, nonce }

    # Re-post inside the rewards band
    for offset_bps in [spread_bps, spread_bps*2, spread_bps*3]:
        POST /v1/orders  {
            side: "buy",  outcome: "yes",
            price: max(1, mid - offset_bps),
            size: N,  order_type: "gtc",
            signature, nonce
        }
        POST /v1/orders  {
            side: "sell", outcome: "yes",
            price: min(9999, mid + offset_bps),
            size: N,  order_type: "gtc",
            signature, nonce
        }

    sleep(5)

Order type is gtc (not post_only) because cancel-all runs before each rebalance, so there are no stale LP orders to cross with.

Picking spread_bps

Quote inside the market's max_spread_bps — quotes outside earn rebates on fills but score 0 for rewards. Rule of thumb: spread_bps ≈ max_spread_bps / 4 for the tightest level, widening geometrically.

Key endpoints for market makers

Endpoint Use
GET /v1/markets/{id}/book Current order book state
POST /v1/orders Place orders (gtc or post_only)
POST /v1/orders/cancel-all Bulk cancel before requoting
WS book:{market_id} Real-time book updates
GET /v1/rewards/config Per-market max_spread_bps, min_size, daily_budget
GET /v1/rewards/leaderboard?market_id= Current-day scoreboard
GET /v1/rewards/wallet/{wallet} Cumulative claimable balance

5. Deposit & Operational Limits

Market makers hold significant inventory. The protocol enforces per-tx and aggregate bridge caps — see Deposits & Withdrawals for the full table. Summary:

Tier Max USDC per bridge tx
Retail (default) 10,000
LP 1,000,000
Institutional 10,000,000

Plus a global 100,000 USDC/day bridge aggregate cap across all users. Native Fogo deposits (if you're already on-chain) bypass both limits.

Tier upgrade is a single on-chain tx: POST /admin/bridge/user-tier with tier: 1 (LP) or tier: 2 (institutional).


6. Why CLOB, not AMM

  1. Correct price discovery — prediction markets have binary terminal values, so LP-against-AMM strategies bleed to informed traders. A CLOB lets makers step back when they're out-gunned.
  2. Risk isolation — one market's volatility doesn't affect another's liquidity.
  3. LP control — makers choose exactly which markets to provide on, at what spread, with what size.
  4. Capital efficiency — no idle depth in deep out-of-the-money bands; capital quotes where the flow is.