TypeScript SDK for PNP Protocol - Prediction Markets on Solana
npm install pnp-adapterA complete TypeScript SDK for interacting with PNP Protocol prediction markets on Solana.
``bash`
npm install pnp-adapteror
yarn add pnp-adapteror
pnpm add pnp-adapter
Make sure you have the following peer dependencies installed:
`bash`
npm install @coral-xyz/anchor @solana/web3.js @solana/spl-token
`typescript
import { Connection } from "@solana/web3.js";
import {
createMarketV2,
createMarketV3,
buyYesV3,
getMarketData,
DEFAULT_COLLATERAL_MINT,
} from "pnp-adapter";
// Create a connection
const connection = new Connection("https://api.mainnet-beta.solana.com");
// Your wallet (must implement the Wallet interface)
const wallet = {
address: "your-wallet-address",
signTransaction: async (tx) => {
// Sign transaction with your wallet
return signedTx;
},
};
`
V2 markets use an automated market maker model where prices are determined by the Pythagorean formula based on YES/NO token supplies.
V3 markets use a parimutuel betting model where the creator takes a side and other users can bet on either outcome.
---
#### createMarketV2
Creates a new V2 prediction market.
`typescript
import { createMarketV2, DEFAULT_COLLATERAL_MINT } from "pnp-adapter";
const signature = await createMarketV2(connection, wallet, {
question: "Will BTC reach $100k by end of 2024?",
initialLiquidity: 100_000_000, // 100 USDC (6 decimals)
endTime: Math.floor(Date.now() / 1000) + 86400 * 30, // 30 days from now
collateralMint: DEFAULT_COLLATERAL_MINT.toBase58(),
yesOddsBps: 5000, // Optional: 50/50 starting odds
});
`
Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| question | string | The prediction question |initialLiquidity
| | number | Initial liquidity in base units |endTime
| | number | Unix timestamp (seconds) |collateralMint
| | string | Collateral token mint address |yesOddsBps
| | number? | Optional custom odds (100-9900) |oracle
| | string? | Optional custom oracle |
---
#### mintYesTokenV2 / mintNoTokenV2
Mints YES or NO tokens by depositing collateral.
`typescript
import { mintYesTokenV2 } from "pnp-adapter";
const signature = await mintYesTokenV2(
connection,
wallet,
marketAddress,
10_000_000, // 10 USDC
creatorAddress
);
`
---
#### burnYesTokenV2 / burnNoTokenV2
Burns YES or NO tokens to receive collateral back.
`typescript
import { burnYesTokenV2 } from "pnp-adapter";
const signature = await burnYesTokenV2(
connection,
wallet,
marketAddress,
5_000_000, // Burn 5 tokens
creatorAddress
);
`
---
#### redeemPositionV2
Redeems winning position after market settlement.
`typescript
import { redeemPositionV2 } from "@pnp-protocol/sdk";
const signature = await redeemPositionV2(connection, wallet, {
marketAddress: "...",
marketCreatorAddress: "...",
yesTokenAddress: "...",
noTokenAddress: "...",
});
`
---
#### claimCreatorRefundV2
Claims refund for market creator (if market not resolved).
`typescript
import { claimCreatorRefundV2 } from "pnp-adapter";
const signature = await claimCreatorRefundV2(connection, wallet, marketAddress);
`
---
#### createMarketV3
Creates a new V3 parimutuel prediction market.
`typescript
import {
createMarketV3,
DEFAULT_COLLATERAL_MINT,
DEFAULT_MAX_POT_RATIO,
} from "pnp-adapter";
const signature = await createMarketV3(connection, wallet, {
question: "Will ETH flip BTC by 2025?",
initialAmount: 50_000_000, // 50 USDC
side: { yes: {} }, // Creator takes YES side
creatorSideCap: 500_000_000, // 500 USDC max
endTime: Math.floor(Date.now() / 1000) + 86400 * 30,
maxPotRatio: DEFAULT_MAX_POT_RATIO,
collateralMint: DEFAULT_COLLATERAL_MINT.toBase58(),
oddsBps: 5000, // Optional: starting odds
});
`
Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| question | string | The prediction question |initialAmount
| | number | Initial amount in base units |side
| | Side | Creator's side ({ yes: {} } or { no: {} }) |creatorSideCap
| | number | Max cap for creator's side |endTime
| | number | Unix timestamp (seconds) |maxPotRatio
| | number | Max pot imbalance ratio |collateralMint
| | string | Collateral token mint address |oddsBps
| | number? | Optional custom odds |oracle
| | string? | Optional custom oracle |
---
#### buyV3Tokens / buyYesV3 / buyNoV3
Buys tokens in a V3 market.
`typescript
import { buyYesV3, buyNoV3, buyV3Tokens } from "pnp-adapter";
// Simple API
const sig1 = await buyYesV3(connection, wallet, marketAddress, 10_000_000);
const sig2 = await buyNoV3(connection, wallet, marketAddress, 10_000_000);
// Full API
const sig3 = await buyV3Tokens(connection, wallet, {
marketAddress: "...",
amount: 10_000_000,
side: { yes: {} },
minimumTokensOut: 0, // Slippage protection
});
`
---
#### redeemPositionV3
Redeems winning position in a V3 market.
`typescript
import { redeemPositionV3 } from "pnp-adapter";
const signature = await redeemPositionV3(connection, wallet, {
marketAddress: "...",
marketCreatorAddress: "...",
yesTokenAddress: "...",
noTokenAddress: "...",
});
`
---
#### creatorRefundV3
Claims refund for V3 market creator.
`typescript
import { creatorRefundV3 } from "pnp-adapter";
const signature = await creatorRefundV3(connection, wallet, marketAddress);
`
---
#### getMarketVersion
Detects market version (2 or 3).
`typescript
import { getMarketVersion } from "pnp-adapter";
const version = await getMarketVersion(connection, marketAddress);
// Returns: 2 | 3 | null
`
---
#### getPrice
Gets token price in a market.
`typescript
import { getPrice } from "pnp-adapter";
const yesPrice = await getPrice(connection, marketAddress, "yes");
const noPrice = await getPrice(connection, marketAddress, "no");
// Returns: number between 0 and 1
`
---
#### getMarketData
Gets comprehensive market data.
`typescript
import { getMarketData } from "pnp-adapter";
const data = await getMarketData(connection, marketAddress);
// Returns:
// {
// marketReserves: number,
// yesTokenSupply: number,
// noTokenSupply: number,
// endTime: number,
// marketAccount: any
// }
`
---
#### getMarketPricesAndData
Gets market data with computed prices.
`typescript
import { getMarketPricesAndData } from "pnp-adapter";
const result = await getMarketPricesAndData(connection, marketAddress);
// Returns:
// {
// marketData: { ... },
// prices: { yesPrice: number, noPrice: number }
// }
`
---
#### getSlippage / getBurnSlippage
Calculates slippage for trades.
`typescript
import { getSlippage, getBurnSlippage } from "pnp-adapter";
// Minting slippage
const mintSlippage = await getSlippage(
connection,
marketAddress,
10_000_000, // collateral amount
"yes"
);
// Returns: { tokensToMint: number, priceImpact: number }
// Burning slippage
const burnSlippage = await getBurnSlippage(
connection,
marketAddress,
5_000_000, // tokens to burn
"yes"
);
// Returns: { collateralOut: number, priceImpact: number }
`
---
#### Token Balance Queries
`typescript
import {
getUSDCBalance,
getUserTokenBalance,
getMultipleTokenBalances,
} from "pnp-adapter";
// USDC balance
const usdcBalance = await getUSDCBalance(connection, walletAddress);
// Any token balance
const tokenBalance = await getUserTokenBalance(
connection,
walletAddress,
mintAddress
);
// Multiple balances in parallel
const balances = await getMultipleTokenBalances(connection, walletAddress, [
mint1,
mint2,
mint3,
]);
`
---
#### PDA Derivation
`typescript
import {
getGlobalConfigPDA,
getMarketV2PDA,
getMarketV3PDA,
getYesTokenMintV3PDA,
getNoTokenMintV3PDA,
getCreatorFeeTreasuryPDA,
PROGRAM_ID,
} from "pnp-adapter";
import { BN } from "@coral-xyz/anchor";
const globalConfig = getGlobalConfigPDA(PROGRAM_ID);
const [marketPDA] = getMarketV3PDA(new BN(globalId), PROGRAM_ID);
`
---
#### Caching
`typescript
import { getCachedData, setCachedData, clearCache } from "pnp-adapter";
// Cache data
setCachedData("my-key", data, 30000); // 30 second TTL
// Get cached data
const cached = getCachedData("my-key", 30000);
// Clear cache
clearCache("my-key"); // Clear specific key
clearCache(); // Clear all
`
---
`typescript`
import {
PROGRAM_ID, // PNP Protocol Program ID
ADMIN, // Admin address for V2
ADMIN_V3, // Admin address for V3
DEFAULT_COLLATERAL_MINT, // USDC mint
DEFAULT_MAX_POT_RATIO, // 4_000_000_000
TOKEN_DECIMALS, // 6
COMPUTE_UNITS, // 400_000
} from "pnp-adapter";
---
`typescript`
import type {
Wallet,
Side,
TokenType,
MarketVersion,
CreateMarketV2Params,
CreateMarketV3Params,
BuyV3TokensParams,
RedeemPositionParams,
MarketData,
MarketPrices,
MarketPricesAndData,
} from "pnp-adapter";
---
The SDK accepts any wallet that implements this interface:
`typescript`
interface Wallet {
address: string;
signTransaction: (tx: Transaction) => Promise
}
This is compatible with:
- @privy-io/react-auth ConnectedSolanaWallet@solana/wallet-adapter
- wallet adapters
- Custom wallet implementations
---
`typescript``
try {
await buyYesV3(connection, wallet, marketAddress, amount);
} catch (error) {
if ((error as any).isPotSizeReached) {
console.log("Pot size limit reached!");
} else {
console.error("Transaction failed:", error);
}
}
---
MIT