Skip to main content
Index Orca Whirlpool swap instructions from Solana mainnet.

Prerequisites

  • Node.js 22+ installed
  • TypeScript project initialized
1

Download and install

Install the Pipes SDK package.
npm install @subsquid/pipes
2

Create the script

Create a file index.ts with the code listed below:
index.ts
import {
  solanaInstructionDecoder,
  solanaPortalSource,
} from "@subsquid/pipes/solana";
import * as orcaWhirlpool from "./abi/orca_whirlpool/index.js";

async function main() {
  const source = solanaPortalSource({
    portal: "https://portal.sqd.dev/datasets/solana-mainnet",
  });

  const decoder = solanaInstructionDecoder({
    range: { from: 200000000, to: 200001000 },
    programId: orcaWhirlpool.programId,
    instructions: {
      swap: orcaWhirlpool.instructions.swap,
      swapV2: orcaWhirlpool.instructions.swapV2,
    },
  });

  for await (const { data } of source.pipe(decoder)) {
    console.log(`Swaps: ${data.swap.length + data.swapV2.length}`);
    for (const swap of [...data.swap, ...data.swapV2]) {
      console.log(
        `  Slot ${swap.blockNumber}: Swap instruction in tx ${swap.transaction.signatures[0]}`
      );
    }
  }
}

void main();
3

Run the script

Execute the script to start indexing swap instructions.
npx tsx index.ts
You should see swap instructions printed to the console:
Swaps: 42
  Slot 200000123: Swap instruction in tx 0x123...
  Slot 200000124: Swap instruction in tx 0x456...
...

Complete Code

The complete code retrieves and decodes Orca Whirlpool swap instructions from Solana mainnet.
index.ts
import {
  solanaInstructionDecoder,
  solanaPortalSource,
} from "@subsquid/pipes/solana";
import * as orcaWhirlpool from "./abi/orca_whirlpool/index.js";

async function main() {
  // Create a Portal source that streams blockchain data
  const source = solanaPortalSource({
    portal: "https://portal.sqd.dev/datasets/solana-mainnet",
  });

  // Create a decoder that automatically decodes swap instructions
  const decoder = solanaInstructionDecoder({
    // Process slots 200000000 to 200001000
    range: { from: 200000000, to: 200001000 },
    // Monitor the Orca Whirlpool program
    programId: orcaWhirlpool.programId,
    // Decode swap and swapV2 instructions using the program ABI
    instructions: {
      swap: orcaWhirlpool.instructions.swap,
      swapV2: orcaWhirlpool.instructions.swapV2,
    },
  });

  // Stream and process decoded instructions
  for await (const { data } of source.pipe(decoder)) {
    console.log(`Swaps: ${data.swap.length + data.swapV2.length}`);
    // Each swap contains decoded instruction data
    for (const swap of [...data.swap, ...data.swapV2]) {
      console.log(
        `  Slot ${swap.blockNumber}: Swap instruction in tx ${swap.transaction.signatures[0]}`
      );
    }
  }
}

void main();

How it works

  1. Portal source: solanaPortalSource connects to the Portal API and streams Solana blockchain data
  2. Decoder: solanaInstructionDecoder filters and decodes program instructions using ABIs
  3. Pipe: .pipe() chains the decoder to the source
  4. Stream: The for await loop processes batches of decoded data as they arrive

Data structure

Each decoded swap instruction contains:
  • blockNumber: Slot number where the instruction occurred
  • timestamp: Block timestamp
  • programId: Program address that executed the instruction
  • transaction: Transaction details including signatures
  • instruction: Decoded instruction fields (accounts, data)
  • rawInstruction: Raw instruction data

Next steps

  • Use range: { from: 'latest' } to stream from the latest slots
  • Add multiple programs or instruction types
  • Use createTarget to persist data to a database
  • See Basics for more examples