import { NATIVE_MINT } from '@saberhq/token-utils' ; import type { ParsedInnerInstruction } from '@solana/web3.js' ; import type { ParsedConfirmedTransaction , ParsedInstruction } from '../../../../../' ; import { instructionsData } from '../../utils/instructionsData' ; import type { Parser } from '../' ; import { SwapTransaction } from './types' ; export class OrcaSwapParser implements Parser { private static _supportedProgramId = [ 'DjVE6JNiYqPL2QXyCUUh8rNjHrbz9hXHNYt99MQ59qw1' , '9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP' , '9qvG1zUp8xF1Bi4m6UdRNby1BAAuaDrUxSpv4CmRRMjL' , 'SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8' , ] ; /**
     Check instruction can be parsed
     */ static can ( instructions ) { return instructions . some ( ( inst ) => this . _supportedProgramId . includes ( inst . programId . toBase58 ( ) ) ) ; } /**
     Check liquidity to pool
     - Parameter instructions: inner instructions
     */ private static _isLiquidityToPool ( innerInstructions ? ) { const instructions = innerInstructions ?. [ 0 ] ?. instructions as ParsedInstruction [ ] | null ; switch ( instructions ?. length ) { case 3 : return ( instructions [ 0 ] ?. parsed ?. type === 'transfer' && instructions [ 1 ] ?. parsed ?. type === 'transfer' && instructions [ 2 ] ?. parsed ?. type === 'mintTo' ) ; default : return false ; } } /**
     Check liquidity to pool
     - Parameter instructions: inner instructions
     */ private static _isBurn ( innerInstructions ? ) { const instructions = innerInstructions ?. [ 0 ] ?. instructions as ParsedInstruction [ ] | null ; switch ( instructions ?. length ) { case 3 : return ( instructions ?. length === 3 && instructions [ 0 ] ?. parsed ?. type === 'burn' && instructions [ 1 ] ?. parsed ?. type === 'transfer' && instructions [ 2 ] ?. parsed ?. type === 'transfer' ) ; default : return false ; } } private static _parseFailedTransaction ( transactionInfo ) { const postTokenBalances = transactionInfo . meta ?. postTokenBalances ; const approveInstruction = transactionInfo . transaction . message . instructions . find ( ( inst ) => inst ?. parsed ?. type === 'approve' ) ; const sourceAmountString = approveInstruction ?. parsed ?. info . amount ; const destinationMint = postTokenBalances ?. at ( - 1 ) ?. mint ; if ( ! postTokenBalances || ! approveInstruction || ! sourceAmountString || ! destinationMint ) { return null ; } let destination ; if ( destinationMint === NATIVE_MINT . toBase58 ( ) ) { destination = approveInstruction ?. parsed ?. info . owner ; } const source = approveInstruction ?. parsed ?. info . source ; const sourceAmount = sourceAmountString || ( postTokenBalances ?. at ( 0 ) ?. uiTokenAmount . amount ?? '0' ) ; const destinationAmount = postTokenBalances ?. at ( - 1 ) ?. uiTokenAmount . amount ?? '0' ; return new SwapTransaction ( source , sourceAmount , destination , destinationAmount ) ; } private static _parse ( transactionInfo ) { const swapInstructions = instructionsData ( transactionInfo ) . filter ( ( data ) => this . _supportedProgramId . includes ( data . instruction . programId . toBase58 ( ) ) ) ; if ( swapInstructions . length === 0 ) { return this . _parseFailedTransaction ( transactionInfo ) ; } const sourceInstruction = swapInstructions . at ( 0 ) ?. innerInstruction ?. instructions . at ( 0 ) ; const destinationInstruction = swapInstructions . at ( - 1 ) ?. innerInstruction ?. instructions . at ( - 1 ) ; if ( ! sourceInstruction || ! destinationInstruction ) { return this . _parseFailedTransaction ( transactionInfo ) ; } const sourceInfo = sourceInstruction . parsed ?. info ; const destinationInfo = destinationInstruction . parsed ?. info ; let source = sourceInfo ?. source || sourceInfo ?. destination ; const sourceAmount = sourceInfo ?. amount ?? '0' ; let destination = destinationInfo ?. destination || destinationInfo ?. source ; const destinationAmount = destinationInfo ?. amount ?? '0' ; const closeInstruction = transactionInfo . transaction . message . instructions . find ( ( inst ) => inst . parsed ?. type === 'closeAccount' ) ; if ( closeInstruction ?. parsed ) { if ( closeInstruction . parsed . info . account === source ) { source = closeInstruction . parsed . info . destination ; } if ( closeInstruction . parsed . info . account === destination ) { destination = closeInstruction . parsed . info . destination ; } } return new SwapTransaction ( source , sourceAmount , destination , destinationAmount ) ; } static parse ( transactionInfo ) { const innerInstructions = transactionInfo . meta ?. innerInstructions ; switch ( true ) { case this . _isLiquidityToPool ( innerInstructions ) : return null ; case this . _isBurn ( innerInstructions ) : return null ; default : return this . _parse ( transactionInfo ) ; } } }