npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vercora-protocol/sdk

v0.0.19

Published

TypeScript SDK for the Vercora protocol on Solana

Readme

@vercora-protocol/sdk

TypeScript SDK for the Vercora prediction market protocol on Solana (Anchor).

Install

npm install @vercora-protocol/sdk
# or
yarn add @vercora-protocol/sdk

Peer dependencies (install alongside):

npm install @coral-xyz/anchor @solana/web3.js @solana/spl-token bn.js
# or
yarn add @coral-xyz/anchor @solana/web3.js @solana/spl-token bn.js

Quick start

import * as anchor from "@coral-xyz/anchor";
import { Connection, clusterApiUrl } from "@solana/web3.js";
import { IDL, PROGRAM_ID, PredictionMarketClient } from "@vercora-protocol/sdk";
import type { Vercora } from "@vercora-protocol/sdk";

const connection = new Connection(clusterApiUrl("devnet"));
const provider = new anchor.AnchorProvider(connection, wallet, {});
anchor.setProvider(provider);

// Bundled IDL — program id is embedded in `IDL.address` (`PROGRAM_ID` matches it)
const program = new anchor.Program<Vercora>(IDL, provider);
const client = new PredictionMarketClient(program);

Most transaction methods use provider.wallet.publicKey as the signer (user, authority, creator, etc.). Pass a wallet that can sign; read-only flows can use a read-only provider for fetch helpers only.

Package exports

