npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pnp-adapter

v0.1.2

Published

Official SDK for PNP-Adapter - Decentralized AI-Powered Prediction Marketplace on Solana

Downloads

251

Readme

PNP-ADAPTER

TypeScript SDK for interacting with the PNP Protocol on Solana - a decentralized prediction marketplace that uses AI to settle markets.

Installation

npm install pnp-adapter

Or with yarn/pnpm:

npm install pnp-adapter
yarn add pnp-adapter

Quick Start

import { PnpClient } from "pnp-adapter";
import { PublicKey } from "@solana/web3.js";

const client = new PnpClient({
  rpcUrl: "https://api.mainnet-beta.solana.com",
});

const { transaction, blockhash, lastValidBlockHeight } = await client.buyV3Tokens(
  userWalletPublicKey,
  {
    marketAddress: "...",
    amount: 10_000_000,
    side: { yes: {} },
  }
);

Features

  • Transaction Builder Pattern: SDK returns unsigned transactions for you to sign
  • Multi-version Support: V1, V2, and V3 market support
  • TypeScript First: Full type safety with TypeScript
  • No Wallet Dependency: Uses noop wallet internally, you handle signing
  • Slippage Calculations: Built-in price impact calculations

Integration Examples

Frontend (React + Wallet Adapter)

import { useWallet, useConnection } from "@solana/wallet-adapter-react";
import { PnpClient } from "pnp-adapter";

function BuyTokensButton({ marketAddress, amount, side }) {
  const { publicKey, signTransaction } = useWallet();
  const { connection } = useConnection();

  const handleBuy = async () => {
    if (!publicKey || !signTransaction) return;

    const client = new PnpClient({
      rpcUrl: connection.rpcEndpoint,
    });

    const { transaction, blockhash, lastValidBlockHeight } = await client.buyV3Tokens(
      publicKey,
      {
        marketAddress,
        amount,
        side,
        minimumTokensOut: 0,
      }
    );

    const signed = await signTransaction(transaction);
    const signature = await connection.sendRawTransaction(signed.serialize());

    await connection.confirmTransaction({
      signature,
      blockhash,
      lastValidBlockHeight,
    });

    console.log("Transaction confirmed:", signature);
  };

  return <button onClick={handleBuy}>Buy Tokens</button>;
}

Frontend (Vue.js + Solana Wallet)

import { PnpClient } from "pnp-adapter";
import { useWallet } from "solana-wallets-vue";

const { publicKey, signTransaction } = useWallet();
const client = new PnpClient({
  rpcUrl: "https://api.mainnet-beta.solana.com",
});

async function buyTokens(marketAddress: string, amount: number) {
  if (!publicKey.value || !signTransaction.value) return;

  const { transaction, blockhash, lastValidBlockHeight } = await client.buyV3Tokens(
    publicKey.value,
    {
      marketAddress,
      amount,
      side: { yes: {} },
    }
  );

  const signed = await signTransaction.value(transaction);
  const connection = client.getConnection();
  const signature = await connection.sendRawTransaction(signed.serialize());

  await connection.confirmTransaction({
    signature,
    blockhash,
    lastValidBlockHeight,
  });

  return signature;
}

Server-side (Node.js)

import { PnpClient, toBaseUnits } from "pnp-adapter";
import { Keypair, Connection } from "@solana/web3.js";
import bs58 from "bs58";

const privateKey = process.env.WALLET_PRIVATE_KEY!;
const keypair = Keypair.fromSecretKey(bs58.decode(privateKey));

const client = new PnpClient({
  rpcUrl: process.env.RPC_URL!,
  commitment: "confirmed",
});

async function executeTrade(marketAddress: string, usdcAmount: number) {
  const { transaction, blockhash, lastValidBlockHeight } = await client.buyV3Tokens(
    keypair.publicKey,
    {
      marketAddress,
      amount: toBaseUnits(usdcAmount),
      side: { yes: {} },
    }
  );

  transaction.sign(keypair);

  const connection = client.getConnection();
  const signature = await connection.sendRawTransaction(transaction.serialize(), {
    skipPreflight: false,
    preflightCommitment: "confirmed",
  });

  const confirmation = await connection.confirmTransaction({
    signature,
    blockhash,
    lastValidBlockHeight,
  });

  if (confirmation.value.err) {
    throw new Error(`Transaction failed: ${confirmation.value.err}`);
  }

  return signature;
}

