@sdk.markets/sdk is currently a preview package. These docs show the SDK surface we're building toward.Join the waitlist
markets sdk

Participation

How users buy into a parimutuel market.

Participation in today's contracts is still direct and onchain.

Users stake USDC into one of the market's options. There is no orderbook and no quoted price:

  • no matching engine
  • no secondary exit
  • no inventory token
  • just stake into the shared pool before close

Buy in

The target high-level surface should support:

await client.markets.buyIn({
  marketAddress,
  option: 0,
  amount: parseUsdc("10"),
  approveIfNeeded: true,
});

Instance-style access can still exist underneath:

await market.buyIn({
  option: 0,
  amount: parseUsdc("10"),        // 10 USDC
  approveIfNeeded: true,          // approves first if allowance is insufficient
});

With approveIfNeeded, the SDK reads the current allowance and only issues an approve transaction when necessary. Omit it (or set to false) to manage approvals manually:

import { Erc20Abi } from "@sdk.markets/sdk";

await walletClient.writeContract({
  address: markets.addresses.usdc,
  abi: Erc20Abi,
  functionName: "approve",
  args: [market.address, parseUsdc("100")],  // pre-approve 100 USDC
});

// Later, no approval needed per buyIn:
await market.buyIn({ option: 0, amount: parseUsdc("10") });
await market.buyIn({ option: 1, amount: parseUsdc("25") });

Amounts are bigint in USDC base units (6 decimals). Use parseUsdc("10") to convert from a human value and formatUsdc(amount) to go the other way.

Participation rules

  • The market must be Open (block.timestamp < closeTime).
  • option must be a valid option index (< options.length).
  • amount > 0n.
  • If the market has whitelistEnabled, the caller must be whitelisted.
  • A participant can stake repeatedly, on the same option or across options — each call is additive and per‑option stakes are tracked independently.

The first time a user stakes, they're added to eligibleParticipantCount — the denominator for dispute majority later. Re‑staking doesn't double‑count them.

Reading state

const info = await client.markets.get(marketAddress);
console.log(info.totalPool);                  // bigint — total across all options
console.log(info.optionPools);                // bigint[] — pool per option
console.log(info.options);                    // string[] — option labels

// Odds are implicit in the pool composition.
const oddsYes = Number(info.optionPools[0]) / Number(info.totalPool);

// User-specific view:
const position = await client.markets.getUserPosition({
  marketAddress,
  user: userAddress,
});
console.log(position.totalStake);             // bigint
console.log(position.stakes);                 // bigint[] — per-option stake
console.log(position.isEligibleParticipant);  // boolean

getInfo() and getUserPosition() batch their reads via multicall — one round‑trip each.

Whitelists

When whitelistEnabled: true, only whitelisted addresses can buy in. The creator manages the whitelist. This remains a contract-level flow and should stay available in the direct SDK path:

// Single address
await market.addToWhitelist(userAddress);

// Batch (much cheaper per address than repeated single calls)
await market.addToWhitelist([user1, user2, user3]);

await market.removeFromWhitelist(userAddress);

Removals only affect future buy‑ins. Existing stakes remain, and a removed user stays eligible to dispute, redeem, or refund.

There's no post‑creation flag to disable the whitelist. If you want flexibility, launch with whitelistEnabled: true and add addresses liberally — tightening is always possible, turning it off is not.

On this page