Pump TS Vanity
nirholas/pump-fun-sdk
Educational single-threaded TypeScript vanity address generator for Solana using @solana/web3.js with async iteration, event-loop yielding, streaming generator API, and best-effort memory zeroization.
Creates, trades and settles permissionless prediction markets on Solana with any SPL token as collateral, including social-media and custom-oracle markets.
$ npx skills add internet-court/internet-court-skill --skill pnp-markets-solana -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install internet-court/internet-court-skill pnp-markets-solana --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/internet-court/internet-court-skill.git skills-src && mkdir -p .claude/skills && cp -r skills-src/vendored/pnp/pnp-solana .claude/skills/pnp-markets-solana && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "pnp-markets-solana" agent skill from https://github.com/internet-court/internet-court-skill/tree/main/vendored/pnp/pnp-solana into .claude/skills/pnp-markets-solana/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pnp-markets-solana", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/internet-court/internet-court-skill/tree/main/vendored/pnp/pnp-solanaType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add internet-court/internet-court-skill --skill pnp-markets-solana -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install internet-court/internet-court-skill pnp-markets-solana --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/internet-court/internet-court-skill.git skills-src && mkdir -p .agents/skills && cp -r skills-src/vendored/pnp/pnp-solana .agents/skills/pnp-markets-solana && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "pnp-markets-solana" agent skill from https://github.com/internet-court/internet-court-skill/tree/main/vendored/pnp/pnp-solana into .agents/skills/pnp-markets-solana/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pnp-markets-solana", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add internet-court/internet-court-skill --skill pnp-markets-solana -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install internet-court/internet-court-skill pnp-markets-solana --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/internet-court/internet-court-skill.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/vendored/pnp/pnp-solana .cursor/skills/pnp-markets-solana && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "pnp-markets-solana" agent skill from https://github.com/internet-court/internet-court-skill/tree/main/vendored/pnp/pnp-solana into .cursor/skills/pnp-markets-solana/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pnp-markets-solana", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/internet-court/internet-court-skill.git --path vendored/pnp/pnp-solana--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add internet-court/internet-court-skill --skill pnp-markets-solana -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install internet-court/internet-court-skill pnp-markets-solana --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/internet-court/internet-court-skill.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/vendored/pnp/pnp-solana .gemini/skills/pnp-markets-solana && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "pnp-markets-solana" agent skill from https://github.com/internet-court/internet-court-skill/tree/main/vendored/pnp/pnp-solana into .gemini/skills/pnp-markets-solana/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pnp-markets-solana", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install internet-court/internet-court-skill pnp-markets-solanaInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add internet-court/internet-court-skill --skill pnp-markets-solana -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/internet-court/internet-court-skill.git skills-src && mkdir -p .github/skills && cp -r skills-src/vendored/pnp/pnp-solana .github/skills/pnp-markets-solana && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "pnp-markets-solana" agent skill from https://github.com/internet-court/internet-court-skill/tree/main/vendored/pnp/pnp-solana into .github/skills/pnp-markets-solana/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pnp-markets-solana", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add internet-court/internet-court-skill --skill pnp-markets-solana -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install internet-court/internet-court-skill pnp-markets-solana --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/internet-court/internet-court-skill.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/vendored/pnp/pnp-solana .opencode/skills/pnp-markets-solana && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "pnp-markets-solana" agent skill from https://github.com/internet-court/internet-court-skill/tree/main/vendored/pnp/pnp-solana into .opencode/skills/pnp-markets-solana/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pnp-markets-solana", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
pnp-markets-solanaCreates, trades and settles permissionless prediction markets on Solana with any SPL token as collateral, including social-media and custom-oracle markets.
The agent can create prediction markets in three styles: V2 AMM markets, P2P direct bets, and custom-oracle markets that an AI agent can resolve. It can also build social-media markets on Twitter engagement, YouTube views or DeFiLlama metrics. Trading means buying and selling YES and NO outcome tokens, an oracle settles the market after trading ends, and winners redeem their positions. Any SPL token works as collateral, Token-2022 included.
TypeScript scripts handle the main tasks: creating markets (create-market.ts plus variants for X, YouTube, P2P and custom oracles), reading market data and redeeming. References cover the API, program addresses, types and precision, examples and use cases. The skill lists the mainnet and devnet program IDs and common token mints, and a precision table: USDC and USDT use 6 decimals, wrapped SOL uses 9, and decision tokens use 6, with BigInt conversion helpers.
It is not meant for generic Solana wallet work, token swaps without prediction markets, NFTs or other prediction market protocols, which have their own skills. Running it takes Node.js 18 or newer, a Solana RPC endpoint, a funded wallet for transaction fees and a supported token for collateral. The excerpt is cut off in the precision helpers.
5 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit fa89195. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships 8 files in scripts/ (TypeScript, from the files we listed), which the agent can run.
Shell commands in SKILL.md call:
tsxnpmFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
api.mainnet-beta.solana.comx.comyoutu.beyoutube.comtwitter.commainnet.helius-rpc.comsolana-mainnet.g.alchemy.comAlso links to:
npmjs.comdocs.pnp.exchangesolscan.ioFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
PRIVATE_KEYFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Requires Node.js 18+, Solana RPC endpoint (mainnet or devnet), funded wallet with SOL for transaction fees, and any SPL token (including Token-2022) as collateral
From compatibility in the SKILL.md frontmatter.
PNP Prediction Markets on Solana loads about 7.5k tokens when it runs, and up to ~18k if it reads all its reference files. Until then it costs about 99 tokens; SKILL.md has 1,445 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
ripts/` and use `dotenv/config` to load `.env`.Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from internet-court/internet-court-skill at commit fa89195, republished under its MIT licence (© internet-court). 1,445 words, ~7,461 tokens.
.claude/skills/pnp-markets-solana/SKILL.md (or your agent's skills folder). This skill also uses 21 other files; get the full folder from GitHub.Create and manage prediction markets on Solana with any SPL token collateral. Supports V2 AMM markets, P2P direct bets, custom oracle resolution for AI agents, and social media markets (Twitter, YouTube, DeFiLlama).
Use when the user wants to:
Triggers: prediction market, betting, oracle, settlement, forecast, YES/NO, outcome token, market resolution, P2P bet, custom oracle, social media market, autonomous market, info finance, market creation, prediction, wager, binary outcome
Do not use when:
| Item | Address | Notes |
|---|---|---|
| PNP Program (Mainnet) | 8PyE2dizL52ga7ytqLtqRyjwWp4yXEx8M5Z4BAHgHuTb | Main prediction market program |
| PNP Program (Devnet) | pnpkv2qnh4bfpGvTugGDSEhvZC7DP4pVxTuDykV3BGz | Devnet testing program |
| USDC Mint | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | Common collateral (6 decimals) |
| USDT Mint | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB | Alternative stable (6 decimals) |
| WSOL Mint | So11111111111111111111111111111111111111112 | Wrapped SOL (9 decimals) |
| Token Type | Decimals | Example |
|---|---|---|
| USDC / USDT | 6 | 1 USDC = 1_000_000n |
| SOL (wrapped) | 9 | 1 SOL = 1_000_000_000n |
| Decision tokens (YES/NO) | 6 | Minted per-market by the program |
// Conversion helpers
const usdcToRaw = (amount: number) => BigInt(Math.floor(amount * 1_000_000));
const daysFromNow = (days: number) => BigInt(Math.floor(Date.now() / 1000) + days * 86400);
// Example
const liquidity = usdcToRaw(100); // 100 USDC -> 100_000_000n
const endTime = daysFromNow(7); // 7 days from now -> Unix timestamp as bigint[!IMPORTANT] Collateral can be any SPL token or Token-2022 token. Pass the token's mint address as
baseMintorcollateralTokenMint. Make sure to use the correct decimals for the chosen token (e.g., USDC/USDT = 6, SOL = 9). Common mints are listed in the table above for reference.
# Install dependencies
cd scripts && npm install
# Set environment variables
export PRIVATE_KEY=<base58_private_key>
export RPC_URL=https://api.mainnet-beta.solana.com # or dedicated RPCimport { PNPClient } from 'pnp-sdk';
import { PublicKey } from '@solana/web3.js';
const client = new PNPClient(
process.env.RPC_URL || 'https://api.mainnet-beta.solana.com',
process.env.PRIVATE_KEY! // Base58 string or Uint8Array
);
// Collateral can be any SPL token (including Token-2022) — use the mint address of your chosen token
const USDC = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
// Create a prediction market
const result = await client.market.createMarket({
question: 'Will Bitcoin reach $100K by end of 2025?',
initialLiquidity: 1_000_000n, // 1 USDC (6 decimals) — adjust decimals for your collateral token
endTime: BigInt(Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60),
baseMint: USDC, // Any SPL or Token-2022 mint
});
console.log('Market created:', result.market.toBase58());
// Returns: { signature: string, market: PublicKey }[!TIP] Use
PNPClient.parseSecretKey(process.env.PRIVATE_KEY)to handle both Base58 strings and JSON array formats automatically.
Markets follow a strict state progression:
CREATED ──────► ACTIVE ──────► ENDED ──────► RESOLVED ──────► CLAIMED
│ │ │ │ │
│ Trading live No new trades Oracle declares Winners redeem
│ Users buy/sell allowed YES/NO winner collateral
│ YES/NO tokens
│
└── initialLiquidity locked, PNP global oracle resolvesCREATED ──► [15-MIN BUFFER] ──► ACTIVE ──► ENDED ──► RESOLVED ──► CLAIMED
│ │ │ │ │ │
│ setMarketResolvable(true) Trade Wait for settleMarket() redeem
│ MUST call within 15 min! live endTime (oracle only)
│
└── Market starts frozen. If not activated within 15 minutes,
it is PERMANENTLY FROZEN and cannot be recovered.| From | To | Method | Condition |
|---|---|---|---|
| CREATED | ACTIVE | setMarketResolvable(market, true) | Custom oracle only; must be within 15 min of creation |
| ACTIVE | ENDED | (automatic) | Unix timestamp reaches endTime |
| ENDED | RESOLVED | settleMarket({market, yesWinner}) | Oracle-only; can only be called after endTime |
| RESOLVED | CLAIMED | redeemPosition(market) | Any winner; available forever after resolution |
These operations fetch data without executing transactions. Initialize with just an RPC URL:
const readOnlyClient = new PNPClient('https://api.mainnet-beta.solana.com');fetchMarketAddresses() — Discover V2 Marketsconst addresses: string[] = await client.fetchMarketAddresses();
console.log(`Found ${addresses.length} V2 AMM markets`);
// Returns: string[] of market public key base58 addressesfetchMarket(pubkey) — Get On-Chain Market Dataconst { account } = await client.fetchMarket(new PublicKey('HxnpHygK1v7TqodWqAv6RvcEiK9zxAgw5jPZ6rskgj2E'));
// MarketType fields:
// account.question: string
// account.creator: PubkeyLike
// account.resolvable: boolean
// account.resolved: boolean
// account.end_time: U64Like (Unix timestamp)
// account.winning_token_id: 'yes' | 'no' | 'none' | null
// account.yes_token_mint: PubkeyLike
// account.no_token_mint: PubkeyLike
// account.collateral_token: PubkeyLike
// account.market_reserves: U64Like
// account.initial_liquidity: U64LikegetMarketPriceV2(market) — Get Current Prices & Multipliersconst priceData = await client.getMarketPriceV2(marketAddress);
console.log({
yesPrice: priceData.yesPrice, // 0-1 range (e.g., 0.65 = 65%)
noPrice: priceData.noPrice, // 0-1 range (e.g., 0.35 = 35%)
yesMultiplier: priceData.yesMultiplier, // Payout ratio if YES wins (e.g., 1.54x)
noMultiplier: priceData.noMultiplier, // Payout ratio if NO wins (e.g., 2.85x)
marketReserves: priceData.marketReserves, // Total collateral locked (UI units)
yesTokenSupply: priceData.yesTokenSupply, // YES tokens minted (UI units)
noTokenSupply: priceData.noTokenSupply, // NO tokens minted (UI units)
});
// AMM Price Formulas:
// yesPrice = (marketReserves * yesTokenSupply) / (yesTokenSupply^2 + noTokenSupply^2)
// noPrice = (marketReserves * noTokenSupply) / (yesTokenSupply^2 + noTokenSupply^2)
// yesMultiplier = 1 + (noTokenSupply / yesTokenSupply)^2
// noMultiplier = 1 + (yesTokenSupply / noTokenSupply)^2fetchSettlementCriteria(market) — Get AI Resolution Infoconst criteria = await client.fetchSettlementCriteria(marketAddress);
// Returns: { category, reasoning, resolvable, resolution_sources, settlement_criteria }fetchSettlementData(market) — Get Settlement Decisionconst data = await client.fetchSettlementData(marketAddress);
// Returns: { answer: 'YES'|'NO', reasoning: string }trading.getMarketInfo(pubkey) — Extended Market Infoconst info = await client.trading.getMarketInfo(new PublicKey(marketAddress));
// Returns: { address, question, id, creator, initialLiquidity, marketReserves,
// endTime, resolvable, resolved, winningTokenId,
// yesTokenMint, noTokenMint, collateralToken,
// yesTokenSupplyMinted, noTokenSupplyMinted }market.createMarket(params)Creates a V2 AMM market using PNP's global oracle for resolution.
const result = await client.market.createMarket({
question: 'Will SOL hit $250 by end of March?',
initialLiquidity: 10_000_000n, // 10 USDC (6 decimals)
endTime: BigInt(Math.floor(Date.now() / 1000) + 7 * 86400), // 7 days
baseMint: new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
});
console.log('Market:', result.market.toBase58());
// Returns: { signature: string, market: PublicKey }| Parameter | Type | Required | Description |
|---|---|---|---|
question | string | Yes | The prediction question |
initialLiquidity | bigint | Yes | Initial liquidity in raw units (decimals depend on collateral token) |
endTime | bigint | Yes | Unix timestamp when trading ends |
baseMint | PublicKey | No | Collateral token mint — any SPL or Token-2022 token |
createMarketWithCustomOracle(params)When to use: When your AI agent needs full control over market resolution. Your agent's wallet becomes the oracle.
const result = await client.createMarketWithCustomOracle({
question: 'Will BTC hit $150K by Dec 2026?',
initialLiquidity: 10_000_000n, // 10 USDC (6 decimals)
endTime: BigInt(Math.floor(Date.now() / 1000) + 30 * 86400),
collateralMint: new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
settlerAddress: AGENT_WALLET_PUBKEY, // Your agent's wallet is the oracle
yesOddsBps: 5000, // Optional: 50/50 odds (range: 100-9900)
});
// Returns: { market: PublicKey, signature: string }| Parameter | Type | Required | Description |
|---|---|---|---|
question | string | Yes | The prediction question |
initialLiquidity | bigint | Yes | Initial liquidity in raw units |
endTime | bigint | Yes | Unix timestamp when trading ends |
collateralMint | PublicKey | Yes | Collateral token mint |
settlerAddress | PublicKey | Yes | Oracle wallet that will settle the market |
yesOddsBps | number | No | Initial YES odds in basis points (100-9900, default 5000) |
[!WARNING] After creation, you must call
setMarketResolvable(market, true)within 15 minutes or the market is permanently frozen.
createMarketV2WithCustomOdds(params)const result = await client.createMarketV2WithCustomOdds({
question: 'Will Ethereum flip Bitcoin by 2026?',
initialLiquidity: 50_000_000n, // 50 USDC
endTime: daysFromNow(90),
collateralTokenMint: USDC,
yesOddsBps: 2000, // 20% YES / 80% NO
oracle: CUSTOM_ORACLE_PUBKEY, // Optional: custom oracle
});
// Returns: { signature: string, market: string }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, // 1 USDC
endTime: daysFromNow(7),
collateralTokenMint: USDC,
});
// Returns: { signature: string, market: string, detectedTwitterUrl?, isTweetIdFormat? }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: daysFromNow(30),
collateralTokenMint: USDC,
});
// Returns: { signature: string, market: string, detectedYoutubeUrl? }Supported: https://youtu.be/ID, https://youtube.com/watch?v=ID, https://youtube.com/shorts/ID
createMarketDefiLlama(params)const result = await client.createMarketDefiLlama({
question: 'Will Uniswap TVL exceed $5B this quarter?',
protocolName: 'uniswap-v3',
metric: 'tvl',
initialLiquidity: 5_000_000n,
endTime: daysFromNow(30),
collateralTokenMint: USDC,
});
// Returns: { signature: string, market: string, detectedProtocol?, detectedMetric? }createP2PMarketGeneral(params)Direct peer-to-peer betting where the creator takes one side.
const result = await client.createP2PMarketGeneral({
question: 'Will our DAO pass Proposal #42?',
initialAmount: 100_000_000n, // 100 USDC (raw units, 6 decimals)
side: 'yes', // Creator bets YES
creatorSideCap: 500_000_000n, // Max 500 USDC on creator's side
endTime: daysFromNow(14),
collateralTokenMint: USDC,
});
// Returns: { signature: string, market: PubkeyLike, yesTokenMint: PubkeyLike, noTokenMint: PubkeyLike }createP2PMarketSimple(params)UI-friendly wrapper that handles USDC conversion automatically:
const result = await client.createP2PMarketSimple({
question: 'Will it rain tomorrow?',
side: 'yes',
amountUsdc: 50, // 50 USDC (human-readable, SDK converts)
daysUntilEnd: 1, // Defaults to 30 days
creatorSideCapMultiplier: 5, // 5x initial = 250 USDC cap (default)
});createP2PMarketTwitter(params) — P2P + Twitter URL detectioncreateP2PMarketYoutube(params) — P2P + YouTube URL detectioncreateP2PMarketDefiLlama(params) — P2P + DeFiLlama metricscreateP2PMarketTwitterSimple(params) — UI-friendly P2P TwittercreateP2PMarketYoutubeSimple(params) — UI-friendly P2P YouTubecreateP2PMarketDefiLlamaSimple(params) — UI-friendly P2P DeFiLlamacreateMarketP2PWithCustomOdds(params) — P2P with custom initial oddstrading.buyTokensUsdc(params)Purchases YES or NO outcome tokens using USDC collateral.
const result = await client.trading.buyTokensUsdc({
market: marketPubkey,
buyYesToken: true, // true = YES, false = NO
amountUsdc: 10, // 10 USDC (human-readable, SDK converts using mint decimals)
minimumOut: 0n, // Optional: minimum tokens received (slippage protection)
});
// Returns:
// { signature: string, usdcSpent: number, tokensReceived: number,
// before: BalanceSnapshot, after: BalanceSnapshot }trading.sellTokensBase(params)const result = await client.trading.sellTokensBase({
market: marketPubkey,
burnYesToken: true, // true = sell YES, false = sell NO
amountBaseUnits: 5_000_000n, // Raw token units (6 decimals)
});
// Returns: { signature: string, tokensSold: number, usdcReceived: number }buyV3TokensUsdc(params)const result = await client.buyV3TokensUsdc({
market: marketPubkey,
buyYesToken: true,
amountUsdc: 10, // Human-readable USDC
});
// Returns: { signature: string }Key Differences:
trading.buyTokensUsdc() — human-readable amountUsdcbuyV3TokensUsdc() — human-readable amountUsdctrading.sellTokensBase() — raw units amountBaseUnitssetMarketResolvable(market, resolvable, forceResolve?)When to use: Immediately after creating a custom oracle market. Activates trading.
await client.setMarketResolvable(marketAddress, true);
// Signature: setMarketResolvable(market: PublicKey | string, resolvable: boolean, forceResolve?: boolean)
// Returns: { signature: string }[!CAUTION] Must be called within 15 minutes of creation. After that, the market is permanently frozen and cannot be recovered. Create a new market instead.
For P2P markets: setMarketResolvableP2p(market, resolvable)
After endTime passes, use the proxy server to get the AI-suggested resolution, then settle:
// 1. Wait for settlement criteria (retries every 2s for up to 15 min)
const { resolvable, answer, criteria } = await client.waitForSettlementCriteria(marketAddress);
// 2. Settle the market if resolvable
if (resolvable) {
// Use the anchorMarket module for V2 settlement
const result = await client.anchorMarket.settleMarket({
market: new PublicKey(marketAddress),
yesWinner: answer === 'YES',
});
console.log('Settled:', result.signature);
}redeemPosition(market)Converts winning outcome tokens back to collateral after market settlement.
const { account: market } = await client.fetchMarket(marketPubkey);
if (!market.resolved) throw new Error('Market not settled yet');
const result = await client.redeemPosition(marketPubkey);
// Returns: { signature: string }redeemP2PPosition(market)const result = await client.redeemP2PPosition(marketPubkey);
// Returns: { signature: string }| Error | Cause | Solution |
|---|---|---|
0x1770 (InvalidLiquidity) | Liquidity below minimum | Use >= 1 USDC (1_000_000n) |
Insufficient funds for rent | Not enough SOL for account creation | Ensure >= 0.05 SOL in wallet |
Blockhash not found | Transaction expired before confirmation | Retry; use faster RPC (Helius/QuickNode) |
15-minute buffer expired | Didn't call setMarketResolvable in time | Market is permanently frozen; create new one |
TokenAccountNotFound | Missing Associated Token Account | SDK auto-creates ATAs, ensure SOL for rent |
Oracle mismatch | Wrong wallet trying to settle | Only designated oracle can settle |
Market not ended | Trying to settle before end time | Wait until market's endTime passes |
Market not tradable: ended | Trying to trade after endTime | Market has ended; no more trades allowed |
Insufficient collateral balance | Wallet balance below trade amount | Ensure wallet has enough USDC |
VALIDATION_ERROR | Invalid parameters | Check input types and ranges |
TRANSPORT_ERROR | Network/RPC failure | Retry with exponential backoff |
PROGRAM_ERROR | On-chain program error | Check .programErrorCode and .logs for details |
The SDK uses typed errors (SdkError, ValidationError, TransportError, ProgramError):
import { SdkError, ValidationError, TransportError, ProgramError } from 'pnp-sdk';
async function safeMarketOperation<T>(
operation: () => Promise<T>,
operationName: string
): Promise<{ ok: boolean; result?: T; error?: { code: string; message: string; retryable: boolean } }> {
try {
const result = await operation();
return { ok: true, result };
} catch (error: any) {
console.error(`${operationName} failed:`, error.message);
if (error instanceof TransportError || error.message?.includes('Blockhash')) {
return {
ok: false,
error: { code: 'TRANSPORT_ERROR', message: 'Network error. Retry with backoff.', retryable: true },
};
}
if (error instanceof ProgramError) {
return {
ok: false,
error: {
code: `PROGRAM_ERROR_${error.programErrorCode ?? 'UNKNOWN'}`,
message: error.message,
retryable: false,
},
};
}
if (error instanceof ValidationError) {
return {
ok: false,
error: { code: 'VALIDATION_ERROR', message: error.message, retryable: false },
};
}
if (error.message?.includes('Market not tradable')) {
return {
ok: false,
error: { code: 'MARKET_ENDED', message: error.message, retryable: false },
};
}
return {
ok: false,
error: { code: 'UNKNOWN', message: error.message || String(error), retryable: false },
};
}
}
// Usage
const result = await safeMarketOperation(
() => client.market.createMarket(params),
'Create Market'
);
if (!result.ok && result.error?.retryable) {
// Retry with exponential backoff
}PNP operations use these approximate CU limits internally:
| Operation | CU Limit |
|---|---|
| Market creation (V2) | 400,000 |
| Trading (mint/burn) | 600,000 |
| Settlement | 800,000 |
| Set market resolvable | 800,000 |
The SDK sets these automatically. For custom transactions, set explicit budgets:
import { ComputeBudgetProgram, Transaction } from '@solana/web3.js';
const tx = new Transaction();
tx.add(
ComputeBudgetProgram.setComputeUnitLimit({ units: 400_000 }),
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 50_000 })
);During network congestion, increase priority fees:
| Congestion | microLamports |
|---|---|
| Normal | 10,000 |
| Moderate | 50,000 |
| High | 100,000+ |
async function executeWithRetry(
action: () => Promise<string>,
maxRetries = 3,
timeoutMs = 30_000
): Promise<string> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await Promise.race([
action(),
new Promise<string>((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeoutMs)
),
]);
} catch (error: any) {
if (attempt === maxRetries) throw error;
const delay = Math.pow(2, attempt - 1) * 1000;
console.log(`Retry ${attempt} after ${delay}ms...`);
await new Promise(r => setTimeout(r, delay));
}
}
throw new Error('Max retries exceeded');
}function validateMarketParams(params: { question: string; initialLiquidity: bigint; endTime: bigint }) {
if (!params.question || params.question.length === 0) throw new Error('Question cannot be empty');
if (params.initialLiquidity < 1_000_000n) throw new Error('Min liquidity is 1 USDC (1_000_000n)');
if (params.endTime <= BigInt(Math.floor(Date.now() / 1000))) throw new Error('End time must be in the future');
}const RPC_URLS = [
process.env.RPC_URL || 'https://api.mainnet-beta.solana.com',
'https://mainnet.helius-rpc.com/?api-key=YOUR_KEY',
'https://solana-mainnet.g.alchemy.com/v2/YOUR_KEY',
];| Method | Scope | When to Use |
|---|---|---|
market.createMarket({...}) | Write | Standard V2 AMM markets |
createMarketWithCustomOracle({...}) | Write | Agent-controlled market resolution |
createMarketV2WithCustomOdds({...}) | Write | V2 with non-50/50 starting odds |
createP2PMarketGeneral({...}) | Write | P2P direct bets (raw units) |
createP2PMarketSimple({...}) | Write | P2P direct bets (UI-friendly) |
createMarketTwitter({...}) | Write | V2 markets linked to tweets |
createMarketYoutube({...}) | Write | V2 markets linked to videos |
createMarketDefiLlama({...}) | Write | V2 markets linked to DeFi metrics |
setMarketResolvable(market, true) | Write | Activate custom oracle markets (15 min!) |
setMarketResolvableP2p(market, true) | Write | Activate P2P custom oracle markets |
trading.buyTokensUsdc({...}) | Write | Buy YES/NO tokens on V2 markets |
trading.sellTokensBase({...}) | Write | Sell YES/NO tokens on V2 markets |
buyV3TokensUsdc({...}) | Write | Buy tokens on P2P/V3 markets |
redeemPosition(market) | Write | Redeem V2 winning position |
redeemP2PPosition(market) | Write | Redeem P2P winning position |
getMarketPriceV2(market) | Read | Current prices and multipliers |
fetchMarket(pubkey) | Read | On-chain market account data |
fetchMarketAddresses() | Read | List all V2 market addresses |
fetchMarkets() | Read | All V2 markets with full data |
fetchSettlementCriteria(market) | Read | AI resolution criteria |
fetchSettlementData(market) | Read | Settlement decision |
waitForSettlementCriteria(market) | Read | Retry until criteria available |
trading.getMarketInfo(pubkey) | Read | Extended market info |
trading.getBalances(market) | Read | User's token balances for market |
trading.getPrices(market) | Read | Token supply-based price shares |
PNPClient.parseSecretKey(str) | Static | Parse Base58 or JSON array private key |
client.uiToRaw(amount, decimals) | Util | Convert UI amount to raw bigint |
PNPClient.detectTwitterUrl(text) | Static | Extract Twitter URL from question |
PNPClient.detectYoutubeUrl(text) | Static | Extract YouTube URL from question |
PNPClient.detectDefiLlamaUrl(text) | Static | Extract DeFiLlama format from question |
All scripts are located in scripts/ and use dotenv/config to load .env.
| Script | Purpose | Run Command |
|---|---|---|
create-market.ts | Create standard V2 AMM market | tsx scripts/create-market.ts |
create-market-x.ts | Create Twitter/X engagement market | tsx scripts/create-market-x.ts |
create-market-yt.ts | Create YouTube views market | tsx scripts/create-market-yt.ts |
create-market-p2p.ts | Create P2P betting market | tsx scripts/create-market-p2p.ts |
create-market-custom.ts | Create custom oracle market | tsx scripts/create-market-custom.ts |
market-data.ts | Fetch market info & settlement data | tsx scripts/market-data.ts |
trade.ts | Buy/sell outcome tokens | tsx scripts/trade.ts --buy --market <addr> --outcome YES --amount 10 |
settle.ts | Resolve market as oracle | tsx scripts/settle.ts --market <addr> --outcome YES |
redeem.ts | Claim winnings after settlement | tsx scripts/redeem.ts --market <addr> |
pnp-sdk on npmsolana-skill/
├── SKILL.md # Main entry point (this file)
│ ├── When to Use / Triggers
│ ├── Program IDs & Precision
│ ├── Quick Start
│ ├── Market Lifecycle / State Machine
│ ├── Core Operations (Read-Only, Creation, Trading, Settlement, Redemption)
│ ├── Error Handling
│ ├── Production Hardening
│ └── SDK Quick Reference
│
├── README.md # Human-facing overview for GitHub
│
├── references/
│ ├── api-reference.md # Complete method signatures & parameter docs
│ ├── types-and-precision.md # TypeScript interfaces, decimal constants
│ ├── program-addresses.md # Program IDs, PDA derivations, token mints
│ ├── examples.md # Advanced code patterns
│ └── use-cases.md # Real-world prediction market patterns
│
├── scripts/ # CLI utilities for testing
│ ├── create-market.ts
│ ├── create-market-custom.ts
│ ├── create-market-x.ts
│ ├── create-market-yt.ts
│ ├── create-market-p2p.ts
│ ├── market-data.ts
│ ├── trade.ts
│ ├── settle.ts
│ └── redeem.ts
│
└── package.jsonProgressive disclosure: SKILL.md covers 80% of use cases. Reference files handle the deep details.
© internet-court, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 21 other files (scripts, references) in vendored/pnp/pnp-solana of internet-court/internet-court-skill.
Open the folder on GitHubat commit fa89195
PNP Prediction Markets on Solana next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| PNP Prediction Markets on Solana this skillinternet-court/internet-court-skill | 6.6k | — | ~7.5k | Automated safety check: Notes | MIT | |
| Pump TS Vanitynirholas/pump-fun-sdk | 134 | — | ~738 | Automated safety check: Pass | Custom licence | |
| Trust Wallet SDKtrustwallet/tw-agent-skills | 106 | — | ~364 | Automated safety check: Pass | MIT | |
| Stock Analysis24mlight/StockClaw | 101 | 2 repos | ~2k | Automated safety check: Notes | MIT | |
| Swapper Depositswapperfinance/swapper-toolkit | 852 | — | ~1.8k | Automated safety check: Pass | MIT | |
| Minara Crypto Trading and WalletMinara-AI/minara-skills | 362 | — | ~5.7k | Automated safety check: Pass | None |
nirholas/pump-fun-sdk
Educational single-threaded TypeScript vanity address generator for Solana using @solana/web3.js with async iteration, event-loop yielding, streaming generator API, and best-effort memory zeroization.
trustwallet/tw-agent-skills
Trust Wallet open-source libraries — Wallet Core (HD wallets, address derivation, tx signing in Swift/Kotlin/TypeScript/Go for 140+ chains), Web3 Provider (dApp connection for…
24mlight/StockClaw
Analyze stocks and cryptocurrencies using Yahoo Finance data.
swapperfinance/swapper-toolkit
Deposit and bridge funds into a wallet or protocol using Swapper Finance.
Minara-AI/minara-skills
Drives the Minara CLI for crypto swaps, perps, limit orders, wallet transfers, deposits and withdrawals, plus AI market analysis.
dex-original/okx-agent-trade-kit
A skill your agent uses when the user asks for: price of any asset, ticker, order book, candles, OHLCV, funding rate, open interest, OI change scanner, market screener (top movers, high-volume…
internet-court/internet-court-skill
Uploads one Kleros-related file per paid request to IPFS through the Kleros x402 gateway for 0.01 USDC on Base, returning a CID that Kleros contracts can reference.
internet-court/internet-court-skill
Guides building on the 0G Compute Network, a decentralized GPU marketplace for AI inference and fine-tuning, with SDK patterns and CLI commands.
internet-court/internet-court-skill
Connects an agent to the BNB Chain MCP server to read blocks and contracts, move tokens and NFTs, register ERC-8004 agents and use Greenfield storage.
internet-court/internet-court-skill
Specifies how a GenLayer Intelligent Contract decision about an agent's performance becomes an ERC-7710 revocation or policy change, through a relayer or bridge and an EVM controller.
internet-court/internet-court-skill
Specifies how a GenLayer Intelligent Contract should supervise an AI agent, with review rubrics, evidence schemas and continue, warn, constrain or revoke decisions.
internet-court/internet-court-skill
Pulls live crypto token data, DeFi metrics, wallet holdings, project research and Twitter/X signals through Heurist Mesh agents over a REST API.
Categories
Creates, trades and settles permissionless prediction markets on Solana with any SPL token as collateral, including social-media and custom-oracle markets. The agent can create prediction markets in three styles: V2 AMM markets, P2P direct bets, and custom-oracle markets that an AI agent can resolve. It can also build social-media markets on Twitter engagement, YouTube views or DeFiLlama metrics.
PNP Prediction Markets on Solana fits situations like: creating a prediction market on Solana with a chosen collateral token; settling a custom-oracle market after trading has ended; redeeming winning positions after a market settles; building a market on Twitter engagement or YouTube views.
Run `npx skills add internet-court/internet-court-skill --skill pnp-markets-solana -a claude-code`. Or copy the skill folder (vendored/pnp/pnp-solana in internet-court/internet-court-skill) into .claude/skills/pnp-markets-solana in your project. Claude Code loads it when a task matches its description.
Run `npx skills add internet-court/internet-court-skill --skill pnp-markets-solana -a codex`. Or copy the skill folder (vendored/pnp/pnp-solana in internet-court/internet-court-skill) into .agents/skills/pnp-markets-solana in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add internet-court/internet-court-skill --skill pnp-markets-solana -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/pnp-markets-solana, .gemini/skills/pnp-markets-solana, .github/skills/pnp-markets-solana and .opencode/skills/pnp-markets-solana in your project.
Going by SKILL.md and its folder, PNP Prediction Markets on Solana needs TypeScript for the scripts in its folder, the command-line tools its instructions call (tsx and npm) and credentials named PRIVATE_KEY. Our summary lists: Node.js 18 or newer; A Solana RPC endpoint (mainnet or devnet); A funded wallet with SOL for transaction fees; An SPL token, including Token-2022, as collateral. Compatibility (from SKILL.md): Requires Node.js 18+, Solana RPC endpoint (mainnet or devnet), funded wallet with SOL for transaction fees, and any SPL token (including Token-2022) as collateral.
SKILL.md names 10 domains. In commands or code: api.mainnet-beta.solana.com, x.com, youtu.be, youtube.com, twitter.com, mainnet.helius-rpc.com and solana-mainnet.g.alchemy.com; the agent is likely to contact these when it follows the instructions. As links in the text: npmjs.com, docs.pnp.exchange and solscan.io. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
PNP Prediction Markets on Solana is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 7.5k tokens (SKILL.md is roughly 30k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 10k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with PNP Prediction Markets on Solana: Pump TS Vanity (nirholas/pump-fun-sdk, 134 stars), Trust Wallet SDK (trustwallet/tw-agent-skills, 106 stars), Stock Analysis (24mlight/StockClaw, 101 stars) and Swapper Deposit (swapperfinance/swapper-toolkit, 852 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
internet-court (a GitHub organization) maintains it in internet-court/internet-court-skill, which has 6,551 GitHub stars. The repository holds 80 skills in this directory. The repository was last updated on August 19, 2026.
Source: internet-court/internet-court-skill on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.