All files parser-raydium.ts

70.58% Statements 24/34
50% Branches 3/6
72.72% Functions 8/11
72.72% Lines 24/33

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67  1x   1x 1x   1x         8x 8x   8x 8x 8x                             8x 8x 8x                         8x 8x   8x 12x 8x 45x 45x         45x 16x   29x 6x   23x    
import { ParsedInstruction, ParsedTransactionWithMeta } from "@solana/web3.js";
import { DEX_PROGRAMS } from "./constants";
import { DexInfo, TokenInfo, TradeInfo, TransferData } from "./types";
import { TokenInfoExtractor } from "./token-extractor";
import { isTransfer, processTransfer, isTransferCheck, processTransferCheck, processSwapData } from "./transfer-utils";
 
export class RaydiumParser {
  private readonly splTokenMap: Map<string, TokenInfo>;
  private readonly splDecimalsMap: Map<string, number>;
 
  constructor(
    private readonly txWithMeta: ParsedTransactionWithMeta,
    private readonly dexInfo: DexInfo
  ) {
    const tokenExtractor = new TokenInfoExtractor(txWithMeta);
    this.splTokenMap = tokenExtractor.extractSPLTokenInfo();
    this.splDecimalsMap = tokenExtractor.extractDecimals();
  }
 
  public processTrades(): TradeInfo[] {
    return this.txWithMeta.transaction.message.instructions
      .reduce((trades: TradeInfo[], instruction: any, index: number) => {
        Iif (this.isRaydiumInstruction(instruction)) {
          const instructionTrades = this.processInstructionTrades(index);
          trades.push(...instructionTrades);
        }
        return trades;
      }, []);
  }
 
  public processInstructionTrades(instructionIndex: number): TradeInfo[] {
    try {
      const transfers = this.processRaydiumSwaps(instructionIndex);
      return transfers.length ? [processSwapData(this.txWithMeta, transfers, this.dexInfo)] : [];
    } catch (error) {
      console.error('Error processing Raydium trades:', error);
      return [];
    }
  }
 
  private isRaydiumInstruction(instruction: any): boolean {
    const programId = instruction.programId.toBase58();
    return [DEX_PROGRAMS.RAYDIUM_V4.id, DEX_PROGRAMS.RAYDIUM_AMM.id, DEX_PROGRAMS.RAYDIUM_CL.id, DEX_PROGRAMS.RAYDIUM_CPMM].includes(programId);
  }
 
  private processRaydiumSwaps(instructionIndex: number): TransferData[] {
    const innerInstructions = this.txWithMeta.meta?.innerInstructions;
    Iif (!innerInstructions) return [];
 
    return innerInstructions
      .filter(set => set.index === instructionIndex)
      .flatMap(set => set.instructions
        .map(instruction => this.processTransferInstruction(instruction as ParsedInstruction))
        .filter((transfer): transfer is TransferData => transfer !== null)
      );
  }
 
  private processTransferInstruction(instruction: ParsedInstruction): TransferData | null {
    if (isTransfer(instruction)) {
      return processTransfer(instruction, this.splTokenMap, this.splDecimalsMap);
    }
    if (isTransferCheck(instruction)) {
      return processTransferCheck(instruction, this.splDecimalsMap);
    }
    return null;
  }
}