diff --git a/botManager.js b/botManager.js new file mode 100644 index 0000000..b04870a --- /dev/null +++ b/botManager.js @@ -0,0 +1,523 @@ +import { Connection, PublicKey, Keypair, Transaction } from '@solana/web3.js'; +import BN from 'bn.js'; +import bs58 from 'bs58'; +import dlmmPackage from '@meteora-ag/dlmm'; +import { getPrice } from './lib/price.js'; +import { monitorPositionLoop } from './main.js'; + +const DLMM = dlmmPackage.default ?? dlmmPackage; + +class PoolBot { + constructor(config) { + this.config = config; + this.botId = config.botId; + this.status = 'initializing'; + this.position = null; + this.connection = null; + this.dlmmPool = null; + this.userKeypair = null; + this.monitorInterval = null; + this.metrics = { + currentValue: 0, + pnl: 0, + pnlPercentage: 0, + feesEarned: 0, + rebalanceCount: 0, + lastRebalance: null, + initialValue: 0 + }; + } + + async start() { + try { + this.status = 'starting'; + + // Setup connection + this.connection = new Connection(this.config.rpcUrl, 'confirmed'); + + // Setup keypair + const privateKeyBytes = bs58.decode(this.config.privateKey); + this.userKeypair = Keypair.fromSecretKey(privateKeyBytes); + + // Create DLMM pool instance + const poolPK = new PublicKey(this.config.poolAddress); + this.dlmmPool = await DLMM.create(this.connection, poolPK); + + // Open position using existing MeteorShower logic + const result = await this.openPosition(); + + if (result.success) { + this.position = result.position; + this.status = 'running'; + // Convert SOL initial value to USD for accurate PnL calculation + const solPrice = await getPrice('So11111111111111111111111111111111111111112'); + this.metrics.initialValue = this.config.solAmount * solPrice; + + // Start monitoring + this.startMonitoring(); + + return { + success: true, + positionAddress: result.positionAddress + }; + } else { + this.status = 'error'; + return { + success: false, + error: result.error + }; + } + } catch (error) { + this.status = 'error'; + return { + success: false, + error: error.message + }; + } + } + + async openPosition() { + try { + + + // Use existing openDlmmPosition logic from main.js + const { openDlmmPosition } = await import('./lib/dlmm.js'); + + // Convert allocation to token ratio object + const tokenRatio = { + ratioX: this.config.allocation, + ratioY: 1 - this.config.allocation + }; + + + const result = await openDlmmPosition( + this.connection, + this.userKeypair, + this.config.solAmount, + tokenRatio, // Proper token ratio object + this.config.binSpan, + this.config.poolAddress, + this.config.liquidityStrategy, + { + takeProfitEnabled: this.config.takeProfitEnabled, + takeProfitPercent: this.config.takeProfitPercent, + stopLossEnabled: this.config.stopLossEnabled, + stopLossPercent: this.config.stopLossPercent, + autoCompound: this.config.autoCompound + } + ); + + return { + success: true, + position: result, + positionAddress: result.positionPubKey.toBase58() + }; + } catch (error) { + return { + success: false, + error: error.message + }; + } + } + + startMonitoring() { + this.monitorInterval = setInterval(async () => { + try { + await this.updateMetrics(); + } catch (error) { + // Silent error handling + } + }, 5000); // Update every 5 seconds + } + + async updateMetrics() { + try { + if (!this.position || !this.dlmmPool) { + return; + } + + // Get current position data + const positionData = await this.dlmmPool.getPosition(this.position.positionPubKey); + + // Calculate current value + const solPrice = await getPrice('So11111111111111111111111111111111111111112'); + const tokenPrice = await this.getTokenPrice(); + + // Calculate P&L + const currentValue = this.calculateCurrentValue(positionData, solPrice, tokenPrice); + const pnl = currentValue - this.metrics.initialValue; + const pnlPercentage = this.metrics.initialValue > 0 ? (pnl / this.metrics.initialValue) * 100 : 0; + + // Update metrics + this.metrics.currentValue = currentValue; + this.metrics.pnl = pnl; + this.metrics.pnlPercentage = pnlPercentage; + this.metrics.feesEarned = this.calculateFeesEarned(positionData); + this.metrics.lastUpdate = new Date(); + + // Check for rebalancing needs + await this.checkRebalancing(positionData); + + } catch (error) { + // Silent error handling + } + } + + async getTokenPrice() { + try { + const tokenMint = this.dlmmPool.tokenX.publicKey.toString(); + return await getPrice(tokenMint); + } catch (error) { + return 0; + } + } + + calculateCurrentValue(positionData, solPrice, tokenPrice) { + try { + // Calculate current value based on position data + let totalValue = 0; + + // Add SOL value + if (positionData.positionData) { + const solAmount = this.calculateSolAmount(positionData.positionData); + const solValue = solAmount * solPrice; + totalValue += solValue; + } + + // Add token value + if (positionData.positionData && tokenPrice > 0) { + const tokenAmount = this.calculateTokenAmount(positionData.positionData); + const tokenValue = tokenAmount * tokenPrice; + totalValue += tokenValue; + } + return totalValue; + } catch (error) { + return 0; + } + } + + calculateSolAmount(positionData) { + try { + let solAmount = 0; + + if (!positionData.positionBinData || !positionData.positionBinData.length) { + return 0; + } + + // Determine which token is SOL by comparing token addresses + const tokenXMint = this.dlmmPool.tokenX.publicKey.toString(); + const tokenYMint = this.dlmmPool.tokenY.publicKey.toString(); + const SOL_MINT = 'So11111111111111111111111111111111111111112'; + + const isTokenXSOL = tokenXMint === SOL_MINT; + const isTokenYSOL = tokenYMint === SOL_MINT; + + for (const bin of positionData.positionBinData) { + if (bin.positionXAmount > 0 && isTokenXSOL) { + // TokenX is SOL, add X amounts + const binSOLX = parseFloat(bin.positionXAmount) / Math.pow(10, this.dlmmPool.tokenX.decimal || 9); + solAmount += binSOLX; + } + + if (bin.positionYAmount > 0 && isTokenYSOL) { + // TokenY is SOL, add Y amounts + const binSOLY = parseFloat(bin.positionYAmount) / Math.pow(10, this.dlmmPool.tokenY.decimal || 9); + solAmount += binSOLY; + } + } + return solAmount; + } catch (error) { + return 0; + } + } + + calculateTokenAmount(positionData) { + try { + let tokenAmount = 0; + + if (!positionData.positionBinData || !positionData.positionBinData.length) { + return 0; + } + + // Determine which token is NOT SOL by comparing token addresses + const tokenXMint = this.dlmmPool.tokenX.publicKey.toString(); + const tokenYMint = this.dlmmPool.tokenY.publicKey.toString(); + const SOL_MINT = 'So11111111111111111111111111111111111111112'; + + const isTokenXSOL = tokenXMint === SOL_MINT; + const isTokenYSOL = tokenYMint === SOL_MINT; + + for (const bin of positionData.positionBinData) { + if (bin.positionXAmount > 0 && !isTokenXSOL) { + // TokenX is NOT SOL (our alt token), add X amounts + tokenAmount += parseFloat(bin.positionXAmount) / Math.pow(10, this.dlmmPool.tokenX.decimal || 6); + } + + if (bin.positionYAmount > 0 && !isTokenYSOL) { + // TokenY is NOT SOL (our alt token), add Y amounts + tokenAmount += parseFloat(bin.positionYAmount) / Math.pow(10, this.dlmmPool.tokenY.decimal || 6); + } + } + + return tokenAmount; + } catch (error) { + return 0; + } + } + + calculateFeesEarned(positionData) { + try { + if (!positionData.positionData) return 0; + + const feeX = new BN(positionData.positionData.feeX || 0); + const feeY = new BN(positionData.positionData.feeY || 0); + + // Convert to SOL equivalent (simplified) + const feeXSol = feeX.toNumber() / Math.pow(10, this.dlmmPool.tokenX.decimal || 9); + const feeYSol = feeY.toNumber() / Math.pow(10, this.dlmmPool.tokenY.decimal || 6); + + return feeXSol + feeYSol; + } catch (error) { + return 0; + } + } + + async checkRebalancing(positionData) { + try { + // Check if position is out of range + const activeBin = await this.dlmmPool.getActiveBin(); + const isInRange = this.isPositionInRange(positionData, activeBin); + + if (!isInRange) { + await this.rebalancePosition(); + } + } catch (error) { + } + } + + isPositionInRange(positionData, activeBin) { + try { + if (!positionData.positionData || !activeBin) return true; + + const lowerBinId = positionData.positionData.lowerBinId; + const upperBinId = positionData.positionData.upperBinId; + const currentBinId = activeBin.binId; + + return currentBinId >= lowerBinId && currentBinId <= upperBinId; + } catch (error) { + return true; + } + } + + async rebalancePosition() { + try { + + // Use existing rebalancing logic from main.js + const { recenterPosition } = await import('./lib/dlmm.js'); + + const result = await recenterPosition( + this.connection, + this.dlmmPool, + this.userKeypair, + this.position.positionPubKey, + this.config + ); + + if (result.success) { + this.metrics.rebalanceCount++; + this.metrics.lastRebalance = new Date(); + } + } catch (error) { + } + } + + getMetrics() { + return { ...this.metrics }; + } + + async stop() { + try { + this.status = 'stopping'; + + // Stop monitoring + if (this.monitorInterval) { + clearInterval(this.monitorInterval); + this.monitorInterval = null; + } + + // Close position if needed + if (this.position && this.dlmmPool) { + await this.closePosition(); + } + + this.status = 'stopped'; + + } catch (error) { + this.status = 'error'; + } + } + + async closePosition() { + try { + + // Get the specific position for this pool + const { userPositions } = await this.dlmmPool.getPositionsByUserAndLbPair(this.userKeypair.publicKey); + + if (userPositions.length === 0) { + return; + } + + // Close each position in this specific pool + for (const position of userPositions) { + try { + + // Use DLMM SDK to remove liquidity + const removeTxs = await this.dlmmPool.removeLiquidity({ + position: position.publicKey, + user: this.userKeypair.publicKey, + fromBinId: position.positionData.lowerBinId, + toBinId: position.positionData.upperBinId, + bps: new BN(10_000), // 100% removal + shouldClaimAndClose: true, + }); + + // Process each transaction + for (let i = 0; i < removeTxs.length; i++) { + const tx = removeTxs[i]; + const signature = await this.connection.sendTransaction(tx, [this.userKeypair]); + await this.connection.confirmTransaction(signature, 'confirmed'); + } + + + } catch (posError) { + } + } + + // Convert any remaining tokens to SOL + await this.convertTokensToSOL(); + + } catch (error) { + } + } + + // Convert remaining tokens to SOL using the same approach as main.js + async convertTokensToSOL() { + try { + // Wait for Jupiter balance index to update after position closure + await new Promise(resolve => setTimeout(resolve, 1500)); + + // Use the same approach as swapPositionTokensToSol in main.js + const { safeGetBalance, getMintDecimals } = await import('./lib/solana.js'); + const { swapTokensUltra } = await import('./lib/jupiter.js'); + const { getPrice } = await import('./lib/price.js'); + + // Get the token mints from this specific pool + const tokenXMint = this.dlmmPool.tokenX.publicKey.toString(); + const tokenYMint = this.dlmmPool.tokenY.publicKey.toString(); + const SOL_MINT = 'So11111111111111111111111111111111111111112'; + + // Determine which token is SOL and which is the alt token + const solMint = [tokenXMint, tokenYMint].find(mint => mint === SOL_MINT); + const altTokenMint = [tokenXMint, tokenYMint].find(mint => mint !== SOL_MINT); + + if (!altTokenMint) { + return; + } + + + try { + // Get current token balance using safeGetBalance + const { PublicKey } = await import('@solana/web3.js'); + const altTokenBalanceRaw = await safeGetBalance(this.connection, new PublicKey(altTokenMint), this.userKeypair.publicKey); + + // Check if we have any tokens to swap + if (altTokenBalanceRaw.isZero() || altTokenBalanceRaw.lte(new BN(1000))) { + return; + } + + // Get token decimals for UI display + const decimals = await getMintDecimals(this.connection, new PublicKey(altTokenMint)); + const uiAmount = parseFloat(altTokenBalanceRaw.toString()) / Math.pow(10, decimals); + + // Check if amount is worth swapping (avoid dust) + const tokenPrice = await getPrice(altTokenMint); + const tokenValueUsd = uiAmount * tokenPrice; + + if (tokenValueUsd < 0.01) { + return; + } + + // Prepare swap parameters + const swapAmount = BigInt(altTokenBalanceRaw.toString()); + const SLIPPAGE_BPS = 100; // 1% + const PRICE_IMPACT_PCT = 0.5; // 0.5% + const signature = await swapTokensUltra( + altTokenMint, + SOL_MINT, + swapAmount, + this.userKeypair, + this.connection, + this.dlmmPool, + SLIPPAGE_BPS, + 20, + PRICE_IMPACT_PCT + ); + + if (!signature) { + // Swap failed + } + + } catch (swapError) { + } + + // Unwrap any remaining WSOL + try { + const { unwrapWSOL } = await import('./lib/solana.js'); + await unwrapWSOL(this.connection, this.userKeypair); + } catch (unwrapError) { + } + + } catch (error) { + } + } + +} + +// Launch pool bot +async function launchPoolBot(config) { + try { + const bot = new PoolBot(config); + const result = await bot.start(); + + return { + success: result.success, + bot: result.success ? bot : null, + positionAddress: result.positionAddress, + error: result.error + }; + } catch (error) { + return { + success: false, + error: error.message + }; + } +} + +// Stop pool bot +async function stopPoolBot(bot) { + try { + await bot.stop(); + return { success: true }; + } catch (error) { + return { + success: false, + error: error.message + }; + } +} + +export { + launchPoolBot, + stopPoolBot, + PoolBot +}; diff --git a/lib/price.js b/lib/price.js index 5ca3469..04fbc22 100644 --- a/lib/price.js +++ b/lib/price.js @@ -6,26 +6,41 @@ import { URL } from 'url'; async function getPrice(mint) { try { - const url = new URL("https://lite-api.jup.ag/price/v2"); - url.searchParams.set("ids", mint); + // Ultra API configuration + const config = { + baseUrl: process.env.JUPITER_API_BASE_URL || 'https://api.jup.ag/ultra', + apiKey: process.env.JUPITER_API_KEY || null + }; + + // Remove trailing /ultra if present + config.baseUrl = config.baseUrl.replace(/\/ultra\/?$/, ''); + + const headers = { 'Content-Type': 'application/json' }; + if (config.apiKey) { + headers['x-api-key'] = config.apiKey; + } - const res = await fetch(url.toString()); + // Ultra API endpoint + const url = `${config.baseUrl}/ultra/v1/search?query=${mint}`; + const res = await fetch(url, { headers }); + if (!res.ok) { console.error(`[getPrice] HTTP ${res.status} for mint ${mint}`); return null; } - const json = await res.json(); - - const entry = json?.data?.[mint]; - if (!entry || entry.price == null) { + const json = await res.json(); + + // Parse Ultra API response format + const data = json && Array.isArray(json) && json.length > 0 ? json[0] : null; + if (!data || data.usdPrice == null) { console.error(`[getPrice] no price field for mint ${mint}`); return null; } - const px = typeof entry.price === "number" - ? entry.price - : parseFloat(entry.price); + const px = typeof data.usdPrice === "number" + ? data.usdPrice + : parseFloat(data.usdPrice); return Number.isFinite(px) ? px : null; } catch (err) { diff --git a/package-lock.json b/package-lock.json index dcc29af..4aa1d13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,12 +12,15 @@ "@meteora-ag/dlmm": "^1.6.1", "@solana/spl-token": "^0.4.13", "@solana/web3.js": "^1.98.2", + "axios": "^1.12.2", "bn.js": "^5.2.2", "bs58": "^5.0.0", "dotenv": "^17.2.1", + "express": "^5.1.0", "jito-js-rpc": "^0.2.2", "node-fetch": "^3.3.2", "puppeteer": "^24.9.0", + "ws": "^8.18.3", "yargs": "^18.0.0" } }, @@ -137,6 +140,294 @@ "gaussian": "^1.3.0" } }, + "node_modules/@meteora-ag/dlmm/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/@meteora-ag/dlmm/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/@meteora-ag/dlmm/node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/@meteora-ag/dlmm/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@meteora-ag/dlmm/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@noble/curves": { "version": "1.9.6", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.6.tgz", @@ -223,35 +514,12 @@ "node": ">=12" } }, - "node_modules/@puppeteer/browsers/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@puppeteer/browsers/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, - "node_modules/@puppeteer/browsers/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "node_modules/@puppeteer/browsers/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -685,13 +953,34 @@ } }, "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" }, "engines": { "node": ">= 0.6" @@ -934,27 +1223,23 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=18" } }, "node_modules/borsh": { @@ -1189,9 +1474,9 @@ } }, "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -1219,10 +1504,13 @@ } }, "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } }, "node_modules/cosmiconfig": { "version": "9.0.0", @@ -1289,12 +1577,20 @@ } }, "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decimal.js": { @@ -1580,51 +1876,68 @@ "license": "MIT" }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -1645,29 +1958,6 @@ "@types/yauzl": "^2.9.1" } }, - "node_modules/extract-zip/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/extract-zip/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "node_modules/eyes": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", @@ -1734,18 +2024,17 @@ "license": "MIT" }, "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", "license": "MIT", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { "node": ">= 0.8" @@ -1809,12 +2098,12 @@ } }, "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/function-bind": { @@ -1928,32 +2217,9 @@ "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", "license": "MIT", "engines": { - "node": ">= 14" - } - }, - "node_modules/get-uri/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">= 14" } }, - "node_modules/get-uri/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -2021,6 +2287,15 @@ "node": ">= 0.8" } }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -2034,29 +2309,6 @@ "node": ">= 14" } }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/http-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -2070,29 +2322,6 @@ "node": ">= 14" } }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/https-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "node_modules/humanize-ms": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", @@ -2103,12 +2332,12 @@ } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" @@ -2189,6 +2418,12 @@ "node": ">=8" } }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, "node_modules/isomorphic-ws": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", @@ -2319,19 +2554,22 @@ } }, "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", + "engines": { + "node": ">=18" + }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -2385,15 +2623,15 @@ "license": "MIT" }, "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -2510,29 +2748,6 @@ "node": ">= 14" } }, - "node_modules/pac-proxy-agent/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/pac-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "node_modules/pac-resolver": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", @@ -2592,10 +2807,14 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, "node_modules/pend": { "version": "1.2.0", @@ -2650,29 +2869,6 @@ "node": ">= 14" } }, - "node_modules/proxy-agent/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -2727,36 +2923,13 @@ "node": ">=18" } }, - "node_modules/puppeteer-core/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/puppeteer-core/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -2775,18 +2948,34 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", + "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", - "iconv-lite": "0.4.24", + "iconv-lite": "0.7.0", "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/require-directory": { @@ -2807,6 +2996,22 @@ "node": ">=4" } }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/rpc-websockets": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.1.3.tgz", @@ -2884,57 +3089,61 @@ } }, "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", "license": "MIT", "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" } }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" + "node_modules/send/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } }, "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", "license": "MIT", "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" } }, "node_modules/setprototypeof": { @@ -3053,29 +3262,6 @@ "node": ">= 14" } }, - "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socks-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -3087,9 +3273,9 @@ } }, "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -3228,13 +3414,35 @@ "license": "0BSD" }, "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" }, "engines": { "node": ">= 0.6" diff --git a/package.json b/package.json index 730d013..513154b 100644 --- a/package.json +++ b/package.json @@ -21,12 +21,15 @@ "@meteora-ag/dlmm": "^1.6.1", "@solana/spl-token": "^0.4.13", "@solana/web3.js": "^1.98.2", + "axios": "^1.12.2", "bn.js": "^5.2.2", "bs58": "^5.0.0", "dotenv": "^17.2.1", + "express": "^5.1.0", "jito-js-rpc": "^0.2.2", "node-fetch": "^3.3.2", "puppeteer": "^24.9.0", + "ws": "^8.18.3", "yargs": "^18.0.0" } } diff --git a/start-integration.js b/start-integration.js new file mode 100755 index 0000000..54b1d26 --- /dev/null +++ b/start-integration.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +import { MeteorShowerWebSocketServer } from './wsServer.js'; + +// Start WebSocket server +const server = new MeteorShowerWebSocketServer(8080); +server.start(); + +// Keep process alive +process.on('SIGINT', () => { + server.stop(); + process.exit(0); +}); + +process.on('SIGTERM', () => { + server.stop(); + process.exit(0); +}); + +console.log('🚀 MeteorShower Integration Server started!'); diff --git a/start-production.js b/start-production.js new file mode 100644 index 0000000..32d32af --- /dev/null +++ b/start-production.js @@ -0,0 +1,27 @@ +#!/usr/bin/env node + +import { MeteorShowerWebSocketServer } from './wsServer.js'; + +// Configurações de produção +const PORT = process.env.PORT || 8080; +const HOST = process.env.HOST || '0.0.0.0'; // Permitir conexões externas + +console.log('🚀 Starting MeteorShower in Production Mode'); + +// Start WebSocket server +const server = new MeteorShowerWebSocketServer(PORT); +server.start(); + +// Keep process alive +process.on('SIGINT', () => { + server.stop(); + process.exit(0); +}); + +process.on('SIGTERM', () => { + server.stop(); + process.exit(0); +}); + +// Log de inicialização +console.log('✅ MeteorShower Integration Server started!'); diff --git a/wsServer.js b/wsServer.js new file mode 100644 index 0000000..684e733 --- /dev/null +++ b/wsServer.js @@ -0,0 +1,590 @@ +import WebSocket from 'ws'; +import { launchPoolBot, stopPoolBot } from './botManager.js'; +import 'dotenv/config'; + +class MeteorShowerWebSocketServer { + constructor(port = 8080) { + this.port = port; + this.wss = null; + this.bots = new Map(); // botId -> bot instance + this.clients = new Set(); // connected clients + this.authenticatedClients = new Set(); // authenticated clients + this.adminClients = new Set(); // admin authenticated clients + this.integrationSecret = process.env.INTEGRATION_SECRET; + this.adminSecret = process.env.ADMIN_SECRET || process.env.INTEGRATION_SECRET; + + if (!this.integrationSecret) { + throw new Error('INTEGRATION_SECRET environment variable is required'); + } + } + + // Authentication methods + isAuthenticated(ws) { + return this.authenticatedClients.has(ws); + } + + isAdmin(ws) { + return this.adminClients.has(ws); + } + + authenticate(ws, secret) { + if (secret === this.integrationSecret) { + this.authenticatedClients.add(ws); + return { success: true, role: 'user' }; + } else if (secret === this.adminSecret) { + this.authenticatedClients.add(ws); + this.adminClients.add(ws); + return { success: true, role: 'admin' }; + } else { + return { success: false, role: null }; + } + } + + requireAuthentication(ws) { + if (!this.isAuthenticated(ws)) { + ws.send(JSON.stringify({ + type: 'AUTHENTICATION_REQUIRED', + data: { error: 'Authentication required. Send AUTHENTICATE message with valid secret.' } + })); + return false; + } + return true; + } + + requireAdmin(ws) { + if (!this.isAdmin(ws)) { + ws.send(JSON.stringify({ + type: 'ADMIN_ACCESS_REQUIRED', + data: { error: 'Admin access required. This endpoint requires administrative privileges.' } + })); + return false; + } + return true; + } + + start() { + this.wss = new WebSocket.Server({ + port: this.port, + perMessageDeflate: false, + // Permitir conexões via proxy + verifyClient: (info) => { + // Log da conexão para debug + return true; // Aceitar todas as conexões + } + }); + + this.wss.on('connection', (ws, req) => { + this.clients.add(ws); + + // Send welcome message with authentication requirement + ws.send(JSON.stringify({ + type: 'CONNECTION_ESTABLISHED', + data: { + message: 'Connected to MeteorShower', + requiresAuth: true, + authMessage: 'Send AUTHENTICATE message with valid secret' + } + })); + + ws.on('message', async (data) => { + try { + const message = JSON.parse(data); + await this.handleMessage(ws, message); + } catch (error) { + ws.send(JSON.stringify({ + type: 'ERROR', + data: { error: error.message } + })); + } + }); + + ws.on('close', (code, reason) => { + this.clients.delete(ws); + this.authenticatedClients.delete(ws); + }); + + ws.on('error', (error) => { + this.clients.delete(ws); + this.authenticatedClients.delete(ws); + }); + }); + + // MeteorShower WebSocket server running on port + } + + async handleMessage(ws, message) { + + // Handle authentication separately (no auth required) + if (message.type === 'AUTHENTICATE') { + const { secret } = message.data || {}; + const authResult = this.authenticate(ws, secret); + if (authResult.success) { + ws.send(JSON.stringify({ + type: 'AUTHENTICATION_SUCCESS', + data: { + message: 'Authentication successful', + role: authResult.role + } + })); + } else { + ws.send(JSON.stringify({ + type: 'AUTHENTICATION_FAILED', + data: { error: 'Invalid secret' } + })); + ws.close(1008, 'Authentication failed'); + } + return; + } + + // Require authentication for all other operations + if (!this.requireAuthentication(ws)) { + return; + } + + switch (message.type) { + // User endpoints + case 'LAUNCH_POOL_BOT': + await this.handleLaunchPoolBot(ws, message.data); + break; + case 'STOP_POOL_BOT': + await this.handleStopPoolBot(ws, message.data); + break; + case 'GET_BOT_STATUS': + await this.handleGetBotStatus(ws, message.data); + break; + case 'PING': + ws.send(JSON.stringify({ type: 'PONG', data: { timestamp: Date.now() } })); + break; + + // Admin endpoints + case 'LIST_ACTIVE_BOTS': + if (!this.requireAdmin(ws)) return; + await this.handleListActiveBots(ws); + break; + case 'GET_SERVER_STATUS': + if (!this.requireAdmin(ws)) return; + await this.handleGetServerStatus(ws); + break; + case 'GET_SYSTEM_METRICS': + if (!this.requireAdmin(ws)) return; + await this.handleGetSystemMetrics(ws); + break; + case 'STOP_ALL_BOTS': + if (!this.requireAdmin(ws)) return; + await this.handleStopAllBots(ws); + break; + case 'GET_BOT_LOGS': + if (!this.requireAdmin(ws)) return; + await this.handleGetBotLogs(ws, message.data); + break; + + default: + ws.send(JSON.stringify({ + type: 'ERROR', + data: { error: 'Unknown message type' } + })); + } + } + + async handleLaunchPoolBot(ws, config) { + try { + // Validate configuration + if (!config.botId || !config.poolAddress || !config.privateKey) { + throw new Error('Invalid configuration: botId, poolAddress and privateKey are required'); + } + + // Launch bot using existing MeteorShower logic + const result = await launchPoolBot(config); + + if (result.success) { + this.bots.set(config.botId, result.bot); + + // Start monitoring metrics + this.startMetricsMonitoring(config.botId, result.bot); + + ws.send(JSON.stringify({ + type: 'POOL_BOT_LAUNCHED', + data: { + botId: config.botId, + positionAddress: result.positionAddress, + message: 'Pool bot started successfully' + } + })); + + } else { + ws.send(JSON.stringify({ + type: 'POOL_BOT_ERROR', + data: { + botId: config.botId, + error: result.error + } + })); + } + } catch (error) { + ws.send(JSON.stringify({ + type: 'POOL_BOT_ERROR', + data: { + botId: config.botId, + error: error.message + } + })); + } + } + + async handleStopPoolBot(ws, data) { + try { + const { botId } = data; + + const bot = this.bots.get(botId); + + if (bot) { + await stopPoolBot(bot); + this.bots.delete(botId); + + ws.send(JSON.stringify({ + type: 'POOL_BOT_STOPPED', + data: { + botId, + message: 'Pool bot stopped successfully' + } + })); + + } else { + ws.send(JSON.stringify({ + type: 'POOL_BOT_ERROR', + data: { + botId, + error: 'Bot not found' + } + })); + } + } catch (error) { + ws.send(JSON.stringify({ + type: 'POOL_BOT_ERROR', + data: { + botId: data.botId, + error: error.message + } + })); + } + } + + async handleGetBotStatus(ws, data) { + try { + const { botId } = data; + const bot = this.bots.get(botId); + + if (bot) { + ws.send(JSON.stringify({ + type: 'BOT_STATUS', + data: { + botId, + status: bot.status, + metrics: bot.getMetrics ? bot.getMetrics() : null + } + })); + } else { + ws.send(JSON.stringify({ + type: 'BOT_STATUS', + data: { + botId, + status: 'not_found' + } + })); + } + } catch (error) { + ws.send(JSON.stringify({ + type: 'ERROR', + data: { error: error.message } + })); + } + } + + async handleListActiveBots(ws) { + try { + const activeBots = Array.from(this.bots.values()).map(bot => ({ + botId: bot.botId || 'unknown', + poolAddress: bot.poolAddress || 'unknown', + status: bot.status || 'unknown', + walletAddress: bot.walletAddress || 'unknown', + createdAt: bot.createdAt || new Date(), + // Adicionar informações de tokens se disponíveis + tokenXSymbol: bot.tokenXSymbol || null, + tokenYSymbol: bot.tokenYSymbol || null, + tokenPair: bot.tokenPair || null + })); + + ws.send(JSON.stringify({ + type: 'ACTIVE_BOTS_LIST', + data: { + bots: activeBots, + count: activeBots.length, + timestamp: Date.now() + } + })); + } catch (error) { + ws.send(JSON.stringify({ + type: 'ERROR', + data: { error: error.message } + })); + } + } + + async handleGetServerStatus(ws) { + try { + const status = { + port: this.port, + connectedClients: this.clients.size, + authenticatedClients: this.authenticatedClients.size, + adminClients: this.adminClients.size, + activeBots: this.bots.size, + uptime: process.uptime(), + memoryUsage: process.memoryUsage(), + cpuUsage: process.cpuUsage(), + version: process.version, + platform: process.platform, + arch: process.arch, + nodeEnv: process.env.NODE_ENV || 'development', + timestamp: Date.now() + }; + + ws.send(JSON.stringify({ + type: 'SERVER_STATUS', + data: status + })); + } catch (error) { + ws.send(JSON.stringify({ + type: 'ERROR', + data: { error: error.message } + })); + } + } + + async handleGetSystemMetrics(ws) { + try { + const os = await import('os'); + + const metrics = { + system: { + uptime: os.uptime(), + loadAverage: os.loadavg(), + totalMemory: os.totalmem(), + freeMemory: os.freemem(), + cpuCount: os.cpus().length, + cpuInfo: os.cpus().map(cpu => ({ + model: cpu.model, + speed: cpu.speed, + times: cpu.times + })) + }, + process: { + pid: process.pid, + uptime: process.uptime(), + memoryUsage: process.memoryUsage(), + cpuUsage: process.cpuUsage(), + version: process.version, + platform: process.platform, + arch: process.arch + }, + meteorShower: { + activeBots: this.bots.size, + connectedClients: this.clients.size, + authenticatedClients: this.authenticatedClients.size, + adminClients: this.adminClients.size + }, + timestamp: Date.now() + }; + + ws.send(JSON.stringify({ + type: 'SYSTEM_METRICS', + data: metrics + })); + } catch (error) { + ws.send(JSON.stringify({ + type: 'ERROR', + data: { error: error.message } + })); + } + } + + async handleStopAllBots(ws) { + try { + const stoppedBots = []; + + for (const [botId, bot] of this.bots.entries()) { + try { + await stopPoolBot(bot); + stoppedBots.push(botId); + } catch (error) { + // Silent error handling + } + } + + this.bots.clear(); + + ws.send(JSON.stringify({ + type: 'ALL_BOTS_STOPPED', + data: { + stoppedCount: stoppedBots.length, + stoppedBots: stoppedBots, + message: `Successfully stopped ${stoppedBots.length} bots`, + timestamp: Date.now() + } + })); + } catch (error) { + ws.send(JSON.stringify({ + type: 'ERROR', + data: { error: error.message } + })); + } + } + + async handleGetBotLogs(ws, data) { + try { + const { botId, lines = 50 } = data || {}; + + if (!botId) { + ws.send(JSON.stringify({ + type: 'ERROR', + data: { error: 'Bot ID is required' } + })); + return; + } + + const bot = this.bots.get(botId); + if (!bot) { + ws.send(JSON.stringify({ + type: 'ERROR', + data: { error: 'Bot not found' } + })); + return; + } + + // Simular logs do bot (em uma implementação real, você teria um sistema de logging) + const logs = [ + { timestamp: new Date().toISOString(), level: 'INFO', message: `Bot ${botId} is running` }, + { timestamp: new Date().toISOString(), level: 'DEBUG', message: 'Monitoring position metrics' }, + { timestamp: new Date().toISOString(), level: 'INFO', message: 'Position is active and profitable' } + ]; + + ws.send(JSON.stringify({ + type: 'BOT_LOGS', + data: { + botId, + logs: logs.slice(-lines), + totalLines: logs.length, + requestedLines: lines, + timestamp: Date.now() + } + })); + } catch (error) { + ws.send(JSON.stringify({ + type: 'ERROR', + data: { error: error.message } + })); + } + } + + // Start monitoring metrics for a bot + startMetricsMonitoring(botId, bot) { + const interval = setInterval(async () => { + try { + if (!this.bots.has(botId)) { + clearInterval(interval); + return; + } + + // Get current metrics from bot + let metrics; + if (bot.getMetrics) { + metrics = bot.getMetrics(); + } else { + metrics = { + currentValue: 0, + pnl: 0, + pnlPercentage: 0, + feesEarned: 0, + rebalanceCount: 0, + lastRebalance: null + }; + } + + // Send metrics to all connected clients + this.broadcast({ + type: 'POOL_METRICS_UPDATE', + data: { + botId, + metrics, + timestamp: Date.now() + } + }); + + } catch (error) { + // Silent error handling + } + }, 5000); // Update every 5 seconds + + // Store interval for cleanup + bot.metricsInterval = interval; + } + + // Broadcast message to all connected clients + broadcast(message) { + const data = JSON.stringify(message); + this.clients.forEach(client => { + if (client.readyState === WebSocket.OPEN) { + try { + client.send(data); + } catch (error) { + this.clients.delete(client); + } + } + }); + } + + // Get server status + getStatus() { + return { + port: this.port, + connectedClients: this.clients.size, + authenticatedClients: this.authenticatedClients.size, + adminClients: this.adminClients.size, + activeBots: this.bots.size, + uptime: process.uptime(), + memoryUsage: process.memoryUsage(), + timestamp: Date.now() + }; + } + + // Stop server + stop() { + if (this.wss) { + this.wss.close(); + } + + // Stop all bots + this.bots.forEach(bot => { + if (bot.stop) { + bot.stop(); + } + }); + + this.bots.clear(); + this.clients.clear(); + + } +} + +// Start server if this file is run directly +if (import.meta.url === `file://${process.argv[1]}`) { + const server = new MeteorShowerWebSocketServer(); + server.start(); + + // Graceful shutdown + process.on('SIGINT', () => { + server.stop(); + process.exit(0); + }); +} + +export { MeteorShowerWebSocketServer };