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
);
| Parameter | Type | Required | Description |
|---|---|---|---|
rpcUrl | string | Yes | Solana RPC endpoint URL |
privateKey | string | No | Base58 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'),
});
| Parameter | Type | Required | Description |
|---|---|---|---|
question | string | Yes | The prediction question |
initialLiquidity | bigint | Yes | Collateral in raw units (decimals depend on chosen token) |
endTime | bigint | Yes | Unix timestamp when trading ends |
baseMint | PublicKey | No | Collateral 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)
});
| Parameter | Type | Required | Description |
|---|---|---|---|
question | string | Yes | The prediction question |
initialLiquidity | bigint | Yes | Collateral in raw units |
endTime | bigint | Yes | Unix timestamp when trading ends |
collateralMint | PublicKey | Yes | Collateral token mint |
settlerAddress | PublicKey | Yes | Oracle wallet (settles the market) |
yesOddsBps | number | No | Initial 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,
});
| Parameter | Type | Required | Description |
|---|---|---|---|
question | string | Yes | The prediction question |
initialAmount | bigint | Yes | Creator's initial stake (raw units) |
side | 'yes' | 'no' | Yes | Side the creator takes |
creatorSideCap | bigint | Yes | Maximum collateral on creator's side |
endTime | bigint | Yes | Unix timestamp when trading ends |
collateralTokenMint | PublicKey | Yes | Collateral 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,
});
| Parameter | Type | Required | Description |
|---|---|---|---|
question | string | Yes | The prediction question |
side | 'yes' | 'no' | Yes | Side the creator takes |
amountUsdc | number | Yes | Human-readable USDC amount (SDK converts) |
daysUntilEnd | number | No | Days until end (default: 30) |
creatorSideCapMultiplier | number | No | Cap multiplier (default: 5) |
P2P Social Media Variants
All accept the same base P2P params plus media-specific fields:
| Method | Extra Params | Returns |
|---|---|---|
createP2PMarketTwitter(params) | tweetUrl | { ..., detectedTwitterUrl? } |
createP2PMarketYoutube(params) | youtubeUrl | { ..., detectedYoutubeUrl? } |
createP2PMarketDefiLlama(params) | protocolName, metric | { ..., detectedProtocol? } |
createP2PMarketTwitterSimple(params) | tweetUrl | P2P Simple + Twitter |
createP2PMarketYoutubeSimple(params) | youtubeUrl | P2P Simple + YouTube |
createP2PMarketDefiLlamaSimple(params) | protocolName, metric | P2P Simple + DeFiLlama |
createMarketP2PWithCustomOdds(params) | yesOddsBps | P2P 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
});
| Parameter | Type | Required | Description |
|---|---|---|---|
market | PublicKey | Yes | Market address |
buyYesToken | boolean | Yes | true = buy YES, false = buy NO |
amountUsdc | number | Yes | USDC amount (human-readable, SDK converts) |
minimumOut | bigint | No | Minimum 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)
});
| Parameter | Type | Required | Description |
|---|---|---|---|
market | PublicKey | Yes | Market address |
burnYesToken | boolean | Yes | true = sell YES, false = sell NO |
amountBaseUnits | bigint | Yes | Token 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);
| Parameter | Type | Required | Description |
|---|---|---|---|
market | PublicKey | string | Yes | Market address |
resolvable | boolean | Yes | true to activate, false to deactivate |
forceResolve | boolean | No | Force 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,
});
| Parameter | Type | Required | Description |
|---|---|---|---|
market | PublicKey | Yes | Market address |
yesWinner | boolean | Yes | true = 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)
| Token | Address | Decimals |
|---|---|---|
| USDC | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | 6 |
| USDT | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB | 6 |
| SOL (wrapped) | So11111111111111111111111111111111111111112 | 9 |
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