LESSON 5 OF 10·Advanced10 min

How to Read Pump.fun Token Data On-Chain (Bonding Curve Account Layout)

Derive the bonding curve PDA, decode the account buffer, and read reserves, price, the creator/dev wallet, and migration status directly from Solana with web3.js — no Pump.fun API required.

Pump.fun’s HTTP API is convenient right up until it rate-limits, geo-blocks, or returns a 530 mid-launch. Everything it serves about a token’s curve lives on-chain and is readable with a single RPC call. This is the reliable way to do it.

What you’ll be able to read: live reserves, spot price, market cap, migration status, and the original creator (dev) wallet — all without touching Pump.fun’s servers.

The program and the account

Every Pump.fun token has a bonding curve account — a Program Derived Address (PDA) owned by the Pump.fun program. That account holds the curve state. You derive its address deterministically from the token mint, so given any contract address you can find its curve with no lookup table.

ThingValue
Pump.fun program ID6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P
PDA seeds"bonding-curve" + mint pubkey bytes
Account ownerThe Pump.fun program
EncodingAnchor account — 8-byte discriminator, then fields

Step 1 — Derive the bonding curve PDA

DERIVE PDA (@solana/web3.js)
import { PublicKey } from "@solana/web3.js";

const PUMP_PROGRAM = new PublicKey(
  "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
);

function bondingCurvePda(mint: PublicKey): PublicKey {
  const [pda] = PublicKey.findProgramAddressSync(
    [Buffer.from("bonding-curve"), mint.toBuffer()],
    PUMP_PROGRAM
  );
  return pda;
}

Step 2 — Fetch and decode the account

Pull the raw account with getAccountInfo and decode the buffer. The layout after the 8-byte Anchor discriminator is five u64 reserve fields, a one-byte complete boolean, and then the 32-bytecreator public key.

ACCOUNT LAYOUT
Offset  Size  Field
──────  ────  ─────────────────────────
0       8     discriminator (Anchor)
8       8     virtual_token_reserves  (u64, LE)
16      8     virtual_sol_reserves    (u64, LE)
24      8     real_token_reserves     (u64, LE)
32      8     real_sol_reserves       (u64, LE)
40      8     token_total_supply      (u64, LE)
48      1     complete                (bool)
49      32    creator                 (Pubkey)  ← the dev wallet
DECODE
import { Connection, PublicKey } from "@solana/web3.js";

const connection = new Connection("https://api.mainnet-beta.solana.com");

async function readCurve(mintAddress: string) {
  const mint = new PublicKey(mintAddress);
  const pda  = bondingCurvePda(mint);

  const acct = await connection.getAccountInfo(pda);
  if (!acct) return null;                 // no curve → not a pump.fun token
  const b = acct.data;

  return {
    virtualTokenReserves: b.readBigUInt64LE(8),
    virtualSolReserves:   b.readBigUInt64LE(16),
    realTokenReserves:    b.readBigUInt64LE(24),
    realSolReserves:      b.readBigUInt64LE(32),
    tokenTotalSupply:     b.readBigUInt64LE(40),
    complete:             b.readUInt8(48) === 1,
    creator:              new PublicKey(b.subarray(49, 81)).toBase58(),
  };
}

Step 3 — Turn reserves into price and market cap

DERIVE PRICE
const c = await readCurve(mint);

const sol   = Number(c.virtualSolReserves)   / 1e9;   // lamports → SOL
const toks  = Number(c.virtualTokenReserves) / 1e6;   // base → tokens (6 dp)

const priceSol = sol / toks;                          // SOL per token
const mcapUsd  = priceSol * solPriceUsd * 1_000_000_000;

console.log({ priceSol, complete: c.complete, dev: c.creator });

Reading the dev wallet — and verifying it

The creator field at offset 49 is the wallet that deployed the token. It is authoritative and tamper-proof — it is written by the program at creation. You can cross-check it against the oldest transaction on the bonding curve account (its fee payer will be the same wallet), which is a useful sanity check when you first wire this up.

This is exactly how MemeAscend verifies dev-wallet sign-in: derive the PDA, read offset 49, and compare it to the connected wallet’s public key. No API dependency, so it keeps working even when Pump.fun’s endpoints are down.

Gotchas

  • Public RPC is rate-limited. api.mainnet-beta.solana.com is fine for testing; use Helius/QuickNode/Triton for anything production.
  • Migrated tokens still have the account. After graduation the complete flag is true but the account persists — always read the flag, don’t assume.
  • Endianness matters. All integers are little-endian. Use readBigUInt64LE, not the big-endian variant.
  • Not every SPL token is a Pump.fun token. If getAccountInfo on the derived PDA returns null, there is no curve — it wasn’t launched on Pump.fun.

FAQ

Do I need an API key for any of this?
No. It's plain Solana RPC. Any endpoint that supports getAccountInfo works, including the public one for light usage.
How do I find the dev/creator wallet of a pump.fun token?
Derive the bonding curve PDA from the mint, fetch the account, and read the 32-byte Pubkey at offset 49. That is the creator wallet, written on-chain at launch.
Will this break when the Pump.fun API goes down?
No — that's the point. You are reading Solana directly. As long as the chain and your RPC are up, it works.
Is the account layout stable?
The layout described here matches current mainnet accounts. Anchor programs can change layouts across upgrades, so validate against a known token when a major protocol update ships.