PNP SDK API Reference (Solana)

February 26, 2026 · View on GitHub

Complete method signatures and parameter documentation for the PNP Protocol SDK on Solana. All signatures verified against pnp-sdk source.

Installation

npm install pnp-sdk @solana/web3.js

PNPClient — Initialization

import { PNPClient } from 'pnp-sdk';

// Read-only client (no transactions, only data fetching)
const readOnlyClient = new PNPClient('https://api.mainnet-beta.solana.com');

// Full client with signing capabilities
const client = new PNPClient(
  'https://api.mainnet-beta.solana.com',
  process.env.PRIVATE_KEY  // Base58 encoded private key
);
ParameterTypeRequiredDescription
rpcUrlstringYesSolana RPC endpoint URL
privateKeystringNoBase58 private key (omit for read-only)

Static Utilities

// Parse private key from Base58 string or JSON array format
const keypair = PNPClient.parseSecretKey(process.env.PRIVATE_KEY);

// Convert human-readable amount to raw bigint
const raw = client.uiToRaw(100, 6);  // 100 USDC → 100_000_000n

// Detect social media URLs in question text
PNPClient.detectTwitterUrl('Will this tweet go viral? https://x.com/user/status/123');
PNPClient.detectYoutubeUrl('Will this video hit 1M? https://youtu.be/abc123');
PNPClient.detectDefiLlamaUrl('Will Uniswap TVL exceed \$5B?');

Market Creation

market.createMarket(params) — V2 AMM Market

Creates a standard V2 AMM market using PNP's global oracle for resolution.

const { market, signature } = await client.market.createMarket({
  question: 'Will BTC hit \$150K by end of 2026?',
  endTime: BigInt(Math.floor(Date.now() / 1000) + 86400 * 30),
  initialLiquidity: 100_000_000n,  // 100 USDC (6 decimals)
  baseMint: new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
});
ParameterTypeRequiredDescription
questionstringYesThe prediction question
initialLiquiditybigintYesCollateral in raw units (decimals depend on chosen token)
endTimebigintYesUnix timestamp when trading ends
baseMintPublicKeyNoCollateral token mint — any SPL or Token-2022 token

Returns: { market: PublicKey, signature: string }

createMarketWithCustomOracle(params) — Custom Oracle Market

Creates a market where the specified wallet acts as the settlement oracle.

const { market, signature } = await client.createMarketWithCustomOracle({
  question: 'Will ETH merge upgrade succeed?',
  initialLiquidity: 10_000_000n,
  endTime: BigInt(Math.floor(Date.now() / 1000) + 86400 * 7),
  collateralMint: new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
  settlerAddress: oracleWalletPubkey,
  yesOddsBps: 5000,  // Optional: 50/50 (range: 100-9900)
});
ParameterTypeRequiredDescription
questionstringYesThe prediction question
initialLiquiditybigintYesCollateral in raw units
endTimebigintYesUnix timestamp when trading ends
collateralMintPublicKeyYesCollateral token mint
settlerAddressPublicKeyYesOracle wallet (settles the market)
yesOddsBpsnumberNoInitial YES odds in basis points (100-9900, default 5000)

Returns: { market: PublicKey, signature: string }

IMPORTANT: Must call setMarketResolvable(market, true) within 15 minutes of creation or the market is permanently frozen.

createMarketV2WithCustomOdds(params) — V2 with Custom Odds

const result = await client.createMarketV2WithCustomOdds({
  question: 'Will Ethereum flip Bitcoin?',
  initialLiquidity: 50_000_000n,
  endTime: BigInt(Math.floor(Date.now() / 1000) + 90 * 86400),
  collateralTokenMint: USDC,
  yesOddsBps: 2000,  // 20% YES / 80% NO
  oracle: customOraclePubkey,  // Optional
});

Returns: { signature: string, market: string }


Social Media Market Creation

createMarketTwitter(params)

const result = await client.createMarketTwitter({
  question: 'Will this tweet cross 5000 replies?',
  tweetUrl: 'https://x.com/username/status/123456789',
  initialLiquidity: 1_000_000n,
  endTime: BigInt(Math.floor(Date.now() / 1000) + 7 * 86400),
  collateralTokenMint: USDC,
});

Returns: { signature: string, market: string, detectedTwitterUrl?: string, isTweetIdFormat?: boolean }

Supported URL formats: https://x.com/user/status/ID, https://twitter.com/user/status/ID

createMarketYoutube(params)

const result = await client.createMarketYoutube({
  question: 'Will this video cross 1B views?',
  youtubeUrl: 'https://youtu.be/VIDEO_ID',
  initialLiquidity: 1_000_000n,
  endTime: BigInt(Math.floor(Date.now() / 1000) + 30 * 86400),
  collateralTokenMint: USDC,
});

Returns: { signature: string, market: string, detectedYoutubeUrl?: string }

createMarketDefiLlama(params)