executeTrade("market-address-here", 10)
  .then(console.log)
  .catch(console.error);

AI Agent / Bot Integration

import { PnpClient, toBaseUnits, fromBaseUnits } from "pnp-adapter";
import { Keypair } from "@solana/web3.js";

class PredictionMarketAgent {
  private client: PnpClient;
  private wallet: Keypair;

  constructor(rpcUrl: string, privateKey: Uint8Array) {
    this.client = new PnpClient({ rpcUrl });
    this.wallet = Keypair.fromSecretKey(privateKey);
  }

  async getMarketPrices(marketAddress: string) {
    const data = await this.client.getMarketPricesAndData(marketAddress);
    if (!data) throw new Error("Market not found");
    return data.prices;
  }

  async placeBet(marketAddress: string, side: "yes" | "no", amount: number) {
    const { transaction } = await this.client.buyV3Tokens(this.wallet.publicKey, {
      marketAddress,
      amount: toBaseUnits(amount),
      side: side === "yes" ? { yes: {} } : { no: {} },
    });

    transaction.sign(this.wallet);
    const connection = this.client.getConnection();
    return connection.sendRawTransaction(transaction.serialize());
  }

  async analyzeAndTrade(marketAddress: string) {
    const prices = await this.getMarketPrices(marketAddress);

    if (prices.yesPrice < 0.3) {
      console.log("YES token undervalued, buying...");
      return this.placeBet(marketAddress, "yes", 10);
    } else if (prices.noPrice < 0.3) {
      console.log("NO token undervalued, buying...");
      return this.placeBet(marketAddress, "no", 10);
    }

    console.log("No opportunity found");
    return null;
  }
}

Express.js API Server

import express from "express";
import { PnpClient, toBaseUnits } from "pnp-adapter";
import { Keypair, PublicKey } from "@solana/web3.js";

const app = express();
app.use(express.json());

const client = new PnpClient({
  rpcUrl: process.env.RPC_URL!,
});

app.get("/api/markets/:address", async (req, res) => {
  try {
    const data = await client.getMarketPricesAndData(req.params.address);
    if (!data) {
      return res.status(404).json({ error: "Market not found" });
    }
    res.json(data);
  } catch (error) {
    res.status(500).json({ error: "Failed to fetch market data" });
  }
});

app.get("/api/markets/:address/price/:side", async (req, res) => {
  try {
    const side = req.params.side as "yes" | "no";
    const price = await client.getPrice(req.params.address, side);
    res.json({ price });
  } catch (error) {
    res.status(500).json({ error: "Failed to fetch price" });
  }
});

app.post("/api/build-transaction", async (req, res) => {
  try {
    const { userPublicKey, marketAddress, amount, side } = req.body;

    const { transaction, blockhash, lastValidBlockHeight } = await client.buyV3Tokens(
      new PublicKey(userPublicKey),
      {
        marketAddress,
        amount: toBaseUnits(amount),
        side: side === "yes" ? { yes: {} } : { no: {} },
      }
    );

    res.json({
      transaction: transaction.serialize({ requireAllSignatures: false }).toString("base64"),
      blockhash,
      lastValidBlockHeight,
    });
  } catch (error) {
    res.status(500).json({ error: "Failed to build transaction" });
  }
});

app.listen(3000, () => console.log("Server running on port 3000"));

API Reference

PnpClient

Constructor

const client = new PnpClient({
  rpcUrl: string,
  programId?: PublicKey,
  commitment?: "processed" | "confirmed" | "finalized",
});

Market Creation

await client.createMarket(creator, { question, initialLiquidity, endTime });
await client.createMarketV2(payer, creator, { question, initialLiquidity, endTime });
await client.createMarketV3(payer, creator, { question, initialAmount, side, creatorSideCap, endTime, maxPotRatio });

Trading

