UNPKG

solana-dex-parser

Version:

Solana Dex Transaction Parser

117 lines (102 loc) 4.25 kB
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); if (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); if (!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); if (!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 { if (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', }; } }