pumpfun
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePumpFun Protocol Integration Guide
PumpFun Protocol集成指南
A comprehensive guide for building applications with PumpFun - Solana's leading token launch and AMM protocol enabling instant trading without initial liquidity.
本指南全面介绍了如何基于PumpFun进行应用开发——PumpFun是Solana上领先的代币发行与AMM协议,支持无需初始流动性的即时交易。
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 instruction
create_v2 - Mayhem Mode - Special mode for enhanced token launches
PumpFun是Solana上的代币发行与交易协议,提供以下功能:
- Pump Program - 创建可在绑定曲线上即时交易的SPL代币
- PumpSwap (AMM) - 适用于成熟代币的恒定乘积自动做市商
- 创作者费用 - 自动向代币创作者分配费用
- Token2022支持 - 通过指令支持现代代币标准
create_v2 - Mayhem模式 - 用于增强代币发行的特殊模式
Program IDs
程序ID
| Program | Address |
|---|---|
| Pump Program | |
| PumpSwap AMM | |
| Pump Fees | |
| Mayhem Program | |
| 程序 | 地址 |
|---|---|
| Pump Program | |
| PumpSwap AMM | |
| Pump Fees | |
| Mayhem Program | |
Quick Start
快速开始
Installation
安装
bash
undefinedbash
undefinedInstall PumpFun SDKs
安装PumpFun SDK
npm install @pump-fun/pump-sdk @pump-fun/pump-swap-sdk
npm install @pump-fun/pump-sdk @pump-fun/pump-swap-sdk
Or with pnpm
或使用pnpm
pnpm add @pump-fun/pump-sdk @pump-fun/pump-swap-sdk
undefinedpnpm add @pump-fun/pump-sdk @pump-fun/pump-swap-sdk
undefinedBasic Setup
基础设置
typescript
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import bs58 from 'bs58';
// Setup connection
const connection = new Connection('https://api.mainnet-beta.solana.com');
const wallet = Keypair.fromSecretKey(bs58.decode('YOUR_SECRET_KEY'));
// Program addresses
const PUMP_PROGRAM_ID = new PublicKey('6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P');
const PUMP_AMM_PROGRAM_ID = new PublicKey('pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA');
const PUMP_FEES_PROGRAM_ID = new PublicKey('pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ');typescript
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)
Pump Program(绑定曲线)
The Pump program enables creation of SPL tokens with instant trading on a bonding curve without requiring initial liquidity.
Pump Program支持创建可在绑定曲线上即时交易的SPL代币,无需初始流动性。
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
- 代币创建 - 创建带有初始虚拟储备的代币
- 交易 - 用户使用Uniswap V2公式在绑定曲线上买卖
- 成熟迁移 - 当市值达到阈值时,流动性迁移至PumpSwap
- LP代币销毁 - LP代币被销毁,使流动性永久化
Global Configuration
全局配置
typescript
interface Global {
initialized: boolean;
authority: PublicKey;
feeRecipient: PublicKey;
initialVirtualTokenReserves: bigint; // Default: 1,073,000,000,000,000
initialVirtualSolReserves: bigint; // Default: 30,000,000,000 (30 SOL)
initialRealTokenReserves: bigint; // Default: 793,100,000,000,000
tokenTotalSupply: bigint; // Default: 1,000,000,000,000,000
feeBasisPoints: bigint; // Default: 100 (1%)
creatorFeeBasisPoints: bigint; // Creator fee percentage
}typescript
interface Global {
initialized: boolean;
authority: PublicKey;
feeRecipient: PublicKey;
initialVirtualTokenReserves: bigint; // 默认值: 1,073,000,000,000,000
initialVirtualSolReserves: bigint; // 默认值: 30,000,000,000 (30 SOL)
initialRealTokenReserves: bigint; // 默认值: 793,100,000,000,000
tokenTotalSupply: bigint; // 默认值: 1,000,000,000,000,000
feeBasisPoints: bigint; // 默认值: 100 (1%)
creatorFeeBasisPoints: bigint; // 创作者费用百分比
}Bonding Curve Account
绑定曲线账户
typescript
interface BondingCurve {
virtualTokenReserves: bigint;
virtualSolReserves: bigint;
realTokenReserves: bigint;
realSolReserves: bigint;
tokenTotalSupply: bigint;
complete: boolean;
creator: PublicKey; // Token creator address
isMayhemMode: boolean; // Mayhem mode flag
}typescript
interface BondingCurve {
virtualTokenReserves: bigint;
virtualSolReserves: bigint;
realTokenReserves: bigint;
realSolReserves: bigint;
tokenTotalSupply: bigint;
complete: boolean;
creator: PublicKey; // 代币创作者地址
isMayhemMode: boolean; // Mayhem模式标记
}Deriving PDAs
推导PDA
typescript
import { PublicKey } from '@solana/web3.js';
const PUMP_PROGRAM_ID = new PublicKey('6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P');
// Derive bonding curve PDA
function getBondingCurvePDA(mint: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('bonding-curve'), mint.toBuffer()],
PUMP_PROGRAM_ID
);
}
// Derive associated bonding curve (token account)
function getAssociatedBondingCurve(mint: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[
Buffer.from('associated-bonding-curve'),
mint.toBuffer()
],
PUMP_PROGRAM_ID
);
}
// Derive creator vault PDA
function getCreatorVaultPDA(creator: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('creator-vault'), creator.toBuffer()],
PUMP_PROGRAM_ID
);
}
// Derive global account PDA
function getGlobalPDA(): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('global')],
PUMP_PROGRAM_ID
);
}typescript
import { PublicKey } from '@solana/web3.js';
const PUMP_PROGRAM_ID = new PublicKey('6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P');
// 推导绑定曲线PDA
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
);
}
// 推导创作者金库PDA
function getCreatorVaultPDA(creator: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('creator-vault'), creator.toBuffer()],
PUMP_PROGRAM_ID
);
}
// 推导全局账户PDA
function getGlobalPDA(): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('global')],
PUMP_PROGRAM_ID
);
}Create Token (Legacy SPL)
创建代币(传统SPL)
typescript
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();
// Metaplex metadata PDA
const METADATA_PROGRAM_ID = new PublicKey('metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s');
const [metadata] = PublicKey.findProgramAddressSync(
[
Buffer.from('metadata'),
METADATA_PROGRAM_ID.toBuffer(),
mint.publicKey.toBuffer(),
],
METADATA_PROGRAM_ID
);
// Build create instruction data
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
);
// Write discriminator for 'create' instruction
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();
}typescript
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();
// Metaplex元数据PDA
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
);
// 写入'create'指令的判别符
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)
创建代币V2(Token2022)
typescript
// create_v2 uses Token2022 program instead of legacy Metaplex
// Account structure (14 accounts):
const createV2Accounts = [
'mint', // 0: New token mint (signer, writable)
'mintAuthority', // 1: Mint authority PDA
'bondingCurve', // 2: Bonding curve PDA (writable)
'associatedBondingCurve', // 3: Token account for bonding curve (writable)
'global', // 4: Global config
'user', // 5: Creator/payer (signer, writable)
'systemProgram', // 6: System program
'token2022Program', // 7: Token2022 program
'associatedTokenProgram', // 8: Associated token program
'rent', // 9: Rent sysvar
'mayhemProgram', // 10: Mayhem program ID (for mayhem mode)
'mayhemFeeRecipient', // 11: Mayhem fee recipient
'eventAuthority', // 12: Event authority
'program', // 13: Pump program
];typescript
// create_v2使用Token2022程序而非传统Metaplex
// 账户结构(14个账户):
const createV2Accounts = [
'mint', // 0: 新代币铸币地址(签名者,可写)
'mintAuthority', // 1: 铸币权限PDA
'bondingCurve', // 2: 绑定曲线PDA(可写)
'associatedBondingCurve', // 3: 绑定曲线的代币账户(可写)
'global', // 4: 全局配置
'user', // 5: 创作者/支付者(签名者,可写)
'systemProgram', // 6: 系统程序
'token2022Program', // 7: Token2022程序
'associatedTokenProgram', // 8: 关联代币程序
'rent', // 9: Rent系统变量
'mayhemProgram', // 10: Mayhem程序ID(用于Mayhem模式)
'mayhemFeeRecipient', // 11: Mayhem费用接收方
'eventAuthority', // 12: 事件权限地址
'program', // 13: Pump程序
];Buy Tokens on Bonding Curve
在绑定曲线上买入代币
typescript
interface BuyArgs {
amount: bigint; // Token amount to buy
maxSolCost: bigint; // Maximum SOL to spend (slippage protection)
}
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();
// Get bonding curve data to find creator
const bondingCurveData = await connection.getAccountInfo(bondingCurve);
// Parse to get creator address...
const creator = parseCreatorFromBondingCurve(bondingCurveData);
const [creatorVault] = getCreatorVaultPDA(creator);
// User's associated token account
const userAta = getAssociatedTokenAddressSync(mint, payer.publicKey);
// Fee recipient (from global config)
const feeRecipient = new PublicKey('FEE_RECIPIENT_ADDRESS');
// Build buy instruction
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 },
// Fee config accounts (required since September 2025)
{ pubkey: PUMP_FEES_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: feeConfigPDA, isSigner: false, isWritable: false },
],
data,
});
// Check if account extension needed (account size < 150 bytes)
const accountInfo = await connection.getAccountInfo(bondingCurve);
if (accountInfo && accountInfo.data.length < 150) {
// Prepend extendAccount instruction
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;
}typescript
interface BuyArgs {
amount: bigint; // 要买入的代币数量
maxSolCost: bigint; // 最大花费SOL(滑点保护)
}
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 },
// 费用配置账户(2025年9月起必填)
{ pubkey: PUMP_FEES_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: feeConfigPDA, isSigner: false, isWritable: false },
],
data,
});
// 检查是否需要扩展账户(账户大小 < 150字节)
const accountInfo = await connection.getAccountInfo(bondingCurve);
if (accountInfo && accountInfo.data.length < 150) {
// 前置extendAccount指令
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
在绑定曲线上卖出代币
typescript
interface SellArgs {
amount: bigint; // Token amount to sell
minSolOutput: bigint; // Minimum SOL to receive (slippage protection)
}
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 },
// Fee config accounts
{ 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;
}typescript
interface SellArgs {
amount: bigint; // 要卖出的代币数量
minSolOutput: bigint; // 最小接收SOL(滑点保护)
}
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)
计算价格(绑定曲线算法)
typescript
// Uniswap V2 constant product formula: x * y = k
// Quote: SOL -> Tokens
interface BondingCurveState {
virtualTokenReserves: bigint;
virtualSolReserves: bigint;
realTokenReserves: bigint;
realSolReserves: bigint;
}
function calculateBuyQuote(
state: BondingCurveState,
solAmountIn: bigint,
feeBasisPoints: bigint = 100n
): bigint {
// Calculate net SOL after fees
const netSol = (solAmountIn * 10000n) / (10000n + feeBasisPoints);
// Calculate tokens out using constant product formula
// tokensOut = (netSol * virtualTokenReserves) / (virtualSolReserves + netSol)
const tokensOut = (netSol * state.virtualTokenReserves) /
(state.virtualSolReserves + netSol);
// Cap at real token reserves
return tokensOut > state.realTokenReserves ? state.realTokenReserves : tokensOut;
}
function calculateSellQuote(
state: BondingCurveState,
tokenAmountIn: bigint,
feeBasisPoints: bigint = 100n
): bigint {
// Calculate SOL out using constant product formula
// solOut = (tokenAmountIn * virtualSolReserves) / (virtualTokenReserves + tokenAmountIn)
const grossSol = (tokenAmountIn * state.virtualSolReserves) /
(state.virtualTokenReserves + tokenAmountIn);
// Deduct fees
const netSol = (grossSol * (10000n - feeBasisPoints)) / 10000n;
// Cap at real SOL reserves
return netSol > state.realSolReserves ? state.realSolReserves : netSol;
}
function calculateMarketCap(state: BondingCurveState, tokenSupply: bigint): bigint {
// marketCap = virtualSolReserves * mintSupply / virtualTokenReserves
return (state.virtualSolReserves * tokenSupply) / state.virtualTokenReserves;
}typescript
// Uniswap V2恒定乘积公式: x * y = k
// 报价: SOL -> 代币
interface BondingCurveState {
virtualTokenReserves: bigint;
virtualSolReserves: bigint;
realTokenReserves: bigint;
realSolReserves: bigint;
}
function calculateBuyQuote(
state: BondingCurveState,
solAmountIn: bigint,
feeBasisPoints: bigint = 100n
): bigint {
// 计算扣除费用后的净SOL
const netSol = (solAmountIn * 10000n) / (10000n + feeBasisPoints);
// 使用恒定乘积公式计算可获得代币数量
// tokensOut = (netSol * virtualTokenReserves) / (virtualSolReserves + netSol)
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 {
// 使用恒定乘积公式计算可获得SOL数量
// solOut = (tokenAmountIn * virtualSolReserves) / (virtualTokenReserves + tokenAmountIn)
const grossSol = (tokenAmountIn * state.virtualSolReserves) /
(state.virtualTokenReserves + tokenAmountIn);
// 扣除费用
const netSol = (grossSol * (10000n - feeBasisPoints)) / 10000n;
// 上限为真实SOL储备
return netSol > state.realSolReserves ? state.realSolReserves : netSol;
}
function calculateMarketCap(state: BondingCurveState, tokenSupply: bigint): bigint {
// marketCap = virtualSolReserves * mintSupply / virtualTokenReserves
return (state.virtualSolReserves * tokenSupply) / state.virtualTokenReserves;
}Migration to PumpSwap
迁移至PumpSwap
When a bonding curve completes (real tokens exhausted), liquidity can be migrated to PumpSwap:
typescript
async function migrateToAMM(
connection: Connection,
payer: Keypair,
mint: PublicKey
): Promise<string> {
const [bondingCurve] = getBondingCurvePDA(mint);
// Migrate instruction is permissionless - anyone can call it
// after bonding curve is complete
const discriminator = Buffer.from([0x9d, 0xaf, 0x1e, 0x65, 0xe8, 0x69, 0x9b, 0x26]);
const instruction = new TransactionInstruction({
programId: PUMP_PROGRAM_ID,
keys: [
// ... migration accounts including PumpSwap pool creation
],
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:
typescript
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: [
// ... 包含PumpSwap池创建的迁移账户
],
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(AMM)
PumpSwap is a constant-product AMM for tokens that have graduated from the bonding curve.
PumpSwap是为从绑定曲线成熟的代币设计的恒定乘积AMM。
Global Config
全局配置
typescript
// GlobalConfig address
const GLOBAL_CONFIG = new PublicKey('ADyA8hdefvWN2dbGGWFotbzWxrAvLW83WG6QCVXvJKqw');
interface GlobalConfig {
admin: PublicKey;
lpFeeBasisPoints: number; // 20 bps (0.2%)
protocolFeeBasisPoints: number; // 5 bps (0.05%)
coinCreatorFeeBasisPoints: number; // Creator fee
disableFlags: number; // Operation disable flags
protocolFeeRecipients: PublicKey[]; // 8 fee recipients for load balancing
tokenIncentivesEnabled: boolean;
}typescript
// GlobalConfig地址
const GLOBAL_CONFIG = new PublicKey('ADyA8hdefvWN2dbGGWFotbzWxrAvLW83WG6QCVXvJKqw');
interface GlobalConfig {
admin: PublicKey;
lpFeeBasisPoints: number; // 20 bps (0.2%)
protocolFeeBasisPoints: number; // 5 bps (0.05%)
coinCreatorFeeBasisPoints: number; // 创作者费用
disableFlags: number; // 操作禁用标记
protocolFeeRecipients: PublicKey[]; // 8个费用接收方用于负载均衡
tokenIncentivesEnabled: boolean;
}Pool Account
池账户
typescript
interface Pool {
bump: number;
poolCreator: PublicKey;
baseMint: PublicKey; // Token mint
quoteMint: PublicKey; // Usually WSOL
lpMint: PublicKey; // LP token mint
poolBaseTokenAccount: PublicKey;
poolQuoteTokenAccount: PublicKey;
lpSupply: bigint; // Tracks original LP supply (independent of burns)
coinCreator: PublicKey; // Creator for fee distribution
isMayhemMode: boolean; // Mayhem mode flag
}typescript
interface Pool {
bump: number;
poolCreator: PublicKey;
baseMint: PublicKey; // 代币铸币地址
quoteMint: PublicKey; // 通常为WSOL
lpMint: PublicKey; // LP代币铸币地址
poolBaseTokenAccount: PublicKey;
poolQuoteTokenAccount: PublicKey;
lpSupply: bigint; // 追踪原始LP供应量(独立于销毁操作)
coinCreator: PublicKey; // 用于费用分配的创作者地址
isMayhemMode: boolean; // Mayhem模式标记
}Deriving Pool PDAs
推导池PDA
typescript
const PUMP_AMM_PROGRAM_ID = new PublicKey('pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA');
// Derive pool PDA
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
);
}
// Derive LP mint PDA
function getLpMintPDA(pool: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('pool_lp_mint'), pool.toBuffer()],
PUMP_AMM_PROGRAM_ID
);
}
// Derive pool token account PDA
function getPoolTokenAccountPDA(pool: PublicKey, mint: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('pool_token_account'), pool.toBuffer(), mint.toBuffer()],
PUMP_AMM_PROGRAM_ID
);
}
// Derive creator vault authority PDA
function getCreatorVaultAuthorityPDA(coinCreator: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('creator_vault'), coinCreator.toBuffer()],
PUMP_AMM_PROGRAM_ID
);
}typescript
const PUMP_AMM_PROGRAM_ID = new PublicKey('pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA');
// 推导池PDA
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
);
}
// 推导LP铸币PDA
function getLpMintPDA(pool: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('pool_lp_mint'), pool.toBuffer()],
PUMP_AMM_PROGRAM_ID
);
}
// 推导池代币账户PDA
function getPoolTokenAccountPDA(pool: PublicKey, mint: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('pool_token_account'), pool.toBuffer(), mint.toBuffer()],
PUMP_AMM_PROGRAM_ID
);
}
// 推导创作者金库权限PDA
function getCreatorVaultAuthorityPDA(coinCreator: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync(
[Buffer.from('creator_vault'), coinCreator.toBuffer()],
PUMP_AMM_PROGRAM_ID
);
}Swap on PumpSwap
在PumpSwap上兑换
typescript
interface SwapArgs {
baseAmountIn: bigint; // Amount of base token (for sell)
quoteAmountIn: bigint; // Amount of quote token (for buy)
minAmountOut: bigint; // Minimum output (slippage protection)
}
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 // allowOwnerOffCurve
);
// Build swap instruction
const data = Buffer.alloc(8 + 8 + 8 + 8);
const discriminator = isBuy
? Buffer.from([0x66, 0x06, 0x3d, 0x12, 0x01, 0xda, 0xeb, 0xea]) // buy
: Buffer.from([0x33, 0xe6, 0x85, 0xa4, 0x01, 0x7f, 0x83, 0xad]); // sell
discriminator.copy(data, 0);
data.writeBigUInt64LE(isBuy ? 0n : amountIn, 8); // baseAmountIn
data.writeBigUInt64LE(isBuy ? amountIn : 0n, 16); // quoteAmountIn
data.writeBigUInt64LE(minAmountOut, 24); // minAmountOut
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 },
// Creator fee accounts (indexes 17-18, required if pool.dataLen < 300)
{ pubkey: creatorVaultAta, isSigner: false, isWritable: true },
{ pubkey: creatorVaultAuthority, isSigner: false, isWritable: false },
// Fee config
{ pubkey: PUMP_FEES_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: feeConfigPDA, isSigner: false, isWritable: false },
],
data,
});
// Check if account extension needed
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());
}typescript
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 // allowOwnerOffCurve
);
// 构建兑换指令
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); // baseAmountIn
data.writeBigUInt64LE(isBuy ? amountIn : 0n, 16); // quoteAmountIn
data.writeBigUInt64LE(minAmountOut, 24); // minAmountOut
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 },
// 创作者费用账户(索引17-18,若pool.dataLen < 300则必填)
{ 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
添加流动性
typescript
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());
}typescript
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
移除流动性
typescript
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());
}typescript
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:
typescript
interface FeeTier {
marketCapLamportsThreshold: bigint;
fees: Fees;
}
interface Fees {
lpFeeBps: number; // LP provider fee
protocolFeeBps: number; // Protocol fee
creatorFeeBps: number; // Creator fee
}
// Fee calculation for bonding curves
function calculateBondingCurveMarketCap(
virtualSolReserves: bigint,
mintSupply: bigint,
virtualTokenReserves: bigint
): bigint {
return (virtualSolReserves * mintSupply) / virtualTokenReserves;
}
// Fee calculation for AMM pools
function calculatePoolMarketCap(
quoteReserve: bigint,
baseMintSupply: bigint,
baseReserve: bigint
): bigint {
return (quoteReserve * baseMintSupply) / baseReserve;
}
// Get applicable fee tier
function getFeeTier(marketCap: bigint, feeTiers: FeeTier[]): Fees {
// Sort tiers by threshold descending
const sortedTiers = [...feeTiers].sort(
(a, b) => Number(b.marketCapLamportsThreshold - a.marketCapLamportsThreshold)
);
for (const tier of sortedTiers) {
if (marketCap >= tier.marketCapLamportsThreshold) {
return tier.fees;
}
}
// Return default/lowest tier
return sortedTiers[sortedTiers.length - 1].fees;
}费用根据以lamport为单位的市值计算:
typescript
interface FeeTier {
marketCapLamportsThreshold: bigint;
fees: Fees;
}
interface Fees {
lpFeeBps: number; // LP提供者费用
protocolFeeBps: number; // 协议费用
creatorFeeBps: number; // 创作者费用
}
// 绑定曲线的费用计算
function calculateBondingCurveMarketCap(
virtualSolReserves: bigint,
mintSupply: bigint,
virtualTokenReserves: bigint
): bigint {
return (virtualSolReserves * mintSupply) / virtualTokenReserves;
}
// AMM池的费用计算
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
费用分享配置
typescript
interface SharingConfig {
status: 'Active' | 'Paused';
mint: PublicKey;
admin: PublicKey;
adminRevoked: boolean;
shareholders: Shareholder[];
}
interface Shareholder {
address: PublicKey;
shareBps: number; // Share in basis points (total must equal 10000)
}
// Create fee sharing config
async function createFeeSharingConfig(
connection: Connection,
payer: Keypair,
mint: PublicKey,
shareholders: Shareholder[]
): Promise<string> {
// Validate shares sum to 10000 bps (100%)
const totalShares = shareholders.reduce((sum, s) => sum + s.shareBps, 0);
if (totalShares !== 10000) {
throw new Error('Shareholder shares must sum to 10000 bps');
}
// Build create_fee_sharing_config instruction
// ...
}typescript
interface SharingConfig {
status: 'Active' | 'Paused';
mint: PublicKey;
admin: PublicKey;
adminRevoked: boolean;
shareholders: Shareholder[];
}
interface Shareholder {
address: PublicKey;
shareBps: number; // 份额(基点,总和必须等于10000)
}
// 创建费用分享配置
async function createFeeSharingConfig(
connection: Connection,
payer: Keypair,
mint: PublicKey,
shareholders: Shareholder[]
): Promise<string> {
// 验证份额总和为10000 bps(100%)
const totalShares = shareholders.reduce((sum, s) => sum + s.shareBps, 0);
if (totalShares !== 10000) {
throw new Error('股东份额总和必须为10000 bps');
}
// 构建create_fee_sharing_config指令
// ...
}Collecting Creator Fees
收取创作者费用
typescript
// Collect fees from bonding curve
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());
}
// Collect fees from PumpSwap pool
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
);
// Build collect_coin_creator_fee instruction
// ...
}typescript
// 从绑定曲线收取费用
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());
}
// 从PumpSwap池收取费用
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
);
// 构建collect_coin_creator_fee指令
// ...
}SDK Usage
SDK使用
Using PumpAmmSdk
使用PumpAmmSdk
typescript
import { PumpAmmSdk } from '@pump-fun/pump-swap-sdk';
const sdk = new PumpAmmSdk(connection);
// Pool creation with autocomplete
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,
});
// Deposit autocomplete (base input changed)
const depositCalc = sdk.depositAutocompleteBaseInput({
pool: poolAddress,
baseAmountIn: userBaseInput,
slippageBps: 50, // 0.5%
});
console.log('Quote needed:', depositCalc.quoteAmountIn);
console.log('LP tokens:', depositCalc.lpTokensOut);
// Deposit autocomplete (quote input changed)
const depositCalc2 = sdk.depositAutocompleteQuoteInput({
pool: poolAddress,
quoteAmountIn: userQuoteInput,
slippageBps: 50,
});
// Execute deposit
const depositIxs = await sdk.depositInstructions({
pool: poolAddress,
user: payer.publicKey,
lpTokenAmountOut: depositCalc.lpTokensOut,
maxBaseAmountIn: depositCalc.baseAmountIn,
maxQuoteAmountIn: depositCalc.quoteAmountIn,
});
// Swap autocomplete
const swapCalc = sdk.swapAutocompleteBaseInput({
pool: poolAddress,
baseAmountIn: sellAmount,
slippageBps: 100, // 1%
});
console.log('Quote out:', swapCalc.quoteAmountOut);
// Execute swap
const swapIxs = await sdk.swapInstructions({
pool: poolAddress,
user: payer.publicKey,
baseAmountIn: sellAmount,
quoteAmountIn: 0n,
minAmountOut: swapCalc.minQuoteAmountOut,
});
// Withdraw
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,
});typescript
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, // 0.5%
});
console.log('所需报价:', depositCalc.quoteAmountIn);
console.log('LP代币:', 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, // 1%
});
console.log('输出报价:', 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('基础代币输出:', withdrawCalc.baseAmountOut);
console.log('报价代币输出:', 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:
typescript
// Check and extend bonding curve account (size < 150 bytes)
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;
}
// Check and extend pool account (size < 300 bytes)
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,
});
}当账户大小增加时,Pump和PumpSwap程序都需要账户扩展:
typescript
// 检查并扩展绑定曲线账户(大小 < 150字节)
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;
}
// 检查并扩展池账户(大小 < 300字节)
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模式
Mayhem mode is a special token launch mode with different fee recipients:
typescript
const MAYHEM_PROGRAM_ID = new PublicKey('MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e');
// Mayhem fee recipients (randomly rotated for load balancing)
const MAYHEM_FEE_RECIPIENTS = [
'DzPPWKfYYMuHxR98xhPkYSp7KHsLpcLZU8tHCqXjC3HG',
'5AbGBKS6NHKcTFyJaZCk3dbMRNFG3y6kkN4y7Rp3iHCk',
'DWM9EuZ3e9cRYdHYRKwsCqXFKgn4jUNkUPEAyNE2Dxnc',
'9BUPJ65gFVaGQKyXiR6xSE1DdLRqkUMv9HJvL8wGfJaL',
];
// Check if token is in mayhem mode
function isMayhemMode(bondingCurve: BondingCurve): boolean {
return bondingCurve.isMayhemMode;
}
// Get correct fee recipient based on mayhem mode
function getFeeRecipient(
bondingCurve: BondingCurve,
defaultFeeRecipient: PublicKey
): PublicKey {
if (bondingCurve.isMayhemMode) {
// Randomly select from mayhem recipients
const index = Math.floor(Math.random() * MAYHEM_FEE_RECIPIENTS.length);
return new PublicKey(MAYHEM_FEE_RECIPIENTS[index]);
}
return defaultFeeRecipient;
}Mayhem模式是一种特殊的代币发行模式,具有不同的费用接收方:
typescript
const MAYHEM_PROGRAM_ID = new PublicKey('MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e');
// Mayhem费用接收方(随机轮换以实现负载均衡)
const MAYHEM_FEE_RECIPIENTS = [
'DzPPWKfYYMuHxR98xhPkYSp7KHsLpcLZU8tHCqXjC3HG',
'5AbGBKS6NHKcTFyJaZCk3dbMRNFG3y6kkN4y7Rp3iHCk',
'DWM9EuZ3e9cRYdHYRKwsCqXFKgn4jUNkUPEAyNE2Dxnc',
'9BUPJ65gFVaGQKyXiR6xSE1DdLRqkUMv9HJvL8wGfJaL',
];
// 检查代币是否处于Mayhem模式
function isMayhemMode(bondingCurve: BondingCurve): boolean {
return bondingCurve.isMayhemMode;
}
// 根据Mayhem模式获取正确的费用接收方
function getFeeRecipient(
bondingCurve: BondingCurve,
defaultFeeRecipient: PublicKey
): PublicKey {
if (bondingCurve.isMayhemMode) {
// 从Mayhem接收方中随机选择
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:
typescript
// Initialize user volume accumulator
async function initUserVolumeAccumulator(
connection: Connection,
payer: Keypair
): Promise<string> {
const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
[Buffer.from('user_volume'), payer.publicKey.toBuffer()],
PUMP_PROGRAM_ID
);
// Build init_user_volume_accumulator instruction
// ...
}
// Claim token incentives
async function claimTokenIncentives(
connection: Connection,
user: Keypair
): Promise<string> {
const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
[Buffer.from('user_volume'), user.publicKey.toBuffer()],
PUMP_PROGRAM_ID
);
// Build claim_token_incentives instruction
// ...
}PumpFun提供基于交易量的代币激励:
typescript
// 初始化用户交易量累加器
async function initUserVolumeAccumulator(
connection: Connection,
payer: Keypair
): Promise<string> {
const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
[Buffer.from('user_volume'), payer.publicKey.toBuffer()],
PUMP_PROGRAM_ID
);
// 构建init_user_volume_accumulator指令
// ...
}
// 领取代币激励
async function claimTokenIncentives(
connection: Connection,
user: Keypair
): Promise<string> {
const [userVolumeAccumulator] = PublicKey.findProgramAddressSync(
[Buffer.from('user_volume'), user.publicKey.toBuffer()],
PUMP_PROGRAM_ID
);
// 构建claim_token_incentives指令
// ...
}Compute Units Optimization
计算单元优化
typescript
// Recommended static CU limit for buy/sell operations
const RECOMMENDED_CU_LIMIT = 100_000;
// Add compute budget instructions
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;
}typescript
// 买卖操作推荐的静态CU限制
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
错误处理
typescript
// Common PumpFun errors
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}`;
}
}typescript
// 常见PumpFun错误
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 '交易失败:滑点容忍度超出限制。请尝试提高滑点。';
case PumpError.InsufficientFunds:
return '交易资金不足。';
case PumpError.BondingCurveComplete:
return '绑定曲线已完成。请在PumpSwap上进行交易。';
case PumpError.BondingCurveNotComplete:
return '绑定曲线尚未完成。无法迁移。';
default:
return `交易失败:${error.message}`;
}
}Best Practices
最佳实践
Transaction Building
交易构建
- Always check account sizes before buy/sell and prepend if needed
extendAccount - 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
- 买卖前始终检查账户大小,若需要则前置指令
extendAccount - 买卖操作使用100,000的静态CU限制
- 包含适当的滑点保护(推荐1-5%)
- 根据Mayhem模式状态使用正确的费用接收方
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
- 始终包含费用配置账户(2025年9月起必填)
- 对于Mayhem模式代币,在正确的账户索引传入Mayhem费用接收方
- 检查市值层级以准确计算费用
Creator Fees
创作者费用
- Creator fees accumulate in creator vault PDAs
- Use to withdraw accumulated fees
collectCreatorFee - Fees apply to non-completed bonding curves and canonical PumpSwap pools
- 创作者费用累积在创作者金库PDA中
- 使用提取累积的费用
collectCreatorFee - 费用适用于未完成的绑定曲线和标准PumpSwap池
Security
安全
- Never expose private keys
- Validate all user inputs
- Use devnet for testing before mainnet
- Implement proper error handling
- 切勿暴露私钥
- 验证所有用户输入
- 上线主网前使用devnet测试
- 实现完善的错误处理
Resources
资源
- Public Docs: https://github.com/pump-fun/pump-public-docs
- IDL Files: https://github.com/pump-fun/pump-public-docs/tree/main/idl
- Pump SDK: on npm
@pump-fun/pump-sdk - PumpSwap SDK: on npm
@pump-fun/pump-swap-sdk
- 公开文档: https://github.com/pump-fun/pump-public-docs
- IDL文件: https://github.com/pump-fun/pump-public-docs/tree/main/idl
- Pump SDK: npm上的
@pump-fun/pump-sdk - PumpSwap SDK: npm上的
@pump-fun/pump-swap-sdk
Skill Structure
Skill结构
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 issuespumpfun/
├── SKILL.md # 本文档
├── resources/
│ ├── pump-program-reference.md # 绑定曲线程序API
│ ├── pump-swap-reference.md # AMM程序API
│ ├── fee-structure.md # 费用计算与层级
│ └── program-addresses.md # 所有程序地址
├── examples/
│ ├── bonding-curve/
│ │ ├── create-token.ts # 代币创建示例
│ │ └── buy-sell.ts # 绑定曲线买卖
│ ├── swap/
│ │ └── swap.ts # PumpSwap交易
│ ├── liquidity/
│ │ └── add-remove.ts # 添加/移除流动性
│ └── creator-fees/
│ └── collect-fees.ts # 费用收取
├── templates/
│ └── pumpfun-setup.ts # 入门模板
└── docs/
└── troubleshooting.md # 常见问题