const result = await client.createMarketDefiLlama({
  question: 'Will Uniswap TVL exceed \$5B?',
  protocolName: 'uniswap-v3',
  metric: 'tvl',
  initialLiquidity: 5_000_000n,
  endTime: BigInt(Math.floor(Date.now() / 1000) + 30 * 86400),
  collateralTokenMint: USDC,
});

Returns: { signature: string, market: string, detectedProtocol?: string, detectedMetric?: string }


P2P Market Creation

createP2PMarketGeneral(params) — Raw Units

const result = await client.createP2PMarketGeneral({
  question: 'Will our DAO pass Proposal #42?',
  initialAmount: 100_000_000n,
  side: 'yes',
  creatorSideCap: 500_000_000n,
  endTime: BigInt(Math.floor(Date.now() / 1000) + 14 * 86400),
  collateralTokenMint: USDC,
});
ParameterTypeRequiredDescription
questionstringYesThe prediction question
initialAmountbigintYesCreator's initial stake (raw units)
side'yes' | 'no'YesSide the creator takes
creatorSideCapbigintYesMaximum collateral on creator's side
endTimebigintYesUnix timestamp when trading ends
collateralTokenMintPublicKeyYesCollateral token mint

Returns: { signature: string, market: PubkeyLike, yesTokenMint: PubkeyLike, noTokenMint: PubkeyLike }

createP2PMarketSimple(params) — UI-Friendly

const result = await client.createP2PMarketSimple({
  question: 'Will it rain tomorrow?',
  side: 'yes',
  amountUsdc: 50,
  daysUntilEnd: 1,
  creatorSideCapMultiplier: 5,
});
ParameterTypeRequiredDescription
questionstringYesThe prediction question
side'yes' | 'no'YesSide the creator takes
amountUsdcnumberYesHuman-readable USDC amount (SDK converts)
daysUntilEndnumberNoDays until end (default: 30)
creatorSideCapMultipliernumberNoCap multiplier (default: 5)

P2P Social Media Variants

All accept the same base P2P params plus media-specific fields:

MethodExtra ParamsReturns
createP2PMarketTwitter(params)tweetUrl{ ..., detectedTwitterUrl? }
createP2PMarketYoutube(params)youtubeUrl{ ..., detectedYoutubeUrl? }
createP2PMarketDefiLlama(params)protocolName, metric{ ..., detectedProtocol? }
createP2PMarketTwitterSimple(params)tweetUrlP2P Simple + Twitter
createP2PMarketYoutubeSimple(params)youtubeUrlP2P Simple + YouTube
createP2PMarketDefiLlamaSimple(params)protocolName, metricP2P Simple + DeFiLlama
createMarketP2PWithCustomOdds(params)yesOddsBpsP2P with custom starting odds

tradeP2PMarket(params) — Trade on P2P Markets

const { signature } = await client.tradeP2PMarket({
  market: marketPubkey,
  side: 'no',
  amount: 50_000_000n,  // 50 USDC (raw units)
});

Market Data (Read-Only)

fetchMarketAddresses() — List All V2 Markets

const addresses: string[] = await client.fetchMarketAddresses();
// Returns array of base58 market addresses

fetchMarket(pubkey) — On-Chain Market Account

const { account } = await client.fetchMarket(new PublicKey(marketAddress));
// account: MarketType (see types-and-precision.md)

fetchMarkets() — All V2 Markets with Full Data

const markets = await client.fetchMarkets();
// Returns array of { pubkey, account: MarketType }

getMarketPriceV2(market) — Current Prices

const prices = await client.getMarketPriceV2(marketPubkey);
// Returns:
// {
//   yesPrice: number,        // 0-1 range (e.g., 0.65 = 65%)
//   noPrice: number,         // 0-1 range (e.g., 0.35 = 35%)
//   yesMultiplier: number,   // Payout if YES wins (e.g., 1.54x)
//   noMultiplier: number,    // Payout if NO wins (e.g., 2.85x)
//   marketReserves: number,  // Total collateral (UI units)
//   yesTokenSupply: number,  // YES tokens minted (UI units)
//   noTokenSupply: number,   // NO tokens minted (UI units)
// }

fetchSettlementCriteria(market) — AI Resolution Info

const criteria = await client.fetchSettlementCriteria(marketAddress);
// Returns: SettlementCriteria (see types-and-precision.md)

fetchSettlementData(market) — Settlement Decision

const data = await client.fetchSettlementData(marketAddress);
// Returns: SettlementData { answer: 'YES'|'NO'|'INVALID', reasoning: string }

waitForSettlementCriteria(market) — Retry Until Available

Polls every 2 seconds for up to 15 minutes until settlement criteria are ready.

const { resolvable, answer, criteria } = await client.waitForSettlementCriteria(marketAddress);

trading.getMarketInfo(pubkey) — Extended Market Info

const info = await client.trading.getMarketInfo(new PublicKey(marketAddress));
// Returns: { address, question, id, creator, initialLiquidity, marketReserves,
//   endTime, resolvable, resolved, winningTokenId,
//   yesTokenMint, noTokenMint, collateralToken,
//   yesTokenSupplyMinted, noTokenSupplyMinted }

