Documentation Index Fetch the complete documentation index at: https://docs.solanatracker.io/llms.txt
Use this file to discover all available pages before exploring further.
Learn how to stream and parse Pump.fun account data using Yellowstone gRPC. This guide demonstrates efficient account monitoring for trading bots, analytics platforms, and real-time DeFi applications.
Overview
For any Solana dApp, trading bot, or real-time analytics platform, efficient account data access is crucial. Yellowstone gRPC streaming offers a high-performance, low-latency alternative to traditional RPC polling and WebSockets.
What you’ll learn:
Stream all Pump.fun account updates in real-time
Decode account data using the program’s IDL
Track bonding curve and global account changes
Build production-ready account monitoring systems
Installation
npm install @triton-one/yellowstone-grpc @coral-xyz/anchor
Complete Working Example
Here’s a production-ready Pump.fun account monitor with bonding curve tracking:
const Client = require ( "@triton-one/yellowstone-grpc" ). default ;
const { CommitmentLevel } = require ( "@triton-one/yellowstone-grpc" );
const { BorshAccountsCoder } = require ( "@coral-xyz/anchor" );
const fs = require ( 'fs' );
const PUMP_PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" ;
// Load Pump.fun IDL
const pumpFunIdl = JSON . parse (
fs . readFileSync ( './idl/pump_0.1.0.json' , 'utf8' )
);
const accountCoder = new BorshAccountsCoder ( pumpFunIdl );
// Initialize and connect to Yellowstone gRPC
const getClient = async () => {
let client = false ;
try {
client = new Client (
process . env . GRPC_ENDPOINT || "https://grpc.solanatracker.io" ,
process . env . GRPC_API_KEY ,
{
"grpc.max_receive_message_length" : 100 * 1024 * 1024 ,
}
);
const version = await client . getVersion ();
if ( version ) {
console . log ( "Connected to Yellowstone gRPC! Version:" , version );
return client ;
}
} catch ( e ) {
console . error ( "Failed to connect:" , e );
}
if ( ! client ) {
throw new Error ( "Failed to connect!" );
}
};
// Track account statistics
const stats = {
totalUpdates: 0 ,
bondingCurves: new Set (),
completedCurves: 0 ,
lastReportTime: Date . now ()
};
// Handle bonding curve updates
function handleBondingCurve ( data , account ) {
stats . bondingCurves . add ( account . pubkey );
console . log ( ` \n [Bonding Curve Update]` );
console . log ( ` Address: ${ account . pubkey } ` );
console . log ( ` Virtual Token Reserves: ${ data . virtualTokenReserves } ` );
console . log ( ` Virtual Sol Reserves: ${ data . virtualSolReserves } ` );
console . log ( ` Real Token Reserves: ${ data . realTokenReserves } ` );
console . log ( ` Real Sol Reserves: ${ data . realSolReserves } ` );
console . log ( ` Token Total Supply: ${ data . tokenTotalSupply } ` );
console . log ( ` Complete: ${ data . complete } ` );
// Calculate current price
const price = Number ( data . virtualSolReserves ) / Number ( data . virtualTokenReserves );
console . log ( ` Current Price: ${ price . toFixed ( 9 ) } SOL/token` );
if ( data . complete && ! stats . bondingCurves . has ( account . pubkey + '_completed' )) {
stats . completedCurves ++ ;
stats . bondingCurves . add ( account . pubkey + '_completed' );
console . log ( ` \n 🎉 BONDING CURVE COMPLETED!` );
console . log ( ` Address: ${ account . pubkey } ` );
console . log ( ` Final Sol Reserves: ${ ( Number ( data . realSolReserves ) / 1e9 ). toFixed ( 4 ) } SOL` );
console . log ( ` Token Supply: ${ data . tokenTotalSupply } ` );
}
}
// Handle global account updates
function handleGlobalAccount ( data , account ) {
console . log ( ` \n [Global Configuration Update]` );
console . log ( ` Address: ${ account . pubkey } ` );
console . log ( ` Fee Recipient: ${ data . feeRecipient } ` );
console . log ( ` Initial Virtual Token Reserves: ${ data . initialVirtualTokenReserves } ` );
console . log ( ` Initial Virtual Sol Reserves: ${ data . initialVirtualSolReserves } ` );
}
( async () => {
const client = await getClient ();
const stream = await client . subscribe ();
// Handle stream lifecycle
const streamClosed = new Promise (( resolve , reject ) => {
stream . on ( "error" , ( error ) => {
console . error ( "Stream error:" , error );
});
stream . on ( "end" , () => {
console . log ( "Stream ended" );
resolve ();
});
stream . on ( "close" , () => {
console . log ( "Stream closed" );
resolve ();
});
});
// Handle incoming account updates
stream . on ( "data" , ( data ) => {
if ( data ?. account ) {
stats . totalUpdates ++ ;
const accountData = data . account . account ;
try {
// Decode account data
const decodedData = accountCoder . decodeAny ( accountData . data );
console . log ( ` \n [Account Update # ${ stats . totalUpdates } ]` );
console . log ( ` Address: ${ accountData . pubkey } ` );
console . log ( ` Type: ${ decodedData . discriminator } ` );
console . log ( ` Slot: ${ data . account . slot } ` );
// Process based on account type
if ( decodedData . discriminator === 'BondingCurve' ) {
handleBondingCurve ( decodedData , accountData );
} else if ( decodedData . discriminator === 'Global' ) {
handleGlobalAccount ( decodedData , accountData );
}
} catch ( error ) {
// Ignore decoding errors for unknown account types
}
// Report statistics every 100 updates
if ( stats . totalUpdates % 100 === 0 ) {
const now = Date . now ();
const elapsed = ( now - stats . lastReportTime ) / 1000 ;
const rate = 100 / elapsed ;
console . log ( ` \n === Statistics ===` );
console . log ( ` Total Updates: ${ stats . totalUpdates } ` );
console . log ( ` Update Rate: ${ rate . toFixed ( 2 ) } /sec` );
console . log ( ` Bonding Curves Tracked: ${ stats . bondingCurves . size } ` );
console . log ( ` Completed Curves: ${ stats . completedCurves } ` );
stats . lastReportTime = now ;
}
}
});
// Subscribe to Pump.fun accounts
const request = {
accounts: {
pumpfun: {
account: [],
owner: [ PUMP_PROGRAM_ID ], // Stream all accounts owned by Pump.fun
filters: []
}
},
slots: {},
transactions: {},
transactionsStatus: {},
entry: {},
blocks: {},
blocksMeta: {},
accountsDataSlice: [],
ping: undefined ,
commitment: CommitmentLevel . PROCESSED , // Fastest updates
};
// Send subscribe request
await new Promise (( resolve , reject ) => {
stream . write ( request , ( err ) => {
if ( err === null || err === undefined ) {
console . log ( "✅ Monitoring Pump.fun accounts... \n " );
resolve ();
} else {
reject ( err );
}
});
}). catch (( reason ) => {
console . error ( "Subscribe failed:" , reason );
throw reason ;
});
await streamClosed ;
})();
// Graceful shutdown
process . on ( 'SIGINT' , () => {
console . log ( ' \n\n Shutting down gracefully...' );
console . log ( `Final Stats - Updates: ${ stats . totalUpdates } , Curves: ${ stats . bondingCurves . size } , Completed: ${ stats . completedCurves } ` );
process . exit ( 0 );
});
Pump.fun Account Types
Bonding Curve Account
The bonding curve account contains the token economics and liquidity information:
{
virtualTokenReserves : bigint , // Virtual token reserves for pricing
virtualSolReserves : bigint , // Virtual SOL reserves for pricing
realTokenReserves : bigint , // Actual tokens in the curve
realSolReserves : bigint , // Actual SOL in the curve
tokenTotalSupply : bigint , // Total token supply
complete : boolean // Whether bonding curve is complete
}
Use cases:
Calculate current token price
Monitor liquidity changes
Detect when bonding curve completes
Track token supply distribution
Global Account
The global account contains program-wide configuration:
{
feeRecipient : string , // Address receiving fees
initialVirtualTokenReserves : bigint , // Initial virtual token reserves
initialVirtualSolReserves : bigint , // Initial virtual SOL reserves
initialRealTokenReserves : bigint , // Initial real token reserves
tokenTotalSupply : bigint , // Standard token total supply
feeBasisPoints : number // Fee in basis points
}
Advanced Examples
Example 2: Track Specific Bonding Curves
Monitor only specific bonding curve addresses:
const BONDING_CURVES = [
"BondingCurve1..." ,
"BondingCurve2..." ,
"BondingCurve3..."
];
const request = {
accounts: {
specificCurves: {
account: BONDING_CURVES , // Monitor specific accounts
owner: [],
filters: []
}
},
// ... other fields
commitment: CommitmentLevel . CONFIRMED ,
};
Example 3: Filter for Active Bonding Curves
Filter for incomplete bonding curves only:
const request = {
accounts: {
activeBondingCurves: {
account: [],
owner: [ PUMP_PROGRAM_ID ],
filters: [
{ dataSize: 120 }, // Bonding curve account size
{
memcmp: {
offset: 108 , // Offset to 'complete' field
bytes: Buffer . from ([ 0 ]). toString ( 'base64' ) // Filter for incomplete
}
}
]
}
},
// ... other fields
commitment: CommitmentLevel . CONFIRMED ,
};
Example 4: Price Tracking
Track price movements across all bonding curves:
const priceHistory = new Map (); // curve address -> array of prices
function trackPrice ( address , virtualSol , virtualToken ) {
const price = Number ( virtualSol ) / Number ( virtualToken );
if ( ! priceHistory . has ( address )) {
priceHistory . set ( address , []);
}
const history = priceHistory . get ( address );
history . push ({ price , timestamp: Date . now () });
// Keep only last 100 prices
if ( history . length > 100 ) {
history . shift ();
}
// Calculate price change
if ( history . length > 1 ) {
const oldPrice = history [ 0 ]. price ;
const priceChange = (( price - oldPrice ) / oldPrice ) * 100 ;
if ( Math . abs ( priceChange ) > 50 ) { // 50% change
console . log ( ` \n 🚨 PRICE ALERT` );
console . log ( ` Curve: ${ address } ` );
console . log ( ` Change: ${ priceChange . toFixed ( 2 ) } %` );
console . log ( ` Current Price: ${ price . toFixed ( 9 ) } SOL` );
}
}
}
// Call in handleBondingCurve:
trackPrice (
account . pubkey ,
data . virtualSolReserves ,
data . virtualTokenReserves
);
Example 5: Liquidity Monitoring
Track liquidity changes:
const liquidityTracker = new Map (); // curve -> last liquidity
function trackLiquidity ( address , realSol ) {
const liquidity = Number ( realSol ) / 1e9 ; // Convert to SOL
const previous = liquidityTracker . get ( address );
if ( previous ) {
const change = liquidity - previous ;
const percentChange = ( change / previous ) * 100 ;
if ( Math . abs ( percentChange ) > 10 ) { // 10% change
console . log ( ` \n 💧 LIQUIDITY CHANGE` );
console . log ( ` Curve: ${ address } ` );
console . log ( ` Current: ${ liquidity . toFixed ( 4 ) } SOL` );
console . log ( ` Change: ${ change > 0 ? '+' : '' }${ change . toFixed ( 4 ) } SOL ( ${ percentChange . toFixed ( 1 ) } %)` );
}
}
liquidityTracker . set ( address , liquidity );
}
Dynamic Subscription Management
Modify your subscription on-the-fly without restarting:
async function addCurveToMonitor ( stream , bondingCurveAddress ) {
await new Promise (( resolve , reject ) => {
stream . write ({
accounts: {
newCurve: {
account: [ bondingCurveAddress ],
owner: [],
filters: []
}
}
}, ( err ) => {
if ( err === null || err === undefined ) {
console . log ( `Added ${ bondingCurveAddress } to monitoring` );
resolve ();
} else {
reject ( err );
}
});
});
}
Use PROCESSED Commitment Get updates faster with CommitmentLevel.PROCESSED for time-sensitive applications
Filter Efficiently Use dataSize and memcmp filters to reduce bandwidth and processing load
Batch Processing Process account updates in batches for better throughput
Cache Account State Maintain local cache of account states to detect changes efficiently
Common Use Cases
Trading Bot
Analytics Dashboard
Alert System
function handleBondingCurve ( data , account ) {
// Calculate current price
const price = Number ( data . virtualSolReserves ) / Number ( data . virtualTokenReserves );
// Check if price is favorable
if ( price < TARGET_PRICE && ! data . complete ) {
executeBuy ( account . pubkey , AMOUNT );
}
}
const analytics = {
totalLiquidity: 0 ,
averagePrice: 0 ,
activeCurves: 0
};
function trackAnalytics ( data ) {
if ( ! data . complete ) {
analytics . activeCurves ++ ;
analytics . totalLiquidity += Number ( data . realSolReserves );
}
}
function checkAlerts ( data , account ) {
const liquidity = Number ( data . realSolReserves ) / 1e9 ;
if ( liquidity > LARGE_LIQUIDITY_THRESHOLD ) {
sendAlert ( `Large bonding curve: ${ liquidity . toFixed ( 2 ) } SOL` );
}
if ( data . complete ) {
sendAlert ( `Bonding curve completed: ${ account . pubkey } ` );
}
}
IDL File
Download the Pump.fun IDL and save it as idl/pump_0.1.0.json:
{
"version" : "0.1.0" ,
"name" : "pump" ,
"accounts" : [
{
"name" : "BondingCurve" ,
"type" : {
"kind" : "struct" ,
"fields" : [
{ "name" : "virtualTokenReserves" , "type" : "u64" },
{ "name" : "virtualSolReserves" , "type" : "u64" },
{ "name" : "realTokenReserves" , "type" : "u64" },
{ "name" : "realSolReserves" , "type" : "u64" },
{ "name" : "tokenTotalSupply" , "type" : "u64" },
{ "name" : "complete" , "type" : "bool" }
]
}
},
{
"name" : "Global" ,
"type" : {
"kind" : "struct" ,
"fields" : [
{ "name" : "feeRecipient" , "type" : "publicKey" },
{ "name" : "initialVirtualTokenReserves" , "type" : "u64" },
{ "name" : "initialVirtualSolReserves" , "type" : "u64" }
]
}
}
]
}
Resources
Best Practices Optimize your implementation
Transaction Parsing Detect buy/sell events
Account Monitoring General account monitoring guide