| Export | Description | | ------------------------ | -------------------------------------------------------------------------------------------- | | PredictionMarketClient | High-level program wrapper (see below). | | IDL, PROGRAM_ID | Anchor IDL JSON and PublicKey for the deployed program. | | pda helpers | deriveMarket, deriveVault, deriveParimutuelState, … (see PDA helpers). | | types | Params and account shapes (CreateMarketParams, ListedMarket, …). | | marketUi | Pure UI helpers (getMarketLifecycleStatus, formatTimeLeft, …). | | Vercora (type) | Anchor Program generic for Program<Vercora>. | | agents/skill.md | Short AI agent entrypoint (production: https://vercora.xyz/agents/skill.md). |


PredictionMarketClient API

Public properties: program, connection, globalConfig (PDA).

Global config (authority)

| Method | Purpose | | ----------------------------------- | ---------------------------------------------- | | initializeConfig(params) | One-time init; authority = connected wallet. | | updateConfig(params) | Update fees, treasury, authorities. |

secondaryAuthority in InitializeConfigParams / UpdateConfigParams: both map to the instruction data field secondary_authority on-chain (not only the secondaryAuthority account meta). Every updateConfig rewrites GlobalConfig.secondary_authority from params.secondaryAuthority. When you only change fees or treasury, pass the existing secondary pubkey you want to keep (from fetchGlobalConfig()); passing the primary key here collapses secondary into primary and removes the backup signer used for platform-only actions (e.g. voiding markets that still hold user liquidity). | addAllowedCollateralMint(mint) | Allowlist a collateral mint. | | removeAllowedCollateralMint(mint) | Remove from allowlist. |

Platforms & categories

| Method | Purpose | | ------------------------------ | ------------------------------------------------------------------------ | | registerPlatform(params) | Next platform_id from GlobalConfig; returns { platformId, sig }. | | createMarketCategory(params) | Next category id per PlatformRegistry (must match next_category_id). | | updateMarketCategory(params) | Rename / toggle active. |

Market creation

| Method | Purpose | | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | createMarket(creator, collateralMint, creatorFeeAccount, params) | Step 1: market + vault. | | initializeMarketResolverSlots(marketPda, params, opts?, parimutuelStateParams?) | Resolver PDAs; optional parimutuelStateParams appends initializeParimutuelState in the same tx. | | initializeMarketOutcomeSlots(marketPda, params) | MarketOutcome labels (complete-set & pari). | | initializeMarketMints(marketPda, marketId) | Mint 8 outcome SPLs (complete-set only). | | initializeParimutuelState(marketPda, params) | Standalone pari pool + penalty params (if not bundled with resolvers). | | createMarketFull(creator, collateralMint, creatorFeeAccount, resolverPubkeys, params) | Runs create → outcomes → resolvers (+ mints or pari state in one flow). | | updateParimutuelState(marketPda, params) | Creator updates penalty split and isEarlyWithdrawAllowed (open pari pool). |

CreateMarketParams (pari-mutuel): optional isEarlyWithdrawAllowed (default true). UpdateParimutuelStateParams requires isEarlyWithdrawAllowed together with penalty fields — creators use updateParimutuelState to change early-withdraw allowance after launch (same instruction as penalty edits; market must still be open and not resolved/voided). When false, early parimutuelWithdraw fails with EarlyWithdrawNotAllowed until close or resolution (voided markets are exempt — full net-stake refunds, no penalty fees). Ignored for complete-set markets. Read fetchMarket(marketPda).isEarlyWithdrawAllowed.

Complete-set trading

| Method | Purpose | | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | mintCompleteSet(user, marketPda, collateralMint, userCollateralAta, platformTreasury, creatorFeeAccount, params, opts?, tokenProgram?) | Mint full set; creates missing outcome ATAs. | | redeemCompleteSet(user, marketPda, collateralMint, userCollateralAta, params) | Burn full set for collateral. | | redeemWinning(user, marketPda, collateralMint, userCollateralAta, params) | After resolution, redeem winning outcome tokens. |

Parimutuel trading

| Method | Purpose | | --------------------------------------- | ------------------------------------------------------- | | parimutuelStake(marketPda, params) | Stake; signer is provider wallet (user on-chain). | | parimutuelWithdraw(marketPda, params) | Early exit (penalty may apply) or, after voidMarket, full net-stake refund (no fees). Early path errors if isEarlyWithdrawAllowed is false; void path ignores that flag. | | parimutuelClaim(marketPda, params) | Claim after resolution. |

Resolution & lifecycle

| Method | Purpose | | ----------------------------------------- | --------------------------------------------- | | voteResolution(marketPda, params) | Resolver vote. | | revokeResolutionVote(marketPda, params) | Clear vote before changing. | | finalizeResolution(marketPda, params) | Anyone, once threshold met. | | closeMarketEarly(marketPda, params) | Creator / config authority before close_at. | | voidMarket(marketPda, params) | Void market. Creator cannot void while pari outcome pools (active stakes) or complete-set outstanding is non-zero — use a global config authority to cancel live markets. Parimutuel: then parimutuelWithdraw for full net refunds. | | claimVoidedParimutuelSurplus(marketPda, params) | Global config authority only. After void, if pari outcome pools are zero but total_pool still holds early-exit pool-keep (no stakers left), sweeps that amount from the vault to the platform treasury. | | abandonMarket(marketPda, params) | Creator abandons empty market (reclaim rent). |

Discovery & reads

| Method | Purpose | | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | fetchGlobalConfig() | Global config account. | | fetchMarket(marketPda) | Market account. | | fetchAllMarkets(platformId?) | All markets (optional memcmp on platform_id); includes outcome labels. | | fetchMarketsByPlatform(platformId) | Same as fetchAllMarkets(platformId). | | fetchVoidedMarkets() | Market accounts with is_voided only (RPC memcmp + dataSize). | | fetchVoidedParimutuelSurplusCandidates() | Subset: voided pari, not resolved, sum(outcome_pools)=0, total_pool > 0 (claimable). | | fetchMarketsByCreator(creator) | Raw rows { pubkey, account }[], memcmp on creator. | | getUsersMarkets(creator, filters?) | ListedMarket[] for creator; optional platformId (RPC) + categoryId (client filter). | | fetchMarketOutcomeLabels(marketPda, outcomeCount) | Outcome labels. | | fetchVaultBalance(marketPda) | Vault balance (bigint base units). | | fetchOutcomeBalance(marketPda, user, outcomeIndex) | Single outcome token balance (complete-set). | | fetchAllOutcomeBalances(marketPda, user, outcomeCount) | All outcome balances for user. | | fetchMarketCategory(categoryPda) | One category. | | fetchAllMarketCategories() | All categories (sorted). | | fetchResolutionVote(marketPda, resolverIndex) | Vote PDA or null. | | fetchMarketOutcomesSnapshot(marketPda, outcomeCount) | Decoded outcomes + tallies. | | fetchOutcomeTallyCounts(marketPda) | Quick tally array. | | fetchAllowedCollateralMints() | Allowlist mints. | | fetchUserProfile(wallet) | User profile or null. | | fetchPlatformProfile(platformId) | Platform profile or null. | | fetchParimutuelState(marketPda) | Pari pool state. | | fetchParimutuelPosition(marketPda, user, outcomeIndex) | Position or null. | | fetchParimutuelActiveStakesBatch(marketPda, user, outcomeCount) | Active stakes per outcome. | | computeParimutuelOdds(state, outcomeCount) | Implied probs + payout multipliers. | | fetchResolver(marketPda, index) | One resolver account. | | fetchAllResolvers(marketPda, numResolvers) | Initialized resolver slots. |

Profiles

| Method | Purpose | | ---------------------------------- | ------------------------------------------- | | upsertUserProfile(params) | Display name / URL. | | closeUserProfile() | Close caller’s profile. | | verifyUserProfile(params) | Verifier marks verified. | | upsertPlatformProfile(params) | Platform profile (scoped by platform_id). | | closePlatformProfile(platformId) | Close profile. | | verifyPlatformProfile(params) | Verify platform profile. |


Examples

Global config (first deploy)

import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";

await client.initializeConfig({
  // System program / “none” placeholder — use a real secondary authority pubkey in production
  secondaryAuthority: new PublicKey("11111111111111111111111111111111"),
  depositPlatformFeeBps: 100,
  platformTreasuryWallet: treasuryPubkey,
  platformFeeLamports: new BN(357_000),
  parimutuelWithdrawPlatformFeeBps: 50,
});

Register platform & category

const { platformId } = await client.registerPlatform({
  profileAuthority: profileSignerPubkey,
});

await client.createMarketCategory({
  platformId,
  name: "Politics",
});

Create a market (manual steps, complete-set)

import BN from "bn.js";

const marketId = new BN(Date.now());
const { marketPda } = await client.createMarket(
  creatorPubkey,
  collateralMint,
  creatorFeeAta,
  {
    marketId,
    outcomeCount: 2,
    resolutionThreshold: 1,
    closeAt: new BN(Math.floor(Date.now() / 1000) + 86400),
    creatorFeeBps: 50,
    depositPlatformFeeBps: 0,
    numResolvers: 1,
    maxOutcomeInvestment: new BN(0),
    title: "Will it rain tomorrow?",
    marketType: "completeSet",
    platformId: new BN(0),
    categoryId: new BN(0),
  },
);

await client.initializeMarketOutcomeSlots(marketPda, {
  marketId,
  labels: ["Yes", "No"],
});
await client.initializeMarketResolverSlots(marketPda, {
  marketId,
  resolverPubkeys: [resolverPubkey],
});
await client.initializeMarketMints(marketPda, marketId);

Create market in one call (createMarketFull)

Complete-set (mints outcome tokens):

const marketPda = await client.createMarketFull(
  creatorPubkey,
  collateralMint,
  creatorFeeAta,
  [resolverPubkey],
  {
    marketId,
    outcomeCount: 2,
    resolutionThreshold: 1,
    closeAt: new BN(Math.floor(Date.now() / 1000) + 86400),
    creatorFeeBps: 50,
    depositPlatformFeeBps: 0,
    numResolvers: 1,
    maxOutcomeInvestment: new BN(0),
    title: "Two-outcome market",
    marketType: "completeSet",
    outcomeLabels: ["Yes", "No"],
  },
);

Parimutuel (resolver tx also initializes pari state; optional parimutuelInit overrides defaults):

const marketPda = await client.createMarketFull(
  creatorPubkey,
  collateralMint,
  creatorFeeAta,
  [resolverPubkey],
  {
    marketId,
    outcomeCount: 2,
    resolutionThreshold: 1,
    closeAt: new BN(Math.floor(Date.now() / 1000) + 86400),
    creatorFeeBps: 50,
    depositPlatformFeeBps: 0,
    numResolvers: 1,
    maxOutcomeInvestment: new BN(0),
    title: "Pari pool",
    marketType: "parimutuel",
    outcomeLabels: ["A", "B"],
    // Optional — default true. Set false to lock stakes until close/resolution (no early parimutuelWithdraw).
    isEarlyWithdrawAllowed: true,
    parimutuelInit: {
      earlyWithdrawPenaltyBps: 500,
      penaltyKeptInPoolBps: 8000,
    },
  },
);

Complete-set trading

const treasury = (await client.fetchGlobalConfig()).platformTreasury;

await client.mintCompleteSet(
  userPubkey,
  marketPda,
  collateralMint,
  userCollateralAta,
  treasury,
  creatorFeeAta,
  { marketId, amount: new BN(1_000_000) },
);

await client.redeemCompleteSet(
  userPubkey,
  marketPda,
  collateralMint,
  userCollateralAta,
  { marketId },
);

await client.redeemWinning(
  userPubkey,
  marketPda,
  collateralMint,
  userCollateralAta,
  {
    marketId,
    amount: winningAmountBn,
  },
);

Parimutuel trading

Signer is always the connected wallet (no user first argument):

await client.parimutuelStake(marketPda, {
  marketId,
  outcomeIndex: 0,
  amount: new BN(500_000),
});

await client.parimutuelWithdraw(marketPda, {
  marketId,
  outcomeIndex: 0,
  amount: new BN(500_000),
});
// If Market.isEarlyWithdrawAllowed is false (from create or updateParimutuelState), parimutuelWithdraw throws EarlyWithdrawNotAllowed — unless the market is voided (then full net stake back, no fees).

// After voidMarket on a pari pool, recover stakes (repeat per outcome / until active stake is 0):
// await client.voidMarket(marketPda, { marketId });
// await client.parimutuelWithdraw(marketPda, { marketId, outcomeIndex: 0, amount: userActiveStakeBn });

await client.parimutuelClaim(marketPda, {
  marketId,
  outcomeIndex: 0,
});

const state = await client.fetchParimutuelState(marketPda);
const odds = client.computeParimutuelOdds(state, 2);

Creator: update penalty split and early withdraw (updateParimutuelState)

Only the market creator can call this while the market is open (not resolved/voided). Pass current penalty bps from fetchParimutuelState and isEarlyWithdrawAllowed from fetchMarket when you only want to toggle early exit:

const m = await client.fetchMarket(marketPda);
const pari = await client.fetchParimutuelState(marketPda);

await client.updateParimutuelState(marketPda, {
  marketId,
  earlyWithdrawPenaltyBps: pari.earlyWithdrawPenaltyBps,
  penaltyKeptInPoolBps: pari.penaltyKeptInPoolBps,
  isEarlyWithdrawAllowed: false, // block parimutuelWithdraw until close/resolution
});

// Re-enable early exit later:
await client.updateParimutuelState(marketPda, {
  marketId,
  earlyWithdrawPenaltyBps: pari.earlyWithdrawPenaltyBps,
  penaltyKeptInPoolBps: pari.penaltyKeptInPoolBps,
  isEarlyWithdrawAllowed: true,
});

Resolution

await client.voteResolution(marketPda, {
  marketId,
  resolverIndex: 0,
  outcomeIndex: 1,
});

await client.finalizeResolution(marketPda, { marketId });

Discovery

// Every market (heavy on RPC)
const all = await client.fetchAllMarkets();

// By platform (memcmp)
const byPlatform = await client.fetchAllMarkets(new BN(1));

// Markets created by a wallet — full rows with labels + filters
const mine = await client.getUsersMarkets(creatorPubkey, {
  platformId: new BN(1), // optional RPC filter
  categoryId: 2, // optional; applied after decode
});

// Raw accounts only (no labels)
const raw = await client.fetchMarketsByCreator(creatorPubkey);

User profile

await client.upsertUserProfile({
  displayName: "Alice",
  url: "https://example.com",
});

const profile = await client.fetchUserProfile(wallet.publicKey);

Platforms and categories

On-chain, platform_id is u32 and category_id is u8 in CreateMarketArgs (not pubkeys).

  1. register_platform — assigns the next id from GlobalConfig.next_platform_id; PDA ["platform", platform_id le u32].
  2. create_market_categorycategory_id must equal PlatformRegistry.next_category_id before bump; PDA ["market-category", platform_id, category_id].
  3. create_market — if platform_id == 0 then category_id must be 0. If platform_id > 0, pass platform_registry; if category_id > 0, pass market_category.

Use derivePlatformRegistry, derivePlatformProfile, deriveMarketCategory when building instructions manually.

Market types

Use marketType: 'parimutuel' or 'completeSet' at creation; the choice is permanent.

  • Parimutuel — pooled stakes, no outcome SPLs; good default for prediction apps. isEarlyWithdrawAllowed is set at create (default allowed) and can be changed by the creator via updateParimutuelState; when disabled, early parimutuelWithdraw is blocked until close or resolution. After voidMarket, participants parimutuelWithdraw full net stakes (no penalty / withdraw fees).
  • Complete-set — outcome SPL tokens; you still need external liquidity for single-leg trading.

PDA helpers

From @vercora-protocol/sdk:

import {
  PROGRAM_ID,
  deriveGlobalConfig,
  deriveAllowedMint,
  deriveMarket,
  deriveVault,
  deriveOutcomeMint,
  deriveAllOutcomeMints,
  deriveResolver,
  deriveAllResolvers,
  deriveResolutionVote,
  deriveMarketOutcome,
  deriveAllMarketOutcomes,
  deriveParimutuelState,
  deriveParimutuelPosition,
  deriveUserProfile,
  derivePlatformRegistry,
  derivePlatformProfile,
  deriveMarketCategory,
  bnLike,
  bnToU32,
  bnToU8,
} from "@vercora-protocol/sdk";

const marketPda = deriveMarket(PROGRAM_ID, creatorPubkey, marketId);
const vaultPda = deriveVault(PROGRAM_ID, marketPda);

Offsets MARKET_ACCOUNT_CREATOR_MEMCMP_OFFSET, MARKET_ACCOUNT_PLATFORM_ID_MEMCMP_OFFSET, and MARKET_ACCOUNT_IS_VOIDED_MEMCMP_OFFSET are exported for custom getProgramAccounts filters. Use marketIsVoidedMemcmp(true) for the Borsh-encoded bool bytes at that offset. fetchVoidedMarkets / fetchVoidedParimutuelSurplusCandidates apply the voided filter so listing cost scales with voided markets only.

marketUi helpers

import {
  getMarketLifecycleStatus,
  formatTimeLeft,
  listedMarketFeedTag,
} from "@vercora-protocol/sdk";

const status = getMarketLifecycleStatus({
  isVoided: false,
  isClosedEarly: false,
  winningOutcomeIndex: null,
  closeAt: ts,
});

TypeScript types

import type {
  CreateMarketParams,
  UpdateParimutuelStateParams,
  ListedMarket,
  GetUsersMarketsFilters,
  MarketAccount,
  ParimutuelStateAccount,
  ParimutuelOdds,
  GlobalConfigAccount,
  UserProfileAccount,
} from "@vercora-protocol/sdk";

AI agent integration

Start from agents/skill.md in this package for a stable entrypoint; the full playbook is at https://vercora.xyz/agents/playbook.md (production), or docs/AI-AGENT-SDK-PLAYBOOK.md in the monorepo.

  1. Bootstrap: ConnectionAnchorProviderProgram<Vercora> from IDLPredictionMarketClient.
  2. Branch: fetchMarketmarket.marketType (completeSet vs parimutuel).
  3. Flows:
    • Optional: registerPlatformcreateMarketCategorycreateMarket with ids.
    • Create: createMarketFull or createMarket + resolver / outcome / mint or pari init.
    • Complete-set: mintCompleteSetredeemCompleteSetredeemWinning.
    • Parimutuel: parimutuelStake → optional parimutuelWithdraw (if isEarlyWithdrawAllowed, or after voidMarket for full refunds) → parimutuelClaim; creator may toggle early withdraw with updateParimutuelState (includes penalty fields).
    • Resolution: voteResolutionfinalizeResolution.
  4. Discovery: fetchAllMarkets, getUsersMarkets, fetchMarketsByCreator, fetchVoidedMarkets, fetchVoidedParimutuelSurplusCandidates.
  5. Safety: verify signers, PDAs, ATAs, and RPC limits on getProgramAccounts.

Changelog

See CHANGELOG.md in the package (published to npm). Releases are generated with standard-version from Conventional Commits in app/sdk (e.g. feat:, fix:). After running a release script you can edit CHANGELOG.md or amend the release commit before npm publish.

Releasing (maintainers)

From prediction_market/app/sdk:

  1. Commit SDK work with conventional messages so the next bump has sensible notes.
  2. npm run release:check — confirms package.json version matches git tag v<version> (follow the script’s hints if not).
  3. npm run release:patch, release:minor, or release:major — bumps version, updates CHANGELOG.md, creates a release commit, and tags vX.Y.Z.
  4. Adjust CHANGELOG.md or message if needed (git commit --amend or a follow-up commit), then npm publish.

Preview without writing: npx standard-version --dry-run --release-as patch (only after release:check passes).

Links