All Resources
Parse Meteora DLMM Swaps from Solana gRPC Streams
MeteoraTypeScriptMarch 26, 20262 min read

Parse Meteora DLMM Swaps from Solana gRPC Streams

Stream Meteora DLMM transactions and decode swaps, liquidity changes and bin-level context with TypeScript.

meteoradlmmgrpctypescriptliquidity

Meteora DLMM parsing is not a simple swap decoder

Meteora's Dynamic Liquidity Market Maker (DLMM) is one of Solana's most innovative DEX protocols, offering concentrated liquidity with dynamic fees. For developers building analytics tools, arbitrage bots, or liquidity management systems, parsing DLMM transactions is a core requirement.

The parsing work is more nuanced than AMM v4 style swaps because DLMM liquidity lives in price bins. You need the stream, the program context and enough instruction decoding to avoid flattening every transaction into the same shape.

Why DLMM bins change the parsing model

Unlike traditional AMMs with uniform liquidity distribution, Meteora DLMM uses a bin-based system:

  • Liquidity is organized into discrete price bins
  • Each bin has a specific price range
  • Fees adjust dynamically based on market volatility
  • LPs can concentrate liquidity around the current price

This architecture means transaction parsing is more nuanced than simple AMM swaps.

Subscribe to the Meteora DLMM program

import Client, { CommitmentLevel } from '@triton-one/yellowstone-grpc';

const METEORA_DLMM_PROGRAM = 'LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo';

const client = new Client(process.env.YELLOWSTONE_GRPC_ENDPOINT!, process.env.YELLOWSTONE_GRPC_TOKEN!, undefined);
await client.connect();
const stream = await client.subscribe();

await stream.write({
  transactions: {
    meteora: {
      accountInclude: [METEORA_DLMM_PROGRAM],
      accountExclude: [],
      accountRequired: [],
      failed: false,
      vote: false,
    },
  },
  accounts: {},
  slots: {},
  blocks: {},
  blocksMeta: {},
  entry: {},
  accountsDataSlice: [],
  transactionsStatus: {},
  commitment: CommitmentLevel.PROCESSED,
});

Parsing DLMM Instructions

Meteora DLMM has several key instruction types:

Swap

The most common instruction, token swaps through DLMM pools.

Add Liquidity

LPs adding tokens to specific bins. Includes parameters for bin range and distribution strategy.

Remove Liquidity

LPs withdrawing tokens from bins. Important for tracking liquidity changes.

Initialize Position

Creating a new LP position in a pool.

import { createHash } from 'crypto';
import meteoraIdl from './idl/meteora-dlmm.json';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

function parseSwap(data: Buffer) {
  if (data.length < 24 || !data.subarray(0, 8).equals(SWAP_DISC)) return null;
  return {
    amountIn: data.readBigUInt64LE(8).toString(),
    minAmountOut: data.readBigUInt64LE(16).toString(),
  };
}

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

import { createHash } from 'crypto';

const SWAP_DISC = createHash('sha256').update('global:swap').digest().subarray(0, 8);

function parseMeteoraDLMMTx(tx: TransactionUpdate) {
  const message = tx.transaction?.message;
  if (!message) return null;

  const events = [];
  for (const ix of message.instructions) {
    const data = Buffer.from(ix.data);
    if (data.length < 24 || !data.subarray(0, 8).equals(SWAP_DISC)) continue;
    events.push({
      type: 'swap',
      amountIn: data.readBigUInt64LE(8).toString(),
      minAmountOut: data.readBigUInt64LE(16).toString(),
      pool: message.accountKeys[ix.accounts[0]],
    });
  }
  return events;
}

Detecting Buy and Sell Events

To classify swaps as buys or sells, compare the input token against the pool's base token:

function classifyDLMMSwap(swap: DLMMSwap, pool: DLMMPool): 'buy' | 'sell' {
  // If swapping SOL/USDC for the token, it's a buy
  // If swapping the token for SOL/USDC, it's a sell
  return swap.swapForY ? 'buy' : 'sell';
}

Working with Bin Data

DLMM bin data provides rich information about liquidity distribution:

// Fetch bin arrays for price analysis
function calculatePriceFromBin(binId: number, binStep: number): number {
  return Math.pow(1 + binStep / 10000, binId - 8388608);
}

Where Meteora parsing gets sharp in production

  1. Multiple pool types, Meteora has DLMM, DAMM v2, and DBC pools. Each has a different program ID and IDL.
  2. Bin precision, Prices derived from bins have specific decimal precision depending on the token pair.
  3. Event ordering, A single transaction can contain multiple Meteora instructions. Process them in order.
  4. Account data, For full context, you may need to fetch the pool account data to know the token mints.

Use indexed pool data where raw decoding is wasteful

Solana Tracker's Data API provides pre-indexed Meteora pool data. Stream via Yellowstone gRPC on Dedicated Nodes including TVL, volume, and price history, saving you from building your own indexer. For real-time needs, combine the Data API with gRPC streaming for comprehensive coverage.

Download the example

Clone the full runnable project on GitHub, npm install && npm start with your keys in .env. See the tutorial for step-by-step context.

Runnable Node.js project — clone from GitHub, add keys to .env, then npm start. gRPC examples use native dependencies — run locally with Node.js.