UNPKG

solana-dex-parser

Version:

Solana Dex Transaction Parser

128 lines 5.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MoonshotParser = void 0; const constants_1 = require("../../constants"); const types_1 = require("../../types"); const utils_1 = require("../../utils"); const base_parser_1 = require("../base-parser"); class MoonshotParser extends base_parser_1.BaseParser { processTrades() { const trades = []; this.classifiedInstructions.forEach(({ instruction, programId, outerIndex, innerIndex }) => { if (this.isTradeInstruction(instruction, programId)) { const trade = this.parseTradeInstruction(instruction, `${outerIndex}-${innerIndex ?? 0}`); if (trade) { trades.push(trade); } } }); return trades; } isTradeInstruction(instruction, programId) { const accounts = this.adapter.getInstructionAccounts(instruction); return programId === constants_1.DEX_PROGRAMS.MOONSHOT.id && accounts && accounts.length === 11; } parseTradeInstruction(instruction, idx) { try { if (!('data' in instruction)) return null; const data = (0, utils_1.getInstructionData)(instruction); const discriminator = data.slice(0, 8); let tradeType; if (discriminator.equals(constants_1.DISCRIMINATORS.MOONSHOT.BUY)) { tradeType = 'BUY'; } else if (discriminator.equals(constants_1.DISCRIMINATORS.MOONSHOT.SELL)) { tradeType = 'SELL'; } else { return null; } const moonshotTokenMint = this.adapter.getInstructionAccounts(instruction)[6]; const accountKeys = this.adapter.accountKeys; const collateralMint = this.detectCollateralMint(accountKeys); const { tokenAmount, collateralAmount } = this.calculateAmounts(moonshotTokenMint, collateralMint); const trade = { type: tradeType, inputToken: { mint: tradeType === 'BUY' ? collateralMint : moonshotTokenMint, amount: tradeType === 'BUY' ? (collateralAmount.uiAmount ?? 0) : (tokenAmount.uiAmount ?? 0), amountRaw: tradeType === 'BUY' ? collateralAmount.amount : tokenAmount.amount, decimals: tradeType === 'BUY' ? collateralAmount.decimals : tokenAmount.decimals, }, outputToken: { mint: tradeType === 'BUY' ? moonshotTokenMint : collateralMint, amount: tradeType === 'BUY' ? (tokenAmount.uiAmount ?? 0) : (collateralAmount.uiAmount ?? 0), amountRaw: tradeType === 'BUY' ? tokenAmount.amount : collateralAmount.amount, decimals: tradeType === 'BUY' ? tokenAmount.decimals : collateralAmount.decimals, }, user: this.adapter.signer, programId: constants_1.DEX_PROGRAMS.MOONSHOT.id, amm: constants_1.DEX_PROGRAMS.MOONSHOT.name, route: this.dexInfo.route || '', slot: this.adapter.slot, timestamp: this.adapter.blockTime, signature: this.adapter.signature, idx, }; return this.utils.attachTokenTransferInfo(trade, this.transferActions); } catch (error) { console.error('Failed to parse Moonshot trade:', error); return null; } } detectCollateralMint(accountKeys) { if (accountKeys.some((key) => key === constants_1.TOKENS.USDC)) return constants_1.TOKENS.USDC; if (accountKeys.some((key) => key === constants_1.TOKENS.USDT)) return constants_1.TOKENS.USDT; return constants_1.TOKENS.SOL; } calculateAmounts(tokenMint, collateralMint) { const tokenBalanceChanges = this.getTokenBalanceChanges(tokenMint); const collateralBalanceChanges = this.getTokenBalanceChanges(collateralMint); return { tokenAmount: this.createTokenAmount((0, utils_1.absBigInt)(tokenBalanceChanges), tokenMint), collateralAmount: this.createTokenAmount((0, utils_1.absBigInt)(collateralBalanceChanges), collateralMint), }; } getTokenBalanceChanges(mint) { const signer = this.adapter.signer; if (mint === constants_1.TOKENS.SOL) { if (!this.adapter.postBalances?.[0] || !this.adapter.preBalances?.[0]) { throw new Error('Insufficient balance information for SOL'); } return BigInt(this.adapter.postBalances[0] - this.adapter.preBalances[0]); } let preAmount = BigInt(0); let postAmount = BigInt(0); let balanceFound = false; this.adapter.preTokenBalances?.forEach((preBalance) => { if (preBalance.mint === mint && preBalance.owner === signer) { preAmount = BigInt(preBalance.uiTokenAmount.amount); balanceFound = true; } }); this.adapter.postTokenBalances?.forEach((postBalance) => { if (postBalance.mint === mint && postBalance.owner === signer) { postAmount = BigInt(postBalance.uiTokenAmount.amount); balanceFound = true; } }); if (!balanceFound) { throw new Error('Could not find balance for specified mint and signer'); } return postAmount - preAmount; } createTokenAmount(amount, mint) { const decimals = this.adapter.getTokenDecimals(mint); return { amount: amount.toString(), uiAmount: (0, types_1.convertToUiAmount)(amount, decimals), decimals, }; } } exports.MoonshotParser = MoonshotParser; //# sourceMappingURL=parser-moonshot.js.map