pnp-adapter
v0.1.4
Published
TypeScript SDK for PNP Protocol - Prediction Markets on Solana
Maintainers
Readme
PNP Protocol TypeScript SDK
A complete TypeScript SDK for interacting with PNP Protocol prediction markets on Solana.
Installation
npm install pnp-adapter
# or
yarn add pnp-adapter
# or
pnpm add pnp-adapterPeer Dependencies
Make sure you have the following peer dependencies installed:
npm install @coral-xyz/anchor @solana/web3.js @solana/spl-tokenQuick Start
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;
},
};Market Types
V2 Markets (Pythagorean AMM)
V2 markets use an automated market maker model where prices are determined by the Pythagorean formula based on YES/NO token supplies.
V3 Markets (Parimutuel/P2P)
V3 markets use a parimutuel betting model where the creator takes a side and other users can bet on either outcome.
API Reference
V2 Market Functions
createMarketV2
Creates a new V2 prediction market.
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.
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.
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.
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).
import { claimCreatorRefundV2 } from "pnp-adapter";
const signature = await claimCreatorRefundV2(connection, wallet, marketAddress);V3 Market Functions
createMarketV3
Creates a new V3 parimutuel prediction market.
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.
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.
import { redeemPositionV3 } from "pnp-adapter";
const signature = await redeemPositionV3(connection, wallet, {
marketAddress: "...",
marketCreatorAddress: "...",
yesTokenAddress: "...",
noTokenAddress: "...",
});creatorRefundV3
Claims refund for V3 market creator.
import { creatorRefundV3 } from "pnp-adapter";
const signature = await creatorRefundV3(connection, wallet, marketAddress);Query Functions
getMarketVersion
Detects market version (2 or 3).
import { getMarketVersion } from "pnp-adapter";
const version = await getMarketVersion(connection, marketAddress);
// Returns: 2 | 3 | nullgetPrice
Gets token price in a market.
import { getPrice } from "pnp-adapter";
const yesPrice = await getPrice(connection, marketAddress, "yes");
const noPrice = await getPrice(connection, marketAddress, "no");
// Returns: number between 0 and 1getMarketData
Gets comprehensive market data.
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.
import { getMarketPricesAndData } from "pnp-adapter";
const result = await getMarketPricesAndData(connection, marketAddress);
// Returns:
// {
// marketData: { ... },
// prices: { yesPrice: number, noPrice: number }
// }getSlippage / getBurnSlippage
Calculates slippage for trades.
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
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,
]);Utility Functions
PDA Derivation
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
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 allConstants
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";Types
import type {
Wallet,
Side,
TokenType,
MarketVersion,
CreateMarketV2Params,
CreateMarketV3Params,
BuyV3TokensParams,
RedeemPositionParams,
MarketData,
MarketPrices,
MarketPricesAndData,
} from "pnp-adapter";Wallet Interface
The SDK accepts any wallet that implements this interface:
interface Wallet {
address: string;
signTransaction: (tx: Transaction) => Promise<Transaction>;
}This is compatible with:
@privy-io/react-authConnectedSolanaWallet@solana/wallet-adapterwallet adapters- Custom wallet implementations
Error Handling
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);
}
}License
MIT
