Skip to main content
v0.8.9
Feature
Current release
Friendlier read-only wallet error. readonlyWallet now throws a typed ReadonlyWalletError instead of a generic Error, with a user-friendly message and a stable code for programmatic detection.
  • New export: ReadonlyWalletError (code === "READONLY_WALLET", name === "ReadonlyWalletError").
  • New default message: "Wallet is read-only. Connect a wallet before sending a transaction."
  • Detect the case with err instanceof ReadonlyWalletError to show a “connect wallet” prompt instead of leaking the SDK detail to your user.
v0.8.8
Feature
RPC batching layer. New src/rpc/ module that chunks bulk reads past Solana’s 100-key getMultipleAccountsInfo cap, runs with bounded concurrency, and retries transient errors (429 / 5xx / network blips) with exponential backoff. Fixes the practical bug where fetchMarketQuestions broke once a deployment had more than 100 markets.
  • New low-level helper: batchedGetMultipleAccountsInfo(connection, pubkeys, overrides?).
  • New CypherClientOptions.rpcOptions?: Partial<BatchOptions> — tune chunkSize, concurrency, retries, retryBaseMs per client. Conservative defaults (chunkSize 100, concurrency 5, retries 3) survive free-tier RPCs; bump concurrency on paid plans.
  • New paginated fetcher: fetchMarketsByIds(client, ids[]) / client.markets.byIds(ids) — fetch a known list of markets without pulling the entire program payload. Preferred over .all() once the program has more than a few hundred markets.
  • client.marketQuestions.fetchMany(markets) — exposes the existing batch helper on the client surface, now routed through the chunked fetcher.
  • React: useMarkets({ ids }) filter mode that routes to byIds.
  • React: useMarketQuestions(markets) — TanStack-Query wrapper over fetchMany with a 60s stale time (questions are immutable after market creation).
  • New query-key factory: marketQuestionKeys.byMarkets(pdas) for manual invalidation.
v0.8.7
FeatureBreaking
Multi-bet support. Users can now hold multiple positions per market. Each bet gets an auto-incrementing betIndex.
  • placeBetAction reads user_state.next_bet_index automatically and retries up to 3 times on concurrent-bet index conflicts.
  • ClaimInputs and useClaimPayout / useClaimRefund now accept betIndex (defaults to 0n).
  • EncryptedPositionAccount adds betIndex: bigint field.
  • saveSecret(market, betIndex, privateKey) - signature changed to include betIndex.
  • positionPda(market, user, betIndex?) - betIndex defaults to 0n.
Separate MarketQuestion PDA. Question text for new markets moves to a dedicated account to save space in MarketAccount.
  • Use fetchMarketQuestions(client, marketPublicKeys) to hydrate questions in batch.
  • Legacy markets still have account.inlineQuestion.
  • marketFormatVersion(accountSize) returns "v1" | "v2" | "v3" | null.
Challenge window. Dispute resolution system added.
  • New actions: flagResolutionAction, finalizeResolutionAction, adminOverrideResolutionAction.
  • New React hooks: useFlagResolution, useFinalizeResolution, useAdminOverrideResolution.
  • New events: ResolutionFlaggedEvent, MarketFinalizedEvent, ResolutionOverriddenEvent.
  • Markets pass through PendingResolution (state 4) between reveal and claim.
  • New constants: MIN_CHALLENGE_PERIOD_SECS (24h), MAX_CHALLENGE_PERIOD_SECS (48h).
v0.8.6
Breaking
Breaking change. The betIndex parameter was removed from the low-level placePrivateBetYesnoIx and placePrivateBetMultiIx instruction builders. The on-chain user_state PDA now tracks next_bet_index automatically.
  • userStatePda(user) - new PDA for per-user bet index counter.
  • readNextBetIndex(client, user) - helper to fetch the current index when building low-level instructions. Not needed if you use placeBetAction.
  • High-level placeBetAction handles index tracking and retries automatically - no changes needed for callers using client.actions.placeBet.
v0.8.5
Fix
Position decoder fix. fetchUserPositions (and client.positions.byUser) now correctly handles mixed legacy 208-byte and current 216-byte position accounts.
  • Previously, a single legacy account in the result set would cause the entire query to fail silently (returning zero positions).
  • The fix uses per-account size-aware decoding instead of Anchor’s all-or-nothing decoder.
v0.8.0 and earlier
  • One position per user per market (no betIndex).
  • saveSecret(market, secret) took two arguments (no betIndex).
  • Questions always stored inline in MarketAccount.inlineQuestion.
  • No challenge window - markets moved directly from PendingResolution to Resolved after the MPC callback.