Skip to main content

Account types

MarketAccount

The central account for a prediction market. Exists at the market PDA.
FieldTypeDescription
marketIdbigintAuto-incrementing ID assigned at creation
marketTypenumber0 = YesNo, 1 = MultiOutcome
numOutcomesnumberNumber of outcome options (2 for YesNo, 2-4 for multi)
categorynumberMarket category enum (0-6)
creatorPublicKeyMarket creator
resolverPublicKeyWallet authorized to post the outcome
closeTimebigintUnix timestamp when betting closes
statenumberCurrent state (0=Active, 1=Closed, 2=Resolved, 3=Unresolved, 4=PendingResolution)
totalBetsCountbigintTotal number of bets placed
pool0bigintRevealed pool for outcome 0 (set by MPC callback)
pool1bigintRevealed pool for outcome 1
pool2bigintRevealed pool for outcome 2 (multi only)
pool3bigintRevealed pool for outcome 3 (multi only)
outcomeValuenumberWinning outcome index (set after resolution)
payoutRatiobigintPayout per unit stake × ODDS_SCALE (1e9)
creatorBondbigintLocked bond amount in micro-USDC
minBetbigintMarket-specific minimum bet in micro-USDC
challengePeriodbigintSeconds for the dispute window (v0.2+)
disputedbooleanWhether a flag was raised during challenge window (v0.2+)
resolutionDeadlinebigintTimestamp when refunds become claimable
claimDeadlinebigintTimestamp when claim period ends
inlineQuestionstringQuestion text for v1/v2 (legacy) market accounts
bumpnumberPDA bump seed
For v0.2+ markets (state === 4 ever touched), the question lives in a separate MarketQuestion PDA rather than inline. Use fetchMarketQuestions to hydrate questions in batch.

EncryptedPositionAccount

Records an encrypted bet. Exists at the position PDA keyed by (market, user, betIndex).
FieldTypeDescription
userPublicKeyBettor’s wallet
marketPublicKeyMarket PDA
encryptedAmountUint8Array32-byte ciphertext of the bet stake
encryptedSideUint8Array32-byte ciphertext of the chosen outcome
userPubkeyUint8ArrayBettor’s x25519 public key (needed for decryption)
noncebigintu128 nonce used for encryption (convert to 16 LE bytes to decrypt)
entryOddsbigintLocked-in odds × ODDS_SCALE at bet time
netAmountbigintPlaintext net stake after fees (asserted by circuit)
betIndexbigintIndex of this bet for the (user, market) pair
claimedbooleanWhether payout or refund was claimed
computationQueuedbooleanWhether the MPC computation was queued
bumpnumberPDA bump seed

GlobalStateAccount

Singleton protocol config. There is only one per deployment.
FieldTypeDescription
marketCounterbigintNext market ID to assign
protocolFeeRatenumberProtocol fee in basis points (e.g., 50 = 0.5%)
lpFeeRatenumberLP (creator) fee in basis points (e.g., 150 = 1.5%)
protocolTreasuryPublicKeyWallet receiving protocol fees
acceptedMintPublicKeyUSDC mint accepted by this deployment
adminPublicKeyAdmin wallet for overrides
bumpnumberPDA bump seed

LpPositionAccount

Tracks the creator’s bond and accumulated LP fees per market.
FieldTypeDescription
marketPublicKeyMarket PDA
creatorPublicKeyCreator wallet
bondbigintOriginal bond deposited
lpFeesbigintAccumulated LP fees from all bets
withdrawnbooleanWhether funds have been withdrawn
bumpnumberPDA bump seed

MarketQuestionAccount v0.2+

Stores the question text for v0.2+ markets (separate PDA to save space in MarketAccount).
FieldTypeDescription
marketPublicKeyAssociated market PDA
questionstringFull question text (max 200 bytes)
bumpnumberPDA bump seed

Fetchers

All fetchers are also available as methods on the CypherClient namespaces.
TypeScript
import {
  fetchMarket,
  fetchAllMarkets,
  fetchUserPositions,
  fetchMarketQuestions,
} from "@cypher-zk/sdk";

// Fetch a single market by ID
const market = await client.markets.fetch(42n);

// Fetch all markets
const markets = await client.markets.all();

// Fetch all positions for a user
const positions = await client.positions.byUser(userPublicKey);

// Hydrate questions for a batch of markets (v0.2+)
const questionMap = await fetchMarketQuestions(
  client,
  markets.map((m) => m.publicKey)
);

// Merge questions
const withQuestions = markets.map(({ publicKey, account }) => ({
  publicKey,
  account,
  question: questionMap.get(publicKey.toBase58()) ?? account.inlineQuestion,
}));

Display helpers

TypeScript
import {
  marketPhase,
  marketStateName,
  marketTypeName,
  marketCategoryName,
  cancelEligibility,
  marketFormatVersion,
  parseEmbeddedOptions,
} from "@cypher-zk/sdk";

marketPhase

Returns a human-readable phase string based on the market’s state and timestamps. Use this to drive UI state.
TypeScript
type MarketPhase =
  | "betting"
  | "awaitingResolve"
  | "pendingResolution"
  | "awaitingFinalize"
  | "disputed"
  | "claimable"
  | "refundable"
  | "expired"
  | "cancelled";

const phase = marketPhase(market.account);

cancelEligibility

Pre-flight check before showing a cancel button.
TypeScript
const { ok, reason } = cancelEligibility(market.account);
if (!ok) console.log("Cannot cancel:", reason);

parseEmbeddedOptions

Extracts option labels from a [A|B|C] question suffix.
TypeScript
const labels = parseEmbeddedOptions("Which chain leads TVL? [Solana|Ethereum|Base]");
// ["Solana", "Ethereum", "Base"]

// Map side index to label
const sideLabel = labels[position.side] ?? `Option ${position.side}`;

marketFormatVersion

Detects the market account layout version from byte length.
TypeScript
const version = marketFormatVersion(accountData.length); // "v1" | "v2" | "v3" | null
Legacy v1 and v2 accounts have inline questions; v3 accounts use the MarketQuestion PDA.