> ## 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.

# Pump.fun Account Streaming

> Stream and parse Pump.fun bonding curve account updates in real time over Yellowstone gRPC — decode account data and track token state changes.

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.

<Info>
  **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
</Info>

## Installation

```bash theme={null}
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:

```javascript theme={null}
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\nShutting 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:

```javascript theme={null}
{
  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:

```javascript theme={null}
{
  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:

```javascript theme={null}
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:

```javascript theme={null}
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:

```javascript theme={null}
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:

```javascript theme={null}
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:

```javascript theme={null}
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);
      }
    });
  });
}
```

## Performance Tips

<CardGroup cols={2}>
  <Card title="Use PROCESSED Commitment" icon="bolt" iconType="duotone">
    Get updates faster with `CommitmentLevel.PROCESSED` for time-sensitive applications
  </Card>

  <Card title="Filter Efficiently" icon="filter" iconType="duotone">
    Use dataSize and memcmp filters to reduce bandwidth and processing load
  </Card>

  <Card title="Batch Processing" icon="layer-group" iconType="duotone">
    Process account updates in batches for better throughput
  </Card>

  <Card title="Cache Account State" icon="database" iconType="duotone">
    Maintain local cache of account states to detect changes efficiently
  </Card>
</CardGroup>

## Common Use Cases

<Tabs>
  <Tab title="Trading Bot">
    ```javascript theme={null}
    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);
      }
    }
    ```
  </Tab>

  <Tab title="Analytics Dashboard">
    ```javascript theme={null}
    const analytics = {
      totalLiquidity: 0,
      averagePrice: 0,
      activeCurves: 0
    };

    function trackAnalytics(data) {
      if (!data.complete) {
        analytics.activeCurves++;
        analytics.totalLiquidity += Number(data.realSolReserves);
      }
    }
    ```
  </Tab>

  <Tab title="Alert System">
    ```javascript theme={null}
    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}`);
      }
    }
    ```
  </Tab>
</Tabs>

## IDL File

Download the Pump.fun IDL and save it as `idl/pump_0.1.0.json`:

```json theme={null}
{
  "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

<CardGroup cols={2}>
  <Card title="Best Practices" icon="star" iconType="duotone" href="/yellowstone-grpc/best-practices">
    Optimize your implementation
  </Card>

  <Card title="Transaction Parsing" icon="receipt" iconType="duotone" href="/yellowstone-grpc/examples/pumpfun-transactions">
    Detect buy/sell events
  </Card>

  <Card title="Account Monitoring" icon="user" iconType="duotone" href="/yellowstone-grpc/account-monitoring">
    General account monitoring guide
  </Card>
</CardGroup>