await client.mintDecisionTokens(buyer, { marketAddress, amount, isYes, creatorAddress, minimumOut? });
await client.burnDecisionTokens(buyer, { marketAddress, amount, isYes, creatorAddress });
await client.buyV3Tokens(buyer, { marketAddress, amount, side, minimumTokensOut? });

Redemption

await client.redeemPosition(user, { marketAddress, marketCreatorAddress, yesTokenAddress, noTokenAddress });
await client.redeemPositionV2(user, params);
await client.redeemV3Position(redeemer, params);

Creator Functions

await client.claimCreatorFee(creator);
await client.creatorRefund(creator, { marketAddress, yesTokenAddress, noTokenAddress });
await client.creatorRefundV2(creator, marketAddress);
await client.creatorRefundV3(creator, marketAddress);

Read Functions

await client.getMarketVersion(marketAddress);
await client.getMarketData(marketAddress);
await client.getMarketPricesAndData(marketAddress);
await client.getPrice(marketAddress, "yes" | "no");
await client.getMarketTokenAddresses(marketAddress);
await client.getGlobalConfig();

Utility Functions

import {
  shortenAddress,
  toBaseUnits,
  fromBaseUnits,
  calculateMintingSlippage,
  calculateBurnSlippage,
  getTokenBalance,
  getUserTokenBalance,
  getMultipleTokenBalances,
  getCachedData,
  setCachedData,
  clearCache,
} from "pnp-adapter";

shortenAddress("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", 4);

const baseUnits = toBaseUnits(10);
const humanUnits = fromBaseUnits(10_000_000);

const { tokensToMint, priceImpact } = calculateMintingSlippage(
  collateralAmount,
  marketReserves,
  supplyToMint,
  supplyOther
);

const { collateralOut, priceImpact } = calculateBurnSlippage(
  tokensToBurn,
  marketReserves,
  supplyToBurn,
  supplyOther
);

PDA Derivation

import {
  getGlobalConfigPDA,
  getMarketPDA,
  getMarketV3PDA,
  getYesTokenMintPDA,
  getNoTokenMintPDA,
  getCreatorFeeTreasuryPDA,
} from "pnp-adapter";

Types

import type {
  TokenSide,
  TransactionResult,
  MarketData,
  MarketPricesAndData,
  MarketTokenAddresses,
  MarketVersion,
  CreateMarketParams,
  CreateMarketV2Params,
  CreateMarketV3Params,
  BuyTokensParams,
  MintTokensParams,
  BurnTokensParams,
  RedeemParams,
} from "pnp-adapter";

const yesSide: TokenSide = { yes: {} };
const noSide: TokenSide = { no: {} };

Constants

import {
  PROGRAM_ID,
  COLLATERAL_TOKEN_MINT,
  METADATA_PROGRAM_ID,
  DEVNET_RPC_URL,
  MAINNET_RPC_URL,
  DECIMALS,
} from "pnp-adapter";

Transaction Flow

The SDK follows a transaction builder pattern:

  1. Build Transaction: SDK constructs the transaction with all required accounts
  2. Return to Caller: Transaction is returned unsigned with blockhash info
  3. Sign Transaction: You sign with your wallet (frontend) or keypair (server)
  4. Send Transaction: You send the signed transaction to the network
const { transaction, blockhash, lastValidBlockHeight } = await client.buyV3Tokens(...);

transaction.sign(keypair);

const signature = await connection.sendRawTransaction(transaction.serialize());

await connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight });

Error Handling

try {
  const { transaction } = await client.buyV3Tokens(buyer, params);
} catch (error) {
  if (error.message.includes("Account not found")) {
    console.error("Market does not exist");
  } else if (error.message.includes("insufficient funds")) {
    console.error("Insufficient balance");
  } else {
    console.error("Transaction failed:", error);
  }
}

Development

npm install

npm run build

npm test

npm run lint

npm run format

Scripts

| Command | Description | |---------|-------------| | npm run build | Build ESM, CJS, and type declarations | | npm run build:esm | Build ESM only | | npm run build:cjs | Build CJS only | | npm run build:types | Build type declarations only | | npm test | Run tests | | npm run lint | Lint code | | npm run format | Format code | | npm run clean | Clean build artifacts |

License

MIT