| name | pumpfun |
| creator | raunit-dev |
| description | Complete PumpFun Protocol guide for building token launches, bonding curves, and AMM integrations on Solana. Covers Pump Program (token creation, buy/sell on bonding curves), PumpSwap AMM (liquidity pools, swaps), fee structures, creator fees, and SDK integration. |
PumpFun Protocol Integration Guide
A comprehensive guide for building applications with PumpFun - Solana's leading token launch and AMM protocol enabling instant trading without initial liquidity.
Overview
PumpFun is a token launch and trading protocol on Solana offering:
- Pump Program - Create SPL tokens with instant trading on bonding curves
- PumpSwap (AMM) - Constant-product automated market maker for graduated tokens
- Creator Fees - Automatic fee distribution to token creators
- Token2022 Support - Modern token standard via
create_v2 instruction
- Mayhem Mode - Special mode for enhanced token launches
Program IDs
| Program | Address |
|---|
| Pump Program | 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P |
| PumpSwap AMM | pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA |
| Pump Fees | pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ |
| Mayhem Program | MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e |
Quick Start
Installation
npm install @pump-fun/pump-sdk @pump-fun/pump-swap-sdk
pnpm add @pump-fun/pump-sdk @pump-fun/pump-swap-sdk
Basic Setup
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import bs58 from 'bs58';
const connection = new Connection('https://api.mainnet-beta.solana.com');
const wallet = Keypair.fromSecretKey(bs58.decode('YOUR_SECRET_KEY'));
const PUMP_PROGRAM_ID = new PublicKey('6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P');
const PUMP_AMM_PROGRAM_ID = new PublicKey('pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA');
const PUMP_FEES_PROGRAM_ID = new PublicKey('pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ');
Pump Program (Bonding Curves)
The Pump program enables creation of SPL tokens with instant trading on a bonding curve without requiring initial liquidity.
How Bonding Curves Work
- Token Creation - Create a token with initial virtual reserves
- Trading - Users buy/sell on the bonding curve using Uniswap V2 formula
- Graduation - When market cap threshold is reached, liquidity migrates to PumpSwap
- LP Burn - LP tokens are burned, making liquidity permanent
Global Configuration
interface Global {
initialized: boolean;
authority: PublicKey;
feeRecipient: PublicKey;
initialVirtualTokenReserves: bigint;
initialVirtualSolReserves: bigint;
initialRealTokenReserves: bigint;
tokenTotalSupply: bigint;
feeBasisPoints: bigint;
creatorFeeBasisPoints: bigint;
}
Bonding Curve Account
interface BondingCurve {
virtualTokenReserves: bigint;
virtualSolReserves: bigint;
realTokenReserves: bigint;
realSolReserves: bigint;
tokenTotalSupply: bigint;
complete: boolean;
creator: PublicKey;
isMayhemMode: boolean;
}
Deriving PDAs
import { PublicKey } from '@solana/web3.js';
const PUMP_PROGRAM_ID = new PublicKey('6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P');
function getBondingCurvePDA(mint: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('bonding-curve'), mint.toBuffer()],
PUMP_PROGRAM_ID
);
}
function getAssociatedBondingCurve(mint: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[
Buffer.from('associated-bonding-curve'),
mint.toBuffer()
],
PUMP_PROGRAM_ID
);
}
function getCreatorVaultPDA(creator: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('creator-vault'), creator.toBuffer()],
PUMP_PROGRAM_ID
);
}
function getGlobalPDA(): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('global')],
PUMP_PROGRAM_ID
);
}
Create Token (Legacy SPL)
import {
Connection,
Keypair,
PublicKey,
Transaction,
TransactionInstruction,
SystemProgram,
SYSVAR_RENT_PUBKEY,
} from '@solana/web3.js';
import {
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID,
getAssociatedTokenAddressSync,
} from '@solana/spl-token';
async function createToken(
connection: Connection,
payer: Keypair,
name: string,
symbol: string,
uri: string
): Promise<string> {
const mint = Keypair.generate();
const [bondingCurve] = getBondingCurvePDA(mint.publicKey);
const [associatedBondingCurve] = getAssociatedBondingCurve(mint.publicKey);
const [global] = getGlobalPDA();
const METADATA_PROGRAM_ID = new PublicKey('metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s');
const [metadata] = PublicKey.findProgramAddressSync(
[
Buffer.from('metadata'),
METADATA_PROGRAM_ID.toBuffer(),
mint.publicKey.toBuffer(),
],
METADATA_PROGRAM_ID
);
const nameBuffer = Buffer.from(name);
const symbolBuffer = Buffer.from(symbol);
const uriBuffer = Buffer.from(uri);
const data = Buffer.alloc(
8 + 4 + nameBuffer.length + 4 + symbolBuffer.length + 4 + uriBuffer.length
);
const discriminator = Buffer.from([0x18, 0x1e, 0xc8, 0x28, 0x05, 0x1c, 0x07, 0x77]);
discriminator.copy(data, 0);
let offset = 8;
data.writeUInt32LE(nameBuffer.length, offset);
offset += 4;
nameBuffer.copy(data, offset);
offset += nameBuffer.length;
data.writeUInt32LE(symbolBuffer.length, offset);
offset += 4;
symbolBuffer.copy(data, offset);
offset += symbolBuffer.length;
data.writeUInt32LE(uriBuffer.length, offset);
offset += 4;
uriBuffer.copy(data, offset);
const instruction = new TransactionInstruction({
programId: PUMP_PROGRAM_ID,
keys: [
{ pubkey: mint.publicKey, isSigner: true, isWritable: true },
{ pubkey: payer.publicKey, isSigner: false, isWritable: true },
{ pubkey: bondingCurve, isSigner: false, isWritable: true },
{ pubkey: associatedBondingCurve, isSigner: false, isWritable: true },
{ pubkey: global, isSigner: false, isWritable: false },
{ pubkey: METADATA_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: metadata, isSigner: false, isWritable: true },
{ pubkey: payer.publicKey, isSigner: true, isWritable: true },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
],
data,
});
const tx = new Transaction().add(instruction);
tx.feePayer = payer.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.sign(payer, mint);
const signature = await connection.sendRawTransaction(tx.serialize());
await connection.confirmTransaction(signature);
return mint.publicKey.toBase58();
}
Create Token V2 (Token2022)
const createV2Accounts = [
'mint',
'mintAuthority',
'bondingCurve',
'associatedBondingCurve',
'global',
'user',
'systemProgram',
'token2022Program',
'associatedTokenProgram',
'rent',
'mayhemProgram',
'mayhemFeeRecipient',
'eventAuthority',
'program',
];
Buy Tokens on Bonding Curve
interface BuyArgs {
amount: bigint;
maxSolCost: bigint;
}
async function buyTokens(
connection: Connection,
payer: Keypair,
mint: PublicKey,
amount: bigint,
maxSolCost: bigint
): Promise<string> {
const [bondingCurve] = getBondingCurvePDA(mint);
const [associatedBondingCurve] = getAssociatedBondingCurve(mint);
const [global] = getGlobalPDA();
const bondingCurveData = await connection.getAccountInfo(bondingCurve);
const creator = parseCreatorFromBondingCurve(bondingCurveData);
const [creatorVault] = getCreatorVaultPDA(creator);
const userAta = getAssociatedTokenAddressSync(mint, payer.publicKey);
const feeRecipient = new PublicKey('FEE_RECIPIENT_ADDRESS');
const data = Buffer.alloc(8 + 8 + 8);
const discriminator = Buffer.from([0x66, 0x06, 0x3d, 0x12, 0x01, 0xda, 0xeb, 0xea]);
discriminator.copy(data, 0);
data.writeBigUInt64LE(amount, 8);
data.writeBigUInt64LE(maxSolCost, 16);
const instruction = new TransactionInstruction({
programId: PUMP_PROGRAM_ID,
keys: [
{ pubkey: global, isSigner: false, isWritable: false },
{ pubkey: feeRecipient, isSigner: false, isWritable: true },
{ pubkey: mint, isSigner: false, isWritable: false },
{ pubkey: bondingCurve, isSigner: false, isWritable: true },
{ pubkey: associatedBondingCurve, isSigner: false, isWritable: true },
{ pubkey: userAta, isSigner: false, isWritable: true },
{ pubkey: payer.publicKey, isSigner: true, isWritable: true },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
{ pubkey: creatorVault, isSigner: false, isWritable: true },
{ pubkey: PUMP_FEES_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: feeConfigPDA, isSigner: false, isWritable: false },
],
data,
});
const accountInfo = await connection.getAccountInfo(bondingCurve);
if (accountInfo && accountInfo.data.length < 150) {
const extendIx = createExtendAccountInstruction(bondingCurve);
const tx = new Transaction().add(extendIx, instruction);
} else {
const tx = new Transaction().add(instruction);
}
tx.feePayer = payer.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.sign(payer);
const signature = await connection.sendRawTransaction(tx.serialize());
await connection.confirmTransaction(signature);
return signature;
}
Sell Tokens on Bonding Curve
interface SellArgs {
amount: bigint;
minSolOutput: bigint;
}
async function sellTokens(
connection: Connection,
payer: Keypair,
mint: PublicKey,
amount: bigint,
minSolOutput: bigint
): Promise<string> {
const [bondingCurve] = getBondingCurvePDA(mint);
const [associatedBondingCurve] = getAssociatedBondingCurve(mint);
const [global] = getGlobalPDA();
const bondingCurveData = await connection.getAccountInfo(bondingCurve);
const creator = parseCreatorFromBondingCurve(bondingCurveData);
const [creatorVault] = getCreatorVaultPDA(creator);
const userAta = getAssociatedTokenAddressSync(mint, payer.publicKey);
const feeRecipient = new PublicKey('FEE_RECIPIENT_ADDRESS');
const data = Buffer.alloc(8 + 8 + 8);
const discriminator = Buffer.from([0x33, 0xe6, 0x85, 0xa4, 0x01, 0x7f, 0x83, 0xad]);
discriminator.copy(data, 0);
data.writeBigUInt64LE(amount, 8);
data.writeBigUInt64LE(minSolOutput, 16);
const instruction = new TransactionInstruction({
programId: PUMP_PROGRAM_ID,
keys: [
{ pubkey: global, isSigner: false, isWritable: false },
{ pubkey: feeRecipient, isSigner: false, isWritable: true },
{ pubkey: mint, isSigner: false, isWritable: false },
{ pubkey: bondingCurve, isSigner: false, isWritable: true },
{ pubkey: associatedBondingCurve, isSigner: false, isWritable: true },
{ pubkey: userAta, isSigner: false, isWritable: true },
{ pubkey: payer.publicKey, isSigner: true, isWritable: true },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
{ pubkey: creatorVault, isSigner: false, isWritable: true },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: PUMP_FEES_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: feeConfigPDA, isSigner: false, isWritable: false },
],
data,
});
const tx = new Transaction().add(instruction);
tx.feePayer = payer.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.sign(payer);
const signature = await connection.sendRawTransaction(tx.serialize());
return signature;
}
Calculate Price (Bonding Curve Math)
interface BondingCurveState {
virtualTokenReserves: bigint;
virtualSolReserves: bigint;
realTokenReserves: bigint;
realSolReserves: bigint;
}
function calculateBuyQuote(
state: BondingCurveState,
solAmountIn: bigint,
feeBasisPoints: bigint = 100n
): bigint {
const netSol = (solAmountIn * 10000n) / (10000n + feeBasisPoints);
const tokensOut = (netSol * state.virtualTokenReserves) /
(state.virtualSolReserves + netSol);
return tokensOut > state.realTokenReserves ? state.realTokenReserves : tokensOut;
}
function calculateSellQuote(
state: BondingCurveState,
tokenAmountIn: bigint,
feeBasisPoints: bigint = 100n
): bigint {
const grossSol = (tokenAmountIn * state.virtualSolReserves) /
(state.virtualTokenReserves + tokenAmountIn);
const netSol = (grossSol * (10000n - feeBasisPoints)) / 10000n;
return netSol > state.realSolReserves ? state.realSolReserves : netSol;
}
function calculateMarketCap(state: BondingCurveState, tokenSupply: bigint): bigint {
return (state.virtualSolReserves * tokenSupply) / state.virtualTokenReserves;
}
Migration to PumpSwap
When a bonding curve completes (real tokens exhausted), liquidity can be migrated to PumpSwap:
async function migrateToAMM(
connection: Connection,
payer: Keypair,
mint: PublicKey
): Promise<string> {
const [bondingCurve] = getBondingCurvePDA(mint);
const discriminator = Buffer.from([0x9d, 0xaf, 0x1e, 0x65, 0xe8, 0x69, 0x9b, 0x26]);
const instruction = new TransactionInstruction({
programId: PUMP_PROGRAM_ID,
keys: [
],
data: discriminator,
});
const tx = new Transaction().add(instruction);
tx.feePayer = payer.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.sign(payer);
return await connection.sendRawTransaction(tx.serialize());
}
PumpSwap (AMM)
PumpSwap is a constant-product AMM for tokens that have graduated from the bonding curve.
Global Config
const GLOBAL_CONFIG = new PublicKey('ADyA8hdefvWN2dbGGWFotbzWxrAvLW83WG6QCVXvJKqw');
interface GlobalConfig {
admin: PublicKey;
lpFeeBasisPoints: number;
protocolFeeBasisPoints: number;
coinCreatorFeeBasisPoints: number;
disableFlags: number;
protocolFeeRecipients: PublicKey[];
tokenIncentivesEnabled: boolean;
}
Pool Account
interface Pool {
bump: number;
poolCreator: PublicKey;
baseMint: PublicKey;
quoteMint: PublicKey;
lpMint: PublicKey;
poolBaseTokenAccount: PublicKey;
poolQuoteTokenAccount: PublicKey;
lpSupply: bigint;
coinCreator: PublicKey;
isMayhemMode: boolean;
}
Deriving Pool PDAs
const PUMP_AMM_PROGRAM_ID = new PublicKey('pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA');
function getPoolPDA(
index: number,
creator: PublicKey,
baseMint: PublicKey,
quoteMint: PublicKey
): [PublicKey, number] {
const indexBuffer = Buffer.alloc(2);
indexBuffer.writeUInt16LE(index);
return PublicKey.findProgramAddressSync(
[
Buffer.from('pool'),
indexBuffer,
creator.toBuffer(),
baseMint.toBuffer(),
quoteMint.toBuffer(),
],
PUMP_AMM_PROGRAM_ID
);
}
function getLpMintPDA(pool: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('pool_lp_mint'), pool.toBuffer()],
PUMP_AMM_PROGRAM_ID
);
}
function getPoolTokenAccountPDA(pool: PublicKey, mint: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('pool_token_account'), pool.toBuffer(), mint.toBuffer()],
PUMP_AMM_PROGRAM_ID
);
}
function getCreatorVaultAuthorityPDA(coinCreator: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('creator_vault'), coinCreator.toBuffer()],
PUMP_AMM_PROGRAM_ID
);
}
Swap on PumpSwap
interface SwapArgs {
baseAmountIn: bigint;
quoteAmountIn: bigint;
minAmountOut: bigint;
}
async function swapOnPumpSwap(
connection: Connection,
payer: Keypair,
pool: PublicKey,
amountIn: bigint,
minAmountOut: bigint,
isBuy: boolean
): Promise<string> {
const poolData = await fetchPoolData(connection, pool);
const userBaseAta = getAssociatedTokenAddressSync(
poolData.baseMint,
payer.publicKey
);
const userQuoteAta = getAssociatedTokenAddressSync(
poolData.quoteMint,
payer.publicKey
);
const [creatorVaultAuthority] = getCreatorVaultAuthorityPDA(poolData.coinCreator);
const creatorVaultAta = getAssociatedTokenAddressSync(
poolData.quoteMint,
creatorVaultAuthority,
true
);
const data = Buffer.alloc(8 + 8 + 8 + 8);
const discriminator = isBuy
? Buffer.from([0x66, 0x06, 0x3d, 0x12, 0x01, 0xda, 0xeb, 0xea])
: Buffer.from([0x33, 0xe6, 0x85, 0xa4, 0x01, 0x7f, 0x83, 0xad]);
discriminator.copy(data, 0);
data.writeBigUInt64LE(isBuy ? 0n : amountIn, 8);
data.writeBigUInt64LE(isBuy ? amountIn : 0n, 16);
data.writeBigUInt64LE(minAmountOut, 24);
const instruction = new TransactionInstruction({
programId: PUMP_AMM_PROGRAM_ID,
keys: [
{ pubkey: pool, isSigner: false, isWritable: true },
{ pubkey: payer.publicKey, isSigner: true, isWritable: true },
{ pubkey: GLOBAL_CONFIG, isSigner: false, isWritable: false },
{ pubkey: poolData.baseMint, isSigner: false, isWritable: false },
{ pubkey: poolData.quoteMint, isSigner: false, isWritable: false },
{ pubkey: userBaseAta, isSigner: false, isWritable: true },
{ pubkey: userQuoteAta, isSigner: false, isWritable: true },
{ pubkey: poolData.poolBaseTokenAccount, isSigner: false, isWritable: true },
{ pubkey: poolData.poolQuoteTokenAccount, isSigner: false, isWritable: true },
{ pubkey: protocolFeeRecipient, isSigner: false, isWritable: true },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: creatorVaultAta, isSigner: false, isWritable: true },
{ pubkey: creatorVaultAuthority, isSigner: false, isWritable: false },
{ pubkey: PUMP_FEES_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: feeConfigPDA, isSigner: false, isWritable: false },
],
data,
});
const poolInfo = await connection.getAccountInfo(pool);
if (poolInfo && poolInfo.data.length < 300) {
const extendIx = createExtendAccountInstruction(pool);
const tx = new Transaction().add(extendIx, instruction);
} else {
const tx = new Transaction().add(instruction);
}
tx.feePayer = payer.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.sign(payer);
return await connection.sendRawTransaction(tx.serialize());
}
Add Liquidity
async function addLiquidity(
connection: Connection,
payer: Keypair,
pool: PublicKey,
baseAmount: bigint,
quoteAmount: bigint,
minLpTokens: bigint
): Promise<string> {
const poolData = await fetchPoolData(connection, pool);
const userBaseAta = getAssociatedTokenAddressSync(poolData.baseMint, payer.publicKey);
const userQuoteAta = getAssociatedTokenAddressSync(poolData.quoteMint, payer.publicKey);
const userLpAta = getAssociatedTokenAddressSync(poolData.lpMint, payer.publicKey);
const data = Buffer.alloc(8 + 8 + 8 + 8);
const discriminator = Buffer.from([0xf2, 0x23, 0xc6, 0x89, 0x52, 0xe1, 0xf2, 0xb6]);
discriminator.copy(data, 0);
data.writeBigUInt64LE(baseAmount, 8);
data.writeBigUInt64LE(quoteAmount, 16);
data.writeBigUInt64LE(minLpTokens, 24);
const instruction = new TransactionInstruction({
programId: PUMP_AMM_PROGRAM_ID,
keys: [
{ pubkey: pool, isSigner: false, isWritable: true },
{ pubkey: GLOBAL_CONFIG, isSigner: false, isWritable: false },
{ pubkey: payer.publicKey, isSigner: true, isWritable: true },
{ pubkey: poolData.baseMint, isSigner: false, isWritable: false },
{ pubkey: poolData.quoteMint, isSigner: false, isWritable: false },
{ pubkey: poolData.lpMint, isSigner: false, isWritable: true },
{ pubkey: userBaseAta, isSigner: false, isWritable: true },
{ pubkey: userQuoteAta, isSigner: false, isWritable: true },
{ pubkey: userLpAta, isSigner: false, isWritable: true },
{ pubkey: poolData.poolBaseTokenAccount, isSigner: false, isWritable: true },
{ pubkey: poolData.poolQuoteTokenAccount, isSigner: false, isWritable: true },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
],
data,
});
const tx = new Transaction().add(instruction);
tx.feePayer = payer.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.sign(payer);
return await connection.sendRawTransaction(tx.serialize());
}
Remove Liquidity
async function removeLiquidity(
connection: Connection,
payer: Keypair,
pool: PublicKey,
lpTokenAmount: bigint,
minBaseOut: bigint,
minQuoteOut: bigint
): Promise<string> {
const poolData = await fetchPoolData(connection, pool);
const userBaseAta = getAssociatedTokenAddressSync(poolData.baseMint, payer.publicKey);
const userQuoteAta = getAssociatedTokenAddressSync(poolData.quoteMint, payer.publicKey);
const userLpAta = getAssociatedTokenAddressSync(poolData.lpMint, payer.publicKey);
const data = Buffer.alloc(8 + 8 + 8 + 8);
const discriminator = Buffer.from([0xb7, 0x12, 0x46, 0x9c, 0x94, 0x6d, 0xa1, 0x22]);
discriminator.copy(data, 0);
data.writeBigUInt64LE(lpTokenAmount, 8);
data.writeBigUInt64LE(minBaseOut, 16);
data.writeBigUInt64LE(minQuoteOut, 24);
const instruction = new TransactionInstruction({
programId: PUMP_AMM_PROGRAM_ID,
keys: [
{ pubkey: pool, isSigner: false, isWritable: true },
{ pubkey: GLOBAL_CONFIG, isSigner: false, isWritable: false },
{ pubkey: payer.publicKey, isSigner: true, isWritable: true },
{ pubkey: poolData.baseMint, isSigner: false, isWritable: false },
{ pubkey: poolData.quoteMint, isSigner: false, isWritable: false },
{ pubkey: poolData.lpMint, isSigner: false, isWritable: true },
{ pubkey: userBaseAta, isSigner: false, isWritable: true },
{ pubkey: userQuoteAta, isSigner: false, isWritable: true },
{ pubkey: userLpAta, isSigner: false, isWritable: true },
{ pubkey: poolData.poolBaseTokenAccount, isSigner: false, isWritable: true },
{ pubkey: poolData.poolQuoteTokenAccount, isSigner: false, isWritable: true },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
],
data,
});
const tx = new Transaction().add(instruction);
tx.feePayer = payer.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.sign(payer);
return await connection.sendRawTransaction(tx.serialize());
}
Fee Structure
Dynamic Fee Tiers
Fees are calculated based on market capitalization in lamports:
interface FeeTier {
marketCapLamportsThreshold: bigint;
fees: Fees;
}
interface Fees {
lpFeeBps: number;
protocolFeeBps: number;
creatorFeeBps: number;
}
function calculateBondingCurveMarketCap(
virtualSolReserves: bigint,
mintSupply: bigint,
virtualTokenReserves: bigint
): bigint {
return (virtualSolReserves * mintSupply) / virtualTokenReserves;
}
function calculatePoolMarketCap(
quoteReserve: bigint,
baseMintSupply: bigint,
baseReserve: bigint
): bigint {
return (quoteReserve * baseMintSupply) / baseReserve;
}
function getFeeTier(marketCap: bigint, feeTiers: FeeTier[]): Fees {
const sortedTiers = [...feeTiers].sort(
(a, b) => Number(b.marketCapLamportsThreshold - a.marketCapLamportsThreshold)
);
for (const tier of sortedTiers) {
if (marketCap >= tier.marketCapLamportsThreshold) {
return tier.fees;
}
}
return sortedTiers[sortedTiers.length - 1].fees;
}
Fee Sharing Configuration
interface SharingConfig {
status: 'Active' | 'Paused';
mint: PublicKey;
admin: PublicKey;
adminRevoked: boolean;
shareholders: Shareholder[];
}
interface Shareholder {
address: PublicKey;
shareBps: number;
}
async function createFeeSharingConfig(
connection: Connection,
payer: Keypair,
mint: PublicKey,
shareholders: Shareholder[]
): Promise<string> {
const totalShares = shareholders.reduce((sum, s) => sum + s.shareBps, 0);
if (totalShares !== 10000) {
throw new Error('Shareholder shares must sum to 10000 bps');
}
}
Collecting Creator Fees
async function collectBondingCurveCreatorFee(
connection: Connection,
creator: Keypair
): Promise<string> {
const [creatorVault] = PublicKey.findProgramAddressSync(
[Buffer.from('creator-vault'), creator.publicKey.toBuffer()],
PUMP_PROGRAM_ID
);
const discriminator = Buffer.from([0x85, 0xb1, 0x29, 0x6d, 0x3a, 0x47, 0x2c, 0x5e]);
const instruction = new TransactionInstruction({
programId: PUMP_PROGRAM_ID,
keys: [
{ pubkey: creatorVault, isSigner: false, isWritable: true },
{ pubkey: creator.publicKey, isSigner: true, isWritable: true },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
],
data: discriminator,
});
const tx = new Transaction().add(instruction);
tx.feePayer = creator.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.sign(creator);
return await connection.sendRawTransaction(tx.serialize());
}
async function collectPoolCreatorFee(
connection: Connection,
coinCreator: Keypair,
pool: PublicKey
): Promise<string> {
const poolData = await fetchPoolData(connection, pool);
const [creatorVaultAuthority] = getCreatorVaultAuthorityPDA(coinCreator.publicKey);
const creatorVaultAta = getAssociatedTokenAddressSync(
poolData.quoteMint,
creatorVaultAuthority,
true
);
const creatorWalletAta = getAssociatedTokenAddressSync(
poolData.quoteMint,
coinCreator.publicKey
);
}
SDK Usage
Using PumpAmmSdk
import { PumpAmmSdk } from '@pump-fun/pump-swap-sdk';
const sdk = new PumpAmmSdk(connection);
const initialPrice = sdk.createAutocompleteInitialPoolPrice(
baseAmount,
quoteAmount
);
const createIxs = await sdk.createPoolInstructions({
index: 0,
creator: payer.publicKey,
baseMint: tokenMint,
quoteMint: WSOL_MINT,
baseAmountIn: baseAmount,
quoteAmountIn: quoteAmount,
});
const depositCalc = sdk.depositAutocompleteBaseInput({
pool: poolAddress,
baseAmountIn: userBaseInput,
slippageBps: 50,
});
console.log('Quote needed:', depositCalc.quoteAmountIn);
console.log('LP tokens:', depositCalc.lpTokensOut);
const depositCalc2 = sdk.depositAutocompleteQuoteInput({
pool: poolAddress,
quoteAmountIn: userQuoteInput,
slippageBps: 50,
});
const depositIxs = await sdk.depositInstructions({
pool: poolAddress,
user: payer.publicKey,
lpTokenAmountOut: depositCalc.lpTokensOut,
maxBaseAmountIn: depositCalc.baseAmountIn,
maxQuoteAmountIn: depositCalc.quoteAmountIn,
});
const swapCalc = sdk.swapAutocompleteBaseInput({
pool: poolAddress,
baseAmountIn: sellAmount,
slippageBps: 100,
});
console.log('Quote out:', swapCalc.quoteAmountOut);
const swapIxs = await sdk.swapInstructions({
pool: poolAddress,
user: payer.publicKey,
baseAmountIn: sellAmount,
quoteAmountIn: 0n,
minAmountOut: swapCalc.minQuoteAmountOut,
});
const withdrawCalc = sdk.withdrawAutocomplete({
pool: poolAddress,
lpTokenAmountIn: lpTokens,
slippageBps: 50,
});
console.log('Base out:', withdrawCalc.baseAmountOut);
console.log('Quote out:', withdrawCalc.quoteAmountOut);
const withdrawIxs = await sdk.withdrawInstructions({
pool: poolAddress,
user: payer.publicKey,
lpTokenAmountIn: lpTokens,
minBaseAmountOut: withdrawCalc.minBaseAmountOut,
minQuoteAmountOut: withdrawCalc.minQuoteAmountOut,
});
Account Extension
Both Pump and PumpSwap programs require account extension when account sizes have been increased:
async function ensureBondingCurveExtended(
connection: Connection,
bondingCurve: PublicKey
): Promise<TransactionInstruction | null> {
const accountInfo = await connection.getAccountInfo(bondingCurve);
if (accountInfo && accountInfo.data.length < 150) {
return createExtendAccountInstruction(PUMP_PROGRAM_ID, bondingCurve);
}
return null;
}
async function ensurePoolExtended(
connection: Connection,
pool: PublicKey
): Promise<TransactionInstruction | null> {
const accountInfo = await connection.getAccountInfo(pool);
if (accountInfo && accountInfo.data.length < 300) {
return createExtendAccountInstruction(PUMP_AMM_PROGRAM_ID, pool);
}
return null;
}
function createExtendAccountInstruction(
programId: PublicKey,
account: PublicKey
): TransactionInstruction {
const discriminator = Buffer.from([0x9a, 0x3f, 0x2c, 0x8b, 0x45, 0xe7, 0x12, 0xd6]);
return new TransactionInstruction({
programId,
keys: [
{ pubkey: account, isSigner: false, isWritable: true },
],
data: discriminator,
});
}
Mayhem Mode
Mayhem mode is a special token launch mode with different fee recipients:
const MAYHEM_PROGRAM_ID = new PublicKey('MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e');
const MAYHEM_FEE_RECIPIENTS = [
'DzPPWKfYYMuHxR98xhPkYSp7KHsLpcLZU8tHCqXjC3HG',
'5AbGBKS6NHKcTFyJaZCk3dbMRNFG3y6kkN4y7Rp3iHCk',
'DWM9EuZ3e9cRYdHYRKwsCqXFKgn4jUNkUPEAyNE2Dxnc',
'9BUPJ65gFVaGQKyXiR6xSE1DdLRqkUMv9HJvL8wGfJaL',
];
function isMayhemMode(bondingCurve: BondingCurve): boolean {
return bondingCurve.isMayhemMode;
}
function getFeeRecipient(
bondingCurve: BondingCurve,
defaultFeeRecipient: PublicKey
): PublicKey {
if (bondingCurve.isMayhemMode) {
const index = Math.floor(Math.random() * MAYHEM_FEE_RECIPIENTS.length);
return new PublicKey(MAYHEM_FEE_RECIPIENTS[index]);
}
return defaultFeeRecipient;
}
Token Incentives
PumpFun offers volume-based token incentives:
async function initUserVolumeAccumulator(
connection: Connection,
payer: Keypair
): Promise<string> {
const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
[Buffer.from('user_volume'), payer.publicKey.toBuffer()],
PUMP_PROGRAM_ID
);
}
async function claimTokenIncentives(
connection: Connection,
user: Keypair
): Promise<string> {
const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
[Buffer.from('user_volume'), user.publicKey.toBuffer()],
PUMP_PROGRAM_ID
);
}
Compute Units Optimization
const RECOMMENDED_CU_LIMIT = 100_000;
import { ComputeBudgetProgram } from '@solana/web3.js';
function addComputeBudget(
tx: Transaction,
units: number = 100_000,
microLamports: number = 10_000
): Transaction {
tx.add(
ComputeBudgetProgram.setComputeUnitLimit({ units }),
ComputeBudgetProgram.setComputeUnitPrice({ microLamports })
);
return tx;
}
Error Handling
enum PumpError {
SlippageExceeded = 6001,
InsufficientFunds = 6002,
BondingCurveComplete = 6003,
BondingCurveNotComplete = 6004,
InvalidAmount = 6005,
MathOverflow = 6006,
Unauthorized = 6007,
}
function handlePumpError(error: any): string {
const code = error?.code || error?.message?.match(/custom program error: 0x(\w+)/)?.[1];
switch (parseInt(code, 16)) {
case PumpError.SlippageExceeded:
return 'Transaction failed: Slippage tolerance exceeded. Try increasing slippage.';
case PumpError.InsufficientFunds:
return 'Insufficient funds for this transaction.';
case PumpError.BondingCurveComplete:
return 'Bonding curve is complete. Trade on PumpSwap instead.';
case PumpError.BondingCurveNotComplete:
return 'Bonding curve not yet complete. Cannot migrate.';
default:
return `Transaction failed: ${error.message}`;
}
}
Best Practices
Transaction Building
- Always check account sizes before buy/sell and prepend
extendAccount if needed
- Use static CU limit of 100,000 for buy/sell operations
- Include proper slippage protection (1-5% recommended)
- Use appropriate fee recipients based on mayhem mode status
Fee Handling
- Always include fee config accounts (required since September 2025)
- For mayhem mode tokens, pass mayhem fee recipient at correct account index
- Check market cap tier for accurate fee calculation
Creator Fees
- Creator fees accumulate in creator vault PDAs
- Use
collectCreatorFee to withdraw accumulated fees
- Fees apply to non-completed bonding curves and canonical PumpSwap pools
Security
- Never expose private keys
- Validate all user inputs
- Use devnet for testing before mainnet
- Implement proper error handling
Resources
Skill Structure
pumpfun/
├── SKILL.md # This file
├── resources/
│ ├── pump-program-reference.md # Bonding curve program API
│ ├── pump-swap-reference.md # AMM program API
│ ├── fee-structure.md # Fee calculation and tiers
│ └── program-addresses.md # All program addresses
├── examples/
│ ├── bonding-curve/
│ │ ├── create-token.ts # Token creation example
│ │ └── buy-sell.ts # Buy/sell on bonding curves
│ ├── swap/
│ │ └── swap.ts # PumpSwap trading
│ ├── liquidity/
│ │ └── add-remove.ts # Add/remove liquidity
│ └── creator-fees/
│ └── collect-fees.ts # Fee collection
├── templates/
│ └── pumpfun-setup.ts # Starter template
└── docs/
└── troubleshooting.md # Common issues