All files / src/parsers/pumpfun parser-pumpfun-event.ts

23.33% Statements 7/30
0% Branches 0/6
0% Functions 0/8
24.13% Lines 7/29

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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 1071x 1x 1x 1x                   1x 1x   1x                                                                                                                                                                                    
import base58 from 'bs58';
import { Buffer } from 'buffer';
import { DEX_PROGRAMS, DISCRIMINATORS } from '../../constants';
import { InstructionClassifier } from '../../instruction-classifier';
import { TransactionAdapter } from '../../transaction-adapter';
import {
  ClassifiedInstruction,
  EventParser,
  PumpfunCompleteEvent,
  PumpfunCreateEvent,
  PumpfunEvent,
  PumpfunTradeEvent,
} from '../../types';
import { getInstructionData } from '../../utils';
import { BinaryReader } from '../binary-reader';
 
export class PumpfunEventParser {
  constructor(private readonly adapter: TransactionAdapter) {}
 
  private readonly eventParsers: Record<string, EventParser<any>> = {
    TRADE: {
      discriminator: DISCRIMINATORS.PUMPFUN.TRADE_EVENT,
      decode: this.decodeTradeEvent.bind(this),
    },
    CREATE: {
      discriminator: DISCRIMINATORS.PUMPFUN.CREATE_EVENT,
      decode: this.decodeCreateEvent.bind(this),
    },
    COMPLETE: {
      discriminator: DISCRIMINATORS.PUMPFUN.COMPLETE_EVENT,
      decode: this.decodeCompleteEvent.bind(this),
    },
  };
 
  public processEvents(): PumpfunEvent[] {
    const instructions = new InstructionClassifier(this.adapter).getInstructions(DEX_PROGRAMS.PUMP_FUN.id);
    return this.parseInstructions(instructions);
  }
 
  public parseInstructions(instructions: ClassifiedInstruction[]): PumpfunEvent[] {
    return instructions
      .map(({ instruction, outerIndex, innerIndex }) => {
        try {
          const data = getInstructionData(instruction);
          const discriminator = Buffer.from(data.slice(0, 16));
 
          for (const [type, parser] of Object.entries(this.eventParsers)) {
            Iif (discriminator.equals(parser.discriminator)) {
              const eventData = parser.decode(data.slice(16));
              Iif (!eventData) return null;
 
              return {
                type: type as 'TRADE' | 'CREATE' | 'COMPLETE',
                data: eventData,
                slot: this.adapter.slot,
                timestamp: this.adapter.blockTime || 0,
                signature: this.adapter.signature,
                idx: `${outerIndex}-${innerIndex ?? 0}`,
              };
            }
          }
        } catch (error) {
          console.error('Failed to parse Pumpfun event:', error);
        }
        return null;
      })
      .filter((event): event is PumpfunEvent => event !== null);
  }
 
  private decodeTradeEvent(data: Buffer): PumpfunTradeEvent {
    const reader = new BinaryReader(data);
 
    return {
      mint: base58.encode(Buffer.from(reader.readFixedArray(32))),
      solAmount: reader.readU64(),
      tokenAmount: reader.readU64(),
      isBuy: reader.readU8() === 1,
      user: base58.encode(reader.readFixedArray(32)),
      timestamp: reader.readI64(),
      virtualSolReserves: reader.readU64(),
      virtualTokenReserves: reader.readU64(),
    };
  }
 
  private decodeCreateEvent(data: Buffer): PumpfunCreateEvent {
    const reader = new BinaryReader(data);
    return {
      name: reader.readString(),
      symbol: reader.readString(),
      uri: reader.readString(),
      mint: base58.encode(Buffer.from(reader.readFixedArray(32))),
      bondingCurve: base58.encode(reader.readFixedArray(32)),
      user: base58.encode(reader.readFixedArray(32)),
    };
  }
 
  private decodeCompleteEvent(data: Buffer): PumpfunCompleteEvent {
    const reader = new BinaryReader(data);
    return {
      user: base58.encode(reader.readFixedArray(32)),
      mint: base58.encode(Buffer.from(reader.readFixedArray(32))),
      bondingCurve: base58.encode(reader.readFixedArray(32)),
      timestamp: reader.readI64(),
    };
  }
}