trading.getBalances(market) — User Token Balances

const balances = await client.trading.getBalances(new PublicKey(marketAddress));
// Returns user's YES/NO token balances for the market

trading.getPrices(market) — Supply-Based Price Shares

const prices = await client.trading.getPrices(new PublicKey(marketAddress));
// Returns token supply-based price information

Trading

trading.buyTokensUsdc(params) — Buy V2 Tokens

const result = await client.trading.buyTokensUsdc({
  market: marketPubkey,
  buyYesToken: true,
  amountUsdc: 10,       // Human-readable USDC
  minimumOut: 0n,       // Optional: slippage protection
});
ParameterTypeRequiredDescription
marketPublicKeyYesMarket address
buyYesTokenbooleanYestrue = buy YES, false = buy NO
amountUsdcnumberYesUSDC amount (human-readable, SDK converts)
minimumOutbigintNoMinimum tokens to receive (slippage protection)

Returns: { signature: string, usdcSpent: number, tokensReceived: number, before: BalanceSnapshot, after: BalanceSnapshot }

trading.sellTokensBase(params) — Sell V2 Tokens

const result = await client.trading.sellTokensBase({
  market: marketPubkey,
  burnYesToken: true,
  amountBaseUnits: 5_000_000n,  // Raw token units (6 decimals)
});
ParameterTypeRequiredDescription
marketPublicKeyYesMarket address
burnYesTokenbooleanYestrue = sell YES, false = sell NO
amountBaseUnitsbigintYesToken amount in raw units

Returns: { signature: string, tokensSold: number, usdcReceived: number }

buyV3TokensUsdc(params) — Buy P2P/V3 Tokens

const result = await client.buyV3TokensUsdc({
  market: marketPubkey,
  buyYesToken: true,
  amountUsdc: 10,
});

Returns: { signature: string }

trading.mintDecisionTokensDerived(params) — Mint Decision Tokens

await client.trading.mintDecisionTokensDerived({
  market: marketPubkey,
  amount: 10_000_000n,
});

trading.burnDecisionTokensDerived(params) — Burn Decision Tokens

await client.trading.burnDecisionTokensDerived({
  market: marketPubkey,
  amount: 10_000_000n,
});

Settlement

setMarketResolvable(market, resolvable, forceResolve?) — Activate Market

IMPORTANT: Positional arguments, NOT an object parameter.

// Activate a custom oracle market (must be within 15 min of creation)
await client.setMarketResolvable(marketAddress, true);

// Force-resolve flag (optional third parameter)
await client.setMarketResolvable(marketAddress, true, true);
ParameterTypeRequiredDescription
marketPublicKey | stringYesMarket address
resolvablebooleanYestrue to activate, false to deactivate
forceResolvebooleanNoForce resolution flag

Returns: { signature: string }

setMarketResolvableP2p(market, resolvable) — Activate P2P Market

await client.setMarketResolvableP2p(marketAddress, true);

settleMarket(params) — Resolve Market (via anchorMarket)

const result = await client.anchorMarket.settleMarket({
  market: new PublicKey(marketAddress),
  yesWinner: true,
});
ParameterTypeRequiredDescription
marketPublicKeyYesMarket address
yesWinnerbooleanYestrue = YES wins, false = NO wins

Returns: { signature: string }


Redemption

redeemPosition(market, options?) — Redeem V2 Position

const { signature } = await client.redeemPosition(marketPubkey);

redeemP2PPosition(market) — Redeem P2P Position

const { signature } = await client.redeemP2PPosition(marketPubkey);

Token Addresses (Solana Mainnet)

TokenAddressDecimals
USDCEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v6
USDTEs9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB6
SOL (wrapped)So111111111111111111111111111111111111111129

Error Types

The SDK exports typed error classes for structured error handling:

import { SdkError, ValidationError, TransportError, ProgramError } from 'pnp-sdk';

try {
  await client.market.createMarket({ ... });
} catch (error) {
  if (error instanceof ValidationError) {
    // Input validation failed (code: 'VALIDATION_ERROR')
    console.error('Bad input:', error.message);
  } else if (error instanceof TransportError) {
    // Network/RPC failure (code: 'TRANSPORT_ERROR')
    console.error('Network error, retry:', error.message);
  } else if (error instanceof ProgramError) {
    // On-chain program error (code: 'PROGRAM_ERROR')
    console.error('Program error:', error.programErrorCode, error.logs);
  } else if (error instanceof SdkError) {
    // Generic SDK error
    console.error('SDK error:', error.code, error.message);
  }
}

RPC Providers

For production, use dedicated RPC endpoints:

# Helius (recommended)
export RPC_URL=https://mainnet.helius-rpc.com/?api-key=YOUR_KEY

# QuickNode
export RPC_URL=https://your-endpoint.solana-mainnet.quiknode.pro/YOUR_KEY

# Alchemy
export RPC_URL=https://solana-mainnet.g.alchemy.com/v2/YOUR_KEY