All files / src/parsers/raydium parser-raydium-liquidity-base.ts

13.51% Statements 5/37
0% Branches 0/31
0% Functions 0/6
15.15% Lines 5/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 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 107 108 109 110 111 112 113 114 115 116 1171x 1x 1x 1x                         1x                                                                                                                                                                                                        
import { TOKENS } from '../../constants';
import { convertToUiAmount, PoolEvent, PoolEventType, TransferData } from '../../types';
import { getInstructionData } from '../../utils';
import { BaseLiquidityParser } from '../base-liquidity-parser';
 
export interface ParseEventConfig {
  eventType: PoolEventType;
  poolIdIndex: number;
  lpMintIndex: number;
  tokenAmountOffsets?: {
    token0: number;
    token1: number;
    lp: number;
  };
}
 
export abstract class RaydiumLiquidityParserBase extends BaseLiquidityParser {
  abstract getPoolAction(data: Buffer): PoolEventType | { name: string; type: PoolEventType } | null;
 
  abstract getEventConfig(
    type: PoolEventType,
    instructionType: PoolEventType | { name: string; type: PoolEventType }
  ): ParseEventConfig | null;
 
  public processLiquidity(): PoolEvent[] {
    const events: PoolEvent[] = [];
 
    this.classifiedInstructions.forEach(({ instruction, programId, outerIndex, innerIndex }) => {
      const event = this.parseRaydiumInstruction(instruction, programId, outerIndex, innerIndex);
      Iif (event) {
        events.push(event);
      }
    });
 
    return events;
  }
 
  protected parseRaydiumInstruction(
    instruction: any,
    programId: string,
    outerIndex: number,
    innerIndex?: number
  ): PoolEvent | null {
    try {
      const data = getInstructionData(instruction);
      const instructionType = this.getPoolAction(data);
      Iif (!instructionType) return null;
 
      const accounts = this.adapter.getInstructionAccounts(instruction);
      const type = typeof instructionType === 'string' ? instructionType : instructionType.type;
      const transfers = this.getTransfersForInstruction(programId, outerIndex, innerIndex).filter(
        (it) => it.info.authority && accounts.includes(it.info.destination) && it.programId != TOKENS.NATIVE
      );
 
      const config = this.getEventConfig(type, instructionType);
 
      Iif (!config) return null;
      return this.parseEvent(instruction, outerIndex, data, transfers, config);
    } catch (error) {
      console.error('parseRaydiumInstruction error:', error);
      return null;
    }
  }
 
  protected parseEvent(
    instruction: any,
    index: number,
    data: Buffer,
    transfers: TransferData[],
    config: ParseEventConfig
  ): PoolEvent | null {
    Iif (config.eventType === 'ADD' && transfers.length < 2) return null;
 
    const [token0, token1] = this.utils.getLPTransfers(transfers);
    const lpToken = transfers.find((it) => it.type === (config.eventType === 'REMOVE' ? 'burn' : 'mintTo'));
    const programId = this.adapter.getInstructionProgramId(instruction);
    const accounts = this.adapter.getInstructionAccounts(instruction);
 
    const token0Mint = token0?.info.mint;
    const token1Mint = token1?.info.mint;
    const [token0Decimals, token1Decimals] = [
      this.adapter.getTokenDecimals(token0Mint),
      this.adapter.getTokenDecimals(token1Mint),
    ];
 
    return {
      ...this.adapter.getPoolEventBase(config.eventType, programId),
      idx: index.toString(),
      poolId: accounts[config.poolIdIndex],
      poolLpMint: lpToken?.info.mint || accounts[config.lpMintIndex],
      token0Mint,
      token1Mint,
      token0Amount:
        token0?.info.tokenAmount.uiAmount ||
        (config.tokenAmountOffsets &&
          convertToUiAmount(data.readBigUInt64LE(config.tokenAmountOffsets.token0), token0Decimals)),
      token0AmountRaw:
        token0?.info.tokenAmount.amount ||
        (config.tokenAmountOffsets && data.readBigUInt64LE(config.tokenAmountOffsets.token0).toString()),
      token1Amount:
        token1?.info.tokenAmount.uiAmount ||
        (config.tokenAmountOffsets &&
          convertToUiAmount(data.readBigUInt64LE(config.tokenAmountOffsets.token1), token1Decimals)),
      token1AmountRaw:
        token1?.info.tokenAmount.amount ||
        (config.tokenAmountOffsets && data.readBigUInt64LE(config.tokenAmountOffsets.token1).toString()),
      token0Decimals,
      token1Decimals,
      lpAmount: lpToken?.info.tokenAmount.uiAmount,
      lpAmountRaw:
        lpToken?.info.tokenAmount.amount ||
        (config.tokenAmountOffsets && data.readBigUInt64LE(config.tokenAmountOffsets.lp).toString()) ||
        '0',
    };
  }
}