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). optionmust 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); // booleangetInfo() 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.