├── .env.example ├── .gitignore ├── README.md ├── index.js ├── package-lock.json ├── package.json ├── services └── ws.js └── websocket.js /.env.example: -------------------------------------------------------------------------------- 1 | # Bot Configuration 2 | AMOUNT=0.001 3 | DELAY=1000 4 | MONITOR_INTERVAL=1000 5 | SLIPPAGE=25 6 | PRIORITY_FEE=0.00005 7 | JITO=false 8 | RPC_URL="https://rpc-mainnet.solanatracker/?api_key=xxxx" # Your RPC URL or get one here. https://www.solanatracker.io/solana-rpc 9 | WS_URL="wss://websocket-example.com" # Websocket URL from Solana Tracker: https://docs.solanatracker.io/public-data-api/websocket 10 | 11 | # Token Filtering 12 | MIN_LIQUIDITY=1000 13 | MAX_LIQUIDITY=1000000 14 | MIN_MARKET_CAP=2000 15 | MAX_MARKET_CAP=10000000 16 | MIN_RISK_SCORE=0 17 | MAX_RISK_SCORE=8 18 | REQUIRE_SOCIAL_DATA=false 19 | 20 | # PnL Thresholds 21 | MAX_NEGATIVE_PNL=-50 22 | MAX_POSITIVE_PNL=5 23 | 24 | # Markets 25 | MARKETS=raydium,orca,pumpfun,moonshot,raydium-cpmm 26 | 27 | # Wallet 28 | PRIVATE_KEY=YOUR_PRIVATE_KEY 29 | 30 | # API Key from Solana Tarcker 31 | API_KEY=507c5ec3-2d75-404b-b3cf-xxxxxx #Your API Key from Solana Tracker (https://www.solanatracker.io/data-api) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules 3 | trading-bot.log 4 | positions.json 5 | sold_positions.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Solana Trading Bot 2 | 3 | A high-performance, automated trading bot for Solana tokens using the Solana Tracker API. 4 | Supports Raydium (V4/CPMM), Pumpfun, Moonshot, Orca and Jupiter. 5 | 6 | Includes two examples, one using HTTP requests and one using the more efficient and faster Data Streams (Websockets) from Solana Tracker. 7 | 8 | ![Screenshot of the Trading Bot](https://i.gyazo.com/afb12f6c358385f133fa4b95dba3c095.png) 9 | 10 | ## Features 11 | 12 | - Automated buying and selling of Solana tokens 13 | - Multi-token support 14 | - Configurable trading parameters (liquidity, market cap, risk score) 15 | - Real-time position monitoring and management 16 | - Parallel execution of buying and selling operations 17 | - Detailed logging with timestamps and color-coded actions 18 | - Persistent storage of positions and transaction history 19 | 20 | ## Prerequisites 21 | 22 | - Node.js (v14 or later recommended) 23 | - npm (comes with Node.js) 24 | - A Solana wallet with SOL 25 | - API Key (Billing Token) from [Solana Tracker Data API](https://docs.solanatracker.io) 26 | 27 | ## Installation 28 | 29 | 1. Clone the repository: 30 | ```bash 31 | git clone https://github.com/YZYLAB/solana-trading-bot.git 32 | cd solana-trading-bot 33 | ``` 34 | 35 | 2. Install dependencies: 36 | ```bash 37 | npm install 38 | ``` 39 | 40 | 3. Rename the .env.example and configure the bot. 41 | 42 | ## Usage 43 | 44 | Run the bot with: 45 | 46 | ```bash 47 | node index.js 48 | ``` 49 | 50 | Or 51 | 52 | ```bash 53 | node websocket.js 54 | ``` 55 | 56 | ## Configuration 57 | 58 | Adjust the settings in your `.env` file to customize the bot's behavior: 59 | 60 | - AMOUNT: The amount of SOL to swap in each transaction 61 | - DELAY: Delay between buying cycles (in milliseconds) 62 | - MONITOR_INTERVAL: Interval for monitoring positions (in milliseconds) 63 | - SLIPPAGE: Maximum allowed slippage (in percentage) 64 | - PRIORITY_FEE: Priority fee for transactions 65 | - JITO: Set to "true" to use Jito for transaction processing 66 | - RPC_URL: Your Solana RPC URL 67 | - API_KEY: Your Solana Tracker - [Data API Key](https://www.solanatracker.io/data-api) 68 | - PRIVATE_KEY: Your wallet's private key 69 | - MIN_LIQUIDITY / MAX_LIQUIDITY: Liquidity range for token selection 70 | - MIN_MARKET_CAP / MAX_MARKET_CAP: Market cap range for token selection 71 | - MIN_RISK_SCORE / MAX_RISK_SCORE: Risk score range for token selection 72 | - REQUIRE_SOCIAL_DATA: Set to "true" to only trade tokens with social data 73 | - MAX_NEGATIVE_PNL / MAX_POSITIVE_PNL: PnL thresholds for selling positions 74 | - MARKETS: Comma-separated list of markets to trade on 75 | 76 | ## API Usage and Fees 77 | 78 | This bot uses the Solana Tracker API. Please refer to [Solana Tracker's documentation](https://docs.solanatracker.io) for information about API usage and associated fees. 79 | 80 | ## Disclaimer 81 | 82 | This bot is for educational purposes only. Use at your own risk. Always understand the code you're running and the potential financial implications of automated trading. 83 | 84 | The goal of this project is to show the potential ways of using the Solana Tracker API. 85 | 86 | ## License 87 | 88 | [MIT License](LICENSE) 89 | 90 | ## Contributing 91 | 92 | Contributions, issues, and feature requests are welcome! Feel free to check the [issues page](https://github.com/YZYLAB/solana-trading-bot/issues). 93 | 94 | ## Support 95 | 96 | If you find this project helpful, please consider giving it a ⭐️ on GitHub! -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const { SolanaTracker } = require("solana-swap"); 3 | const { Keypair, PublicKey, Connection } = require("@solana/web3.js"); 4 | const bs58 = require("bs58"); 5 | const winston = require("winston"); 6 | const chalk = require("chalk"); 7 | const axios = require("axios"); 8 | const fs = require("fs").promises; 9 | 10 | const session = axios.create({ 11 | baseURL: "https://data.solanatracker.io/", 12 | timeout: 10000, 13 | headers: { "x-api-key": process.env.API_KEY }, 14 | }); 15 | 16 | const sleep = (ms) => { 17 | return new Promise((resolve) => setTimeout(resolve, ms)); 18 | }; 19 | 20 | const logger = winston.createLogger({ 21 | level: "info", 22 | format: winston.format.combine( 23 | winston.format.timestamp({ 24 | format: "YYYY-MM-DD HH:mm:ss", 25 | }), 26 | winston.format.printf( 27 | (info) => `${info.timestamp} ${info.level}: ${info.message}` 28 | ) 29 | ), 30 | transports: [ 31 | new winston.transports.Console(), 32 | new winston.transports.File({ filename: "trading-bot.log" }), 33 | ], 34 | }); 35 | 36 | class TradingBot { 37 | constructor() { 38 | this.config = { 39 | amount: parseFloat(process.env.AMOUNT), 40 | delay: parseInt(process.env.DELAY), 41 | monitorInterval: parseInt(process.env.MONITOR_INTERVAL), 42 | slippage: parseInt(process.env.SLIPPAGE), 43 | priorityFee: parseFloat(process.env.PRIORITY_FEE), 44 | useJito: process.env.JITO === "true", 45 | rpcUrl: process.env.RPC_URL, 46 | minLiquidity: parseFloat(process.env.MIN_LIQUIDITY) || 0, 47 | maxLiquidity: parseFloat(process.env.MAX_LIQUIDITY) || Infinity, 48 | minMarketCap: parseFloat(process.env.MIN_MARKET_CAP) || 0, 49 | maxMarketCap: parseFloat(process.env.MAX_MARKET_CAP) || Infinity, 50 | minRiskScore: parseInt(process.env.MIN_RISK_SCORE) || 0, 51 | maxRiskScore: parseInt(process.env.MAX_RISK_SCORE) || 10, 52 | requireSocialData: process.env.REQUIRE_SOCIAL_DATA === "true", 53 | maxNegativePnL: parseFloat(process.env.MAX_NEGATIVE_PNL) || -Infinity, 54 | maxPositivePnL: parseFloat(process.env.MAX_POSITIVE_PNL) || Infinity, 55 | markets: process.env.MARKETS?.split(",").map((m) => m.trim()) || ['raydium', 'orca', 'pumpfun', 'moonshot', 'raydium-cpmm'], 56 | }; 57 | 58 | this.privateKey = process.env.PRIVATE_KEY; 59 | this.SOL_ADDRESS = "So11111111111111111111111111111111111111112"; 60 | this.positions = new Map(); 61 | this.positionsFile = "positions.json"; 62 | this.soldPositionsFile = "sold_positions.json"; 63 | this.soldPositions = []; 64 | this.seenTokens = new Set(); 65 | this.buyingTokens = new Set(); 66 | this.sellingPositions = new Set(); 67 | 68 | this.connection = new Connection(this.config.rpcUrl); 69 | } 70 | 71 | async initialize() { 72 | this.keypair = Keypair.fromSecretKey(bs58.decode ? bs58.decode (this.privateKey): bs58.default.decode(this.privateKey)); 73 | this.solanaTracker = new SolanaTracker(this.keypair, this.config.rpcUrl); 74 | await this.loadPositions(); 75 | await this.loadSoldPositions(); 76 | } 77 | 78 | async fetchTokens() { 79 | try { 80 | const response = await session.get("/tokens/latest"); 81 | return response.data; 82 | } catch (error) { 83 | logger.error(`Error fetching token data [${error?.response?.data || error}]`); 84 | return []; 85 | } 86 | } 87 | 88 | async fetchTokenData(tokenId) { 89 | try { 90 | const response = await session.get(`/tokens/${tokenId}`); 91 | return response.data; 92 | } catch (error) { 93 | logger.error(`Error fetching token data [${error?.response?.data || error}]`); 94 | return null 95 | } 96 | } 97 | 98 | filterTokens(tokens) { 99 | return tokens.filter((token) => { 100 | const pool = token.pools[0]; 101 | const liquidity = pool.liquidity.usd; 102 | const marketCap = pool.marketCap.usd; 103 | const riskScore = token.risk.score; 104 | const hasSocialData = !!( 105 | token.token.twitter || 106 | token.token.telegram || 107 | token.token.website 108 | ); 109 | const isInAllowedMarket = this.config.markets.includes(pool.market); 110 | 111 | return ( 112 | liquidity >= this.config.minLiquidity && 113 | liquidity <= this.config.maxLiquidity && 114 | marketCap >= this.config.minMarketCap && 115 | marketCap <= this.config.maxMarketCap && 116 | riskScore >= this.config.minRiskScore && 117 | riskScore <= this.config.maxRiskScore && 118 | (!this.config.requireSocialData || hasSocialData) && 119 | isInAllowedMarket && 120 | !this.seenTokens.has(token.token.mint) && 121 | !this.buyingTokens.has(token.token.mint) 122 | ); 123 | }); 124 | } 125 | 126 | async getWalletAmount(wallet, mint, retries = 3) { 127 | await sleep(5000); 128 | for (let attempt = 0; attempt <= retries; attempt++) { 129 | try { 130 | const tokenAccountInfo = 131 | await this.connection.getParsedTokenAccountsByOwner( 132 | new PublicKey(wallet), 133 | { 134 | mint: new PublicKey(mint), 135 | } 136 | ); 137 | 138 | if (tokenAccountInfo.value) { 139 | const balance = 140 | tokenAccountInfo.value[0].account.data.parsed.info.tokenAmount 141 | .uiAmount; 142 | 143 | if (balance > 0) { 144 | return balance; 145 | } 146 | } 147 | 148 | if (attempt < retries) { 149 | await sleep(10000); 150 | } 151 | } catch (error) { 152 | if (attempt < retries) { 153 | await sleep(10000); 154 | } else { 155 | logger.error( 156 | `All attempts failed. Error getting wallet amount for token ${mint}:`, 157 | error 158 | ); 159 | } 160 | } 161 | } 162 | 163 | logger.warn( 164 | `Failed to get wallet amount for token ${mint} after ${retries} retries.` 165 | ); 166 | return null; 167 | } 168 | 169 | async performSwap(token, isBuy) { 170 | logger.info( 171 | `${ 172 | isBuy ? chalk.white("[BUYING]") : chalk.white("[SELLING]") 173 | } [${this.keypair.publicKey.toBase58()}] [${token.token.symbol}] [${ 174 | token.token.mint 175 | }]` 176 | ); 177 | const { amount, slippage, priorityFee } = this.config; 178 | const [fromToken, toToken] = isBuy 179 | ? [this.SOL_ADDRESS, token.token.mint] 180 | : [token.token.mint, this.SOL_ADDRESS]; 181 | 182 | try { 183 | let swapAmount; 184 | if (isBuy) { 185 | swapAmount = amount; 186 | } else { 187 | const position = this.positions.get(token.token.mint); 188 | if (!position) { 189 | logger.error( 190 | `No position found for ${token.token.symbol} when trying to sell` 191 | ); 192 | return false; 193 | } 194 | swapAmount = position.amount; 195 | } 196 | 197 | const swapResponse = await this.solanaTracker.getSwapInstructions( 198 | fromToken, 199 | toToken, 200 | swapAmount, 201 | slippage, 202 | this.keypair.publicKey.toBase58(), 203 | priorityFee 204 | ); 205 | 206 | const swapOptions = this.buildSwapOptions(); 207 | const txid = await this.solanaTracker.performSwap( 208 | swapResponse, 209 | swapOptions 210 | ); 211 | this.logTransaction(txid, isBuy, token); 212 | 213 | if (isBuy) { 214 | const tokenAmount = await this.getWalletAmount( 215 | this.keypair.publicKey.toBase58(), 216 | token.token.mint 217 | ); 218 | if (!tokenAmount) { 219 | logger.error( 220 | `Swap failed ${token.token.mint}` 221 | ); 222 | return false; 223 | } 224 | this.positions.set(token.token.mint, { 225 | txid, 226 | symbol: token.token.symbol, 227 | entryPrice: token.pools[0].price.quote, 228 | amount: tokenAmount, 229 | openTime: Date.now(), 230 | }); 231 | this.seenTokens.add(token.token.mint); 232 | this.buyingTokens.delete(token.token.mint); 233 | } else { 234 | const position = this.positions.get(token.token.mint); 235 | if (position) { 236 | const exitPrice = token.pools[0].price.quote; 237 | const pnl = (exitPrice - position.entryPrice) * position.amount; 238 | const pnlPercentage = 239 | (pnl / (position.entryPrice * position.amount)) * 100; 240 | 241 | const soldPosition = { 242 | ...position, 243 | exitPrice, 244 | pnl, 245 | pnlPercentage, 246 | closeTime: Date.now(), 247 | closeTxid: txid, 248 | }; 249 | 250 | this.soldPositions.push(soldPosition); 251 | 252 | logger.info( 253 | `Closed position for ${token.token.symbol}. PnL: (${pnlPercentage.toFixed(2)}%)` 254 | ); 255 | this.positions.delete(token.token.mint); 256 | this.sellingPositions.delete(token.token.mint); 257 | 258 | await this.saveSoldPositions(); 259 | } 260 | } 261 | 262 | await this.savePositions(); 263 | return txid; 264 | } catch (error) { 265 | logger.error( 266 | `Error performing ${isBuy ? "buy" : "sell"}: ${error.message}`, 267 | { error } 268 | ); 269 | if (isBuy) { 270 | this.buyingTokens.delete(token.token.mint); 271 | } else { 272 | this.sellingPositions.delete(token.token.mint); 273 | } 274 | return false; 275 | } 276 | } 277 | 278 | async checkAndSellPosition(tokenMint) { 279 | if (this.sellingPositions.has(tokenMint)) { 280 | // logger.info(`Already selling position for ${tokenMint}, skipping`); 281 | return; 282 | } 283 | 284 | const position = this.positions.get(tokenMint); 285 | if (!position) return; 286 | 287 | const tokenData = await this.fetchTokenData(tokenMint); 288 | if (!tokenData) { 289 | logger.error(`Failed to fetch data for token ${tokenMint}`); 290 | return; 291 | } 292 | 293 | const currentPrice = tokenData.pools[0].price.quote; 294 | const pnlPercentage = 295 | ((currentPrice - position.entryPrice) / position.entryPrice) * 100; 296 | 297 | logger.info( 298 | `PnL for position [${position.symbol}] [${chalk[ 299 | pnlPercentage > 0 ? "green" : "red" 300 | ](pnlPercentage.toFixed(2))}%]` 301 | ); 302 | 303 | if ( 304 | pnlPercentage <= this.config.maxNegativePnL || 305 | pnlPercentage >= this.config.maxPositivePnL 306 | ) { 307 | const currentAmount = await this.getWalletAmount( 308 | this.keypair.publicKey.toBase58(), 309 | tokenMint 310 | ); 311 | if (currentAmount !== null && currentAmount > 0) { 312 | this.sellingPositions.add(tokenMint); 313 | this.performSwap(tokenData, false).catch((error) => { 314 | logger.error(`Error selling position: ${error.message}`, { error }); 315 | this.sellingPositions.delete(tokenMint); 316 | }); 317 | } else { 318 | logger.warn( 319 | `No balance found for ${position.symbol}, removing from positions` 320 | ); 321 | this.positions.delete(tokenMint); 322 | await this.savePositions(); 323 | } 324 | } 325 | } 326 | 327 | async buyMonitor() { 328 | while (true) { 329 | const tokens = await this.fetchTokens(); 330 | const filteredTokens = this.filterTokens(tokens); 331 | 332 | for (const token of filteredTokens) { 333 | if (!this.positions.has(token.token.mint) && !this.buyingTokens.has(token.token.mint)) { 334 | this.buyingTokens.add(token.token.mint); 335 | this.performSwap(token, true).catch((error) => { 336 | logger.error(`Error buying token: ${error.message}`, { error }); 337 | this.buyingTokens.delete(token.token.mint); 338 | }); 339 | } 340 | } 341 | 342 | await sleep(this.config.delay); 343 | } 344 | } 345 | 346 | async positionMonitor() { 347 | while (true) { 348 | const positionPromises = Array.from(this.positions.keys()).map( 349 | (tokenMint) => this.checkAndSellPosition(tokenMint) 350 | ); 351 | await Promise.allSettled(positionPromises); 352 | await sleep(this.config.monitorInterval); 353 | } 354 | } 355 | 356 | buildSwapOptions() { 357 | return { 358 | sendOptions: { skipPreflight: true }, 359 | confirmationRetries: 30, 360 | confirmationRetryTimeout: 1000, 361 | lastValidBlockHeightBuffer: 150, 362 | resendInterval: 1000, 363 | confirmationCheckInterval: 1000, 364 | commitment: "processed", 365 | jito: this.config.useJito ? { enabled: true, tip: 0.0001 } : undefined, 366 | }; 367 | } 368 | 369 | logTransaction(txid, isBuy, token) { 370 | logger.info( 371 | `${isBuy ? chalk.green("[BOUGHT]") : chalk.red("[SOLD]")} ${ 372 | token.token.symbol 373 | } [${txid}]` 374 | ); 375 | } 376 | 377 | async loadSoldPositions() { 378 | try { 379 | const data = await fs.readFile(this.soldPositionsFile, "utf8"); 380 | this.soldPositions = JSON.parse(data); 381 | logger.info( 382 | `Loaded ${this.soldPositions.length} sold positions from file` 383 | ); 384 | } catch (error) { 385 | if (error.code !== "ENOENT") { 386 | logger.error("Error loading sold positions", { error }); 387 | } 388 | } 389 | } 390 | 391 | async saveSoldPositions() { 392 | try { 393 | await fs.writeFile( 394 | this.soldPositionsFile, 395 | JSON.stringify(this.soldPositions, null, 2) 396 | ); 397 | logger.info(`Saved ${this.soldPositions.length} sold positions to file`); 398 | } catch (error) { 399 | logger.error("Error saving sold positions", { error }); 400 | } 401 | } 402 | 403 | async loadPositions() { 404 | try { 405 | const data = await fs.readFile(this.positionsFile, "utf8"); 406 | const loadedPositions = JSON.parse(data); 407 | this.positions = new Map(Object.entries(loadedPositions)); 408 | this.seenTokens = new Set(this.positions.keys()); 409 | logger.info(`Loaded ${this.positions.size} positions from file`); 410 | } catch (error) { 411 | if (error.code !== "ENOENT") { 412 | logger.error("Error loading positions", { error }); 413 | } 414 | } 415 | } 416 | 417 | async savePositions() { 418 | try { 419 | const positionsObject = Object.fromEntries(this.positions); 420 | await fs.writeFile( 421 | this.positionsFile, 422 | JSON.stringify(positionsObject, null, 2) 423 | ); 424 | logger.info(`Saved ${this.positions.size} positions to file`); 425 | } catch (error) { 426 | logger.error("Error saving positions", { error }); 427 | } 428 | } 429 | 430 | async start() { 431 | try { 432 | logger.info("Starting Trading Bot"); 433 | await this.initialize(); 434 | 435 | // Run buying and selling loops concurrently 436 | await Promise.allSettled([this.buyMonitor(), this.positionMonitor()]); 437 | } catch (error) { 438 | console.log("Error starting bot", error); 439 | } 440 | } 441 | } 442 | 443 | const bot = new TradingBot(); 444 | bot.start().catch((error) => console.error("Error in bot execution", error)); -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solana-volume-bot", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "solana-volume-bot", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "chalk": "4.1.0", 13 | "dotenv": "^16.4.5", 14 | "solana-swap": "^1.1.2", 15 | "winston": "^3.13.1" 16 | } 17 | }, 18 | "node_modules/@babel/runtime": { 19 | "version": "7.25.0", 20 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", 21 | "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", 22 | "license": "MIT", 23 | "dependencies": { 24 | "regenerator-runtime": "^0.14.0" 25 | }, 26 | "engines": { 27 | "node": ">=6.9.0" 28 | } 29 | }, 30 | "node_modules/@colors/colors": { 31 | "version": "1.6.0", 32 | "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", 33 | "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", 34 | "license": "MIT", 35 | "engines": { 36 | "node": ">=0.1.90" 37 | } 38 | }, 39 | "node_modules/@dabh/diagnostics": { 40 | "version": "2.0.3", 41 | "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", 42 | "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", 43 | "license": "MIT", 44 | "dependencies": { 45 | "colorspace": "1.1.x", 46 | "enabled": "2.0.x", 47 | "kuler": "^2.0.0" 48 | } 49 | }, 50 | "node_modules/@noble/curves": { 51 | "version": "1.4.2", 52 | "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", 53 | "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", 54 | "license": "MIT", 55 | "dependencies": { 56 | "@noble/hashes": "1.4.0" 57 | }, 58 | "funding": { 59 | "url": "https://paulmillr.com/funding/" 60 | } 61 | }, 62 | "node_modules/@noble/hashes": { 63 | "version": "1.4.0", 64 | "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", 65 | "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", 66 | "license": "MIT", 67 | "engines": { 68 | "node": ">= 16" 69 | }, 70 | "funding": { 71 | "url": "https://paulmillr.com/funding/" 72 | } 73 | }, 74 | "node_modules/@solana/buffer-layout": { 75 | "version": "4.0.1", 76 | "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", 77 | "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", 78 | "license": "MIT", 79 | "dependencies": { 80 | "buffer": "~6.0.3" 81 | }, 82 | "engines": { 83 | "node": ">=5.10" 84 | } 85 | }, 86 | "node_modules/@solana/web3.js": { 87 | "version": "1.95.2", 88 | "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.95.2.tgz", 89 | "integrity": "sha512-SjlHp0G4qhuhkQQc+YXdGkI8EerCqwxvgytMgBpzMUQTafrkNant3e7pgilBGgjy/iM40ICvWBLgASTPMrQU7w==", 90 | "license": "MIT", 91 | "dependencies": { 92 | "@babel/runtime": "^7.24.8", 93 | "@noble/curves": "^1.4.2", 94 | "@noble/hashes": "^1.4.0", 95 | "@solana/buffer-layout": "^4.0.1", 96 | "agentkeepalive": "^4.5.0", 97 | "bigint-buffer": "^1.1.5", 98 | "bn.js": "^5.2.1", 99 | "borsh": "^0.7.0", 100 | "bs58": "^4.0.1", 101 | "buffer": "6.0.3", 102 | "fast-stable-stringify": "^1.0.0", 103 | "jayson": "^4.1.1", 104 | "node-fetch": "^2.7.0", 105 | "rpc-websockets": "^9.0.2", 106 | "superstruct": "^2.0.2" 107 | } 108 | }, 109 | "node_modules/@solana/web3.js/node_modules/base-x": { 110 | "version": "3.0.10", 111 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", 112 | "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", 113 | "license": "MIT", 114 | "dependencies": { 115 | "safe-buffer": "^5.0.1" 116 | } 117 | }, 118 | "node_modules/@solana/web3.js/node_modules/bs58": { 119 | "version": "4.0.1", 120 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 121 | "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", 122 | "license": "MIT", 123 | "dependencies": { 124 | "base-x": "^3.0.2" 125 | } 126 | }, 127 | "node_modules/@swc/helpers": { 128 | "version": "0.5.12", 129 | "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.12.tgz", 130 | "integrity": "sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g==", 131 | "license": "Apache-2.0", 132 | "dependencies": { 133 | "tslib": "^2.4.0" 134 | } 135 | }, 136 | "node_modules/@types/connect": { 137 | "version": "3.4.38", 138 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", 139 | "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", 140 | "license": "MIT", 141 | "dependencies": { 142 | "@types/node": "*" 143 | } 144 | }, 145 | "node_modules/@types/node": { 146 | "version": "12.20.55", 147 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", 148 | "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", 149 | "license": "MIT" 150 | }, 151 | "node_modules/@types/triple-beam": { 152 | "version": "1.3.5", 153 | "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", 154 | "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", 155 | "license": "MIT" 156 | }, 157 | "node_modules/@types/uuid": { 158 | "version": "8.3.4", 159 | "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", 160 | "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", 161 | "license": "MIT" 162 | }, 163 | "node_modules/@types/ws": { 164 | "version": "7.4.7", 165 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", 166 | "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", 167 | "license": "MIT", 168 | "dependencies": { 169 | "@types/node": "*" 170 | } 171 | }, 172 | "node_modules/agentkeepalive": { 173 | "version": "4.5.0", 174 | "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", 175 | "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", 176 | "license": "MIT", 177 | "dependencies": { 178 | "humanize-ms": "^1.2.1" 179 | }, 180 | "engines": { 181 | "node": ">= 8.0.0" 182 | } 183 | }, 184 | "node_modules/ansi-styles": { 185 | "version": "4.3.0", 186 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 187 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 188 | "license": "MIT", 189 | "dependencies": { 190 | "color-convert": "^2.0.1" 191 | }, 192 | "engines": { 193 | "node": ">=8" 194 | }, 195 | "funding": { 196 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 197 | } 198 | }, 199 | "node_modules/ansi-styles/node_modules/color-convert": { 200 | "version": "2.0.1", 201 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 202 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 203 | "license": "MIT", 204 | "dependencies": { 205 | "color-name": "~1.1.4" 206 | }, 207 | "engines": { 208 | "node": ">=7.0.0" 209 | } 210 | }, 211 | "node_modules/ansi-styles/node_modules/color-name": { 212 | "version": "1.1.4", 213 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 214 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 215 | "license": "MIT" 216 | }, 217 | "node_modules/async": { 218 | "version": "3.2.5", 219 | "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", 220 | "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", 221 | "license": "MIT" 222 | }, 223 | "node_modules/asynckit": { 224 | "version": "0.4.0", 225 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 226 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 227 | "license": "MIT" 228 | }, 229 | "node_modules/axios": { 230 | "version": "1.7.2", 231 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", 232 | "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", 233 | "license": "MIT", 234 | "dependencies": { 235 | "follow-redirects": "^1.15.6", 236 | "form-data": "^4.0.0", 237 | "proxy-from-env": "^1.1.0" 238 | } 239 | }, 240 | "node_modules/base-x": { 241 | "version": "4.0.0", 242 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", 243 | "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==", 244 | "license": "MIT" 245 | }, 246 | "node_modules/base64-js": { 247 | "version": "1.5.1", 248 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 249 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 250 | "funding": [ 251 | { 252 | "type": "github", 253 | "url": "https://github.com/sponsors/feross" 254 | }, 255 | { 256 | "type": "patreon", 257 | "url": "https://www.patreon.com/feross" 258 | }, 259 | { 260 | "type": "consulting", 261 | "url": "https://feross.org/support" 262 | } 263 | ], 264 | "license": "MIT" 265 | }, 266 | "node_modules/bigint-buffer": { 267 | "version": "1.1.5", 268 | "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", 269 | "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", 270 | "hasInstallScript": true, 271 | "license": "Apache-2.0", 272 | "dependencies": { 273 | "bindings": "^1.3.0" 274 | }, 275 | "engines": { 276 | "node": ">= 10.0.0" 277 | } 278 | }, 279 | "node_modules/bindings": { 280 | "version": "1.5.0", 281 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 282 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 283 | "license": "MIT", 284 | "dependencies": { 285 | "file-uri-to-path": "1.0.0" 286 | } 287 | }, 288 | "node_modules/bn.js": { 289 | "version": "5.2.1", 290 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", 291 | "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", 292 | "license": "MIT" 293 | }, 294 | "node_modules/borsh": { 295 | "version": "0.7.0", 296 | "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", 297 | "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", 298 | "license": "Apache-2.0", 299 | "dependencies": { 300 | "bn.js": "^5.2.0", 301 | "bs58": "^4.0.0", 302 | "text-encoding-utf-8": "^1.0.2" 303 | } 304 | }, 305 | "node_modules/borsh/node_modules/base-x": { 306 | "version": "3.0.10", 307 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", 308 | "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", 309 | "license": "MIT", 310 | "dependencies": { 311 | "safe-buffer": "^5.0.1" 312 | } 313 | }, 314 | "node_modules/borsh/node_modules/bs58": { 315 | "version": "4.0.1", 316 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 317 | "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", 318 | "license": "MIT", 319 | "dependencies": { 320 | "base-x": "^3.0.2" 321 | } 322 | }, 323 | "node_modules/bs58": { 324 | "version": "5.0.0", 325 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", 326 | "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", 327 | "license": "MIT", 328 | "dependencies": { 329 | "base-x": "^4.0.0" 330 | } 331 | }, 332 | "node_modules/buffer": { 333 | "version": "6.0.3", 334 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", 335 | "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", 336 | "funding": [ 337 | { 338 | "type": "github", 339 | "url": "https://github.com/sponsors/feross" 340 | }, 341 | { 342 | "type": "patreon", 343 | "url": "https://www.patreon.com/feross" 344 | }, 345 | { 346 | "type": "consulting", 347 | "url": "https://feross.org/support" 348 | } 349 | ], 350 | "license": "MIT", 351 | "dependencies": { 352 | "base64-js": "^1.3.1", 353 | "ieee754": "^1.2.1" 354 | } 355 | }, 356 | "node_modules/bufferutil": { 357 | "version": "4.0.8", 358 | "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", 359 | "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", 360 | "hasInstallScript": true, 361 | "license": "MIT", 362 | "optional": true, 363 | "dependencies": { 364 | "node-gyp-build": "^4.3.0" 365 | }, 366 | "engines": { 367 | "node": ">=6.14.2" 368 | } 369 | }, 370 | "node_modules/chalk": { 371 | "version": "4.1.0", 372 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", 373 | "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", 374 | "license": "MIT", 375 | "dependencies": { 376 | "ansi-styles": "^4.1.0", 377 | "supports-color": "^7.1.0" 378 | }, 379 | "engines": { 380 | "node": ">=10" 381 | }, 382 | "funding": { 383 | "url": "https://github.com/chalk/chalk?sponsor=1" 384 | } 385 | }, 386 | "node_modules/color": { 387 | "version": "3.2.1", 388 | "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", 389 | "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", 390 | "license": "MIT", 391 | "dependencies": { 392 | "color-convert": "^1.9.3", 393 | "color-string": "^1.6.0" 394 | } 395 | }, 396 | "node_modules/color-convert": { 397 | "version": "1.9.3", 398 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 399 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 400 | "license": "MIT", 401 | "dependencies": { 402 | "color-name": "1.1.3" 403 | } 404 | }, 405 | "node_modules/color-name": { 406 | "version": "1.1.3", 407 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 408 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", 409 | "license": "MIT" 410 | }, 411 | "node_modules/color-string": { 412 | "version": "1.9.1", 413 | "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", 414 | "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", 415 | "license": "MIT", 416 | "dependencies": { 417 | "color-name": "^1.0.0", 418 | "simple-swizzle": "^0.2.2" 419 | } 420 | }, 421 | "node_modules/colorspace": { 422 | "version": "1.1.4", 423 | "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", 424 | "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", 425 | "license": "MIT", 426 | "dependencies": { 427 | "color": "^3.1.3", 428 | "text-hex": "1.0.x" 429 | } 430 | }, 431 | "node_modules/combined-stream": { 432 | "version": "1.0.8", 433 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 434 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 435 | "license": "MIT", 436 | "dependencies": { 437 | "delayed-stream": "~1.0.0" 438 | }, 439 | "engines": { 440 | "node": ">= 0.8" 441 | } 442 | }, 443 | "node_modules/commander": { 444 | "version": "2.20.3", 445 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 446 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 447 | "license": "MIT" 448 | }, 449 | "node_modules/delay": { 450 | "version": "5.0.0", 451 | "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", 452 | "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", 453 | "license": "MIT", 454 | "engines": { 455 | "node": ">=10" 456 | }, 457 | "funding": { 458 | "url": "https://github.com/sponsors/sindresorhus" 459 | } 460 | }, 461 | "node_modules/delayed-stream": { 462 | "version": "1.0.0", 463 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 464 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 465 | "license": "MIT", 466 | "engines": { 467 | "node": ">=0.4.0" 468 | } 469 | }, 470 | "node_modules/dotenv": { 471 | "version": "16.4.5", 472 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", 473 | "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", 474 | "license": "BSD-2-Clause", 475 | "engines": { 476 | "node": ">=12" 477 | }, 478 | "funding": { 479 | "url": "https://dotenvx.com" 480 | } 481 | }, 482 | "node_modules/enabled": { 483 | "version": "2.0.0", 484 | "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", 485 | "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", 486 | "license": "MIT" 487 | }, 488 | "node_modules/err-code": { 489 | "version": "2.0.3", 490 | "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", 491 | "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", 492 | "license": "MIT" 493 | }, 494 | "node_modules/es6-promise": { 495 | "version": "4.2.8", 496 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", 497 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", 498 | "license": "MIT" 499 | }, 500 | "node_modules/es6-promisify": { 501 | "version": "5.0.0", 502 | "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", 503 | "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", 504 | "license": "MIT", 505 | "dependencies": { 506 | "es6-promise": "^4.0.3" 507 | } 508 | }, 509 | "node_modules/eventemitter3": { 510 | "version": "5.0.1", 511 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", 512 | "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", 513 | "license": "MIT" 514 | }, 515 | "node_modules/eyes": { 516 | "version": "0.1.8", 517 | "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", 518 | "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", 519 | "engines": { 520 | "node": "> 0.1.90" 521 | } 522 | }, 523 | "node_modules/fast-stable-stringify": { 524 | "version": "1.0.0", 525 | "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", 526 | "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", 527 | "license": "MIT" 528 | }, 529 | "node_modules/fecha": { 530 | "version": "4.2.3", 531 | "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", 532 | "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", 533 | "license": "MIT" 534 | }, 535 | "node_modules/file-uri-to-path": { 536 | "version": "1.0.0", 537 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 538 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", 539 | "license": "MIT" 540 | }, 541 | "node_modules/fn.name": { 542 | "version": "1.1.0", 543 | "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", 544 | "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", 545 | "license": "MIT" 546 | }, 547 | "node_modules/follow-redirects": { 548 | "version": "1.15.6", 549 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", 550 | "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", 551 | "funding": [ 552 | { 553 | "type": "individual", 554 | "url": "https://github.com/sponsors/RubenVerborgh" 555 | } 556 | ], 557 | "license": "MIT", 558 | "engines": { 559 | "node": ">=4.0" 560 | }, 561 | "peerDependenciesMeta": { 562 | "debug": { 563 | "optional": true 564 | } 565 | } 566 | }, 567 | "node_modules/form-data": { 568 | "version": "4.0.0", 569 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 570 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 571 | "license": "MIT", 572 | "dependencies": { 573 | "asynckit": "^0.4.0", 574 | "combined-stream": "^1.0.8", 575 | "mime-types": "^2.1.12" 576 | }, 577 | "engines": { 578 | "node": ">= 6" 579 | } 580 | }, 581 | "node_modules/has-flag": { 582 | "version": "4.0.0", 583 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 584 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 585 | "license": "MIT", 586 | "engines": { 587 | "node": ">=8" 588 | } 589 | }, 590 | "node_modules/humanize-ms": { 591 | "version": "1.2.1", 592 | "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", 593 | "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", 594 | "license": "MIT", 595 | "dependencies": { 596 | "ms": "^2.0.0" 597 | } 598 | }, 599 | "node_modules/ieee754": { 600 | "version": "1.2.1", 601 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 602 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 603 | "funding": [ 604 | { 605 | "type": "github", 606 | "url": "https://github.com/sponsors/feross" 607 | }, 608 | { 609 | "type": "patreon", 610 | "url": "https://www.patreon.com/feross" 611 | }, 612 | { 613 | "type": "consulting", 614 | "url": "https://feross.org/support" 615 | } 616 | ], 617 | "license": "BSD-3-Clause" 618 | }, 619 | "node_modules/inherits": { 620 | "version": "2.0.4", 621 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 622 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 623 | "license": "ISC" 624 | }, 625 | "node_modules/is-arrayish": { 626 | "version": "0.3.2", 627 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", 628 | "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", 629 | "license": "MIT" 630 | }, 631 | "node_modules/is-stream": { 632 | "version": "2.0.1", 633 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", 634 | "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", 635 | "license": "MIT", 636 | "engines": { 637 | "node": ">=8" 638 | }, 639 | "funding": { 640 | "url": "https://github.com/sponsors/sindresorhus" 641 | } 642 | }, 643 | "node_modules/isomorphic-ws": { 644 | "version": "4.0.1", 645 | "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", 646 | "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", 647 | "license": "MIT", 648 | "peerDependencies": { 649 | "ws": "*" 650 | } 651 | }, 652 | "node_modules/jayson": { 653 | "version": "4.1.1", 654 | "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.1.1.tgz", 655 | "integrity": "sha512-5ZWm4Q/0DHPyeMfAsrwViwUS2DMVsQgWh8bEEIVTkfb3DzHZ2L3G5WUnF+AKmGjjM9r1uAv73SaqC1/U4RL45w==", 656 | "license": "MIT", 657 | "dependencies": { 658 | "@types/connect": "^3.4.33", 659 | "@types/node": "^12.12.54", 660 | "@types/ws": "^7.4.4", 661 | "commander": "^2.20.3", 662 | "delay": "^5.0.0", 663 | "es6-promisify": "^5.0.0", 664 | "eyes": "^0.1.8", 665 | "isomorphic-ws": "^4.0.1", 666 | "json-stringify-safe": "^5.0.1", 667 | "JSONStream": "^1.3.5", 668 | "uuid": "^8.3.2", 669 | "ws": "^7.5.10" 670 | }, 671 | "bin": { 672 | "jayson": "bin/jayson.js" 673 | }, 674 | "engines": { 675 | "node": ">=8" 676 | } 677 | }, 678 | "node_modules/json-stringify-safe": { 679 | "version": "5.0.1", 680 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 681 | "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", 682 | "license": "ISC" 683 | }, 684 | "node_modules/jsonparse": { 685 | "version": "1.3.1", 686 | "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", 687 | "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", 688 | "engines": [ 689 | "node >= 0.2.0" 690 | ], 691 | "license": "MIT" 692 | }, 693 | "node_modules/JSONStream": { 694 | "version": "1.3.5", 695 | "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", 696 | "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", 697 | "license": "(MIT OR Apache-2.0)", 698 | "dependencies": { 699 | "jsonparse": "^1.2.0", 700 | "through": ">=2.2.7 <3" 701 | }, 702 | "bin": { 703 | "JSONStream": "bin.js" 704 | }, 705 | "engines": { 706 | "node": "*" 707 | } 708 | }, 709 | "node_modules/kuler": { 710 | "version": "2.0.0", 711 | "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", 712 | "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", 713 | "license": "MIT" 714 | }, 715 | "node_modules/logform": { 716 | "version": "2.6.1", 717 | "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", 718 | "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", 719 | "license": "MIT", 720 | "dependencies": { 721 | "@colors/colors": "1.6.0", 722 | "@types/triple-beam": "^1.3.2", 723 | "fecha": "^4.2.0", 724 | "ms": "^2.1.1", 725 | "safe-stable-stringify": "^2.3.1", 726 | "triple-beam": "^1.3.0" 727 | }, 728 | "engines": { 729 | "node": ">= 12.0.0" 730 | } 731 | }, 732 | "node_modules/mime-db": { 733 | "version": "1.52.0", 734 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 735 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 736 | "license": "MIT", 737 | "engines": { 738 | "node": ">= 0.6" 739 | } 740 | }, 741 | "node_modules/mime-types": { 742 | "version": "2.1.35", 743 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 744 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 745 | "license": "MIT", 746 | "dependencies": { 747 | "mime-db": "1.52.0" 748 | }, 749 | "engines": { 750 | "node": ">= 0.6" 751 | } 752 | }, 753 | "node_modules/ms": { 754 | "version": "2.1.3", 755 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 756 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 757 | "license": "MIT" 758 | }, 759 | "node_modules/node-fetch": { 760 | "version": "2.7.0", 761 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", 762 | "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", 763 | "license": "MIT", 764 | "dependencies": { 765 | "whatwg-url": "^5.0.0" 766 | }, 767 | "engines": { 768 | "node": "4.x || >=6.0.0" 769 | }, 770 | "peerDependencies": { 771 | "encoding": "^0.1.0" 772 | }, 773 | "peerDependenciesMeta": { 774 | "encoding": { 775 | "optional": true 776 | } 777 | } 778 | }, 779 | "node_modules/node-gyp-build": { 780 | "version": "4.8.1", 781 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", 782 | "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", 783 | "license": "MIT", 784 | "optional": true, 785 | "bin": { 786 | "node-gyp-build": "bin.js", 787 | "node-gyp-build-optional": "optional.js", 788 | "node-gyp-build-test": "build-test.js" 789 | } 790 | }, 791 | "node_modules/one-time": { 792 | "version": "1.0.0", 793 | "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", 794 | "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", 795 | "license": "MIT", 796 | "dependencies": { 797 | "fn.name": "1.x.x" 798 | } 799 | }, 800 | "node_modules/promise-retry": { 801 | "version": "2.0.1", 802 | "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", 803 | "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", 804 | "license": "MIT", 805 | "dependencies": { 806 | "err-code": "^2.0.2", 807 | "retry": "^0.12.0" 808 | }, 809 | "engines": { 810 | "node": ">=10" 811 | } 812 | }, 813 | "node_modules/proxy-from-env": { 814 | "version": "1.1.0", 815 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 816 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", 817 | "license": "MIT" 818 | }, 819 | "node_modules/readable-stream": { 820 | "version": "3.6.2", 821 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", 822 | "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", 823 | "license": "MIT", 824 | "dependencies": { 825 | "inherits": "^2.0.3", 826 | "string_decoder": "^1.1.1", 827 | "util-deprecate": "^1.0.1" 828 | }, 829 | "engines": { 830 | "node": ">= 6" 831 | } 832 | }, 833 | "node_modules/regenerator-runtime": { 834 | "version": "0.14.1", 835 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", 836 | "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", 837 | "license": "MIT" 838 | }, 839 | "node_modules/retry": { 840 | "version": "0.12.0", 841 | "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", 842 | "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", 843 | "license": "MIT", 844 | "engines": { 845 | "node": ">= 4" 846 | } 847 | }, 848 | "node_modules/rpc-websockets": { 849 | "version": "9.0.2", 850 | "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.0.2.tgz", 851 | "integrity": "sha512-YzggvfItxMY3Lwuax5rC18inhbjJv9Py7JXRHxTIi94JOLrqBsSsUUc5bbl5W6c11tXhdfpDPK0KzBhoGe8jjw==", 852 | "license": "LGPL-3.0-only", 853 | "dependencies": { 854 | "@swc/helpers": "^0.5.11", 855 | "@types/uuid": "^8.3.4", 856 | "@types/ws": "^8.2.2", 857 | "buffer": "^6.0.3", 858 | "eventemitter3": "^5.0.1", 859 | "uuid": "^8.3.2", 860 | "ws": "^8.5.0" 861 | }, 862 | "funding": { 863 | "type": "paypal", 864 | "url": "https://paypal.me/kozjak" 865 | }, 866 | "optionalDependencies": { 867 | "bufferutil": "^4.0.1", 868 | "utf-8-validate": "^5.0.2" 869 | } 870 | }, 871 | "node_modules/rpc-websockets/node_modules/@types/ws": { 872 | "version": "8.5.12", 873 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", 874 | "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", 875 | "license": "MIT", 876 | "dependencies": { 877 | "@types/node": "*" 878 | } 879 | }, 880 | "node_modules/rpc-websockets/node_modules/ws": { 881 | "version": "8.18.0", 882 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", 883 | "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", 884 | "license": "MIT", 885 | "engines": { 886 | "node": ">=10.0.0" 887 | }, 888 | "peerDependencies": { 889 | "bufferutil": "^4.0.1", 890 | "utf-8-validate": ">=5.0.2" 891 | }, 892 | "peerDependenciesMeta": { 893 | "bufferutil": { 894 | "optional": true 895 | }, 896 | "utf-8-validate": { 897 | "optional": true 898 | } 899 | } 900 | }, 901 | "node_modules/safe-buffer": { 902 | "version": "5.2.1", 903 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 904 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 905 | "funding": [ 906 | { 907 | "type": "github", 908 | "url": "https://github.com/sponsors/feross" 909 | }, 910 | { 911 | "type": "patreon", 912 | "url": "https://www.patreon.com/feross" 913 | }, 914 | { 915 | "type": "consulting", 916 | "url": "https://feross.org/support" 917 | } 918 | ], 919 | "license": "MIT" 920 | }, 921 | "node_modules/safe-stable-stringify": { 922 | "version": "2.4.3", 923 | "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", 924 | "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", 925 | "license": "MIT", 926 | "engines": { 927 | "node": ">=10" 928 | } 929 | }, 930 | "node_modules/simple-swizzle": { 931 | "version": "0.2.2", 932 | "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", 933 | "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", 934 | "license": "MIT", 935 | "dependencies": { 936 | "is-arrayish": "^0.3.1" 937 | } 938 | }, 939 | "node_modules/solana-swap": { 940 | "version": "1.1.2", 941 | "resolved": "https://registry.npmjs.org/solana-swap/-/solana-swap-1.1.2.tgz", 942 | "integrity": "sha512-t07kAFFmJJNO/6KkqRMUaxbovwJH8Xlm2QrygsAL/Y829isR2UV4OJqlxrNEVAmvylJx8At7lC5q3LxM6mQqZA==", 943 | "license": "ISC", 944 | "dependencies": { 945 | "@solana/web3.js": "^1.91.6", 946 | "axios": "^1.6.8", 947 | "bs58": "^5.0.0", 948 | "promise-retry": "^2.0.1" 949 | } 950 | }, 951 | "node_modules/stack-trace": { 952 | "version": "0.0.10", 953 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", 954 | "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", 955 | "license": "MIT", 956 | "engines": { 957 | "node": "*" 958 | } 959 | }, 960 | "node_modules/string_decoder": { 961 | "version": "1.3.0", 962 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 963 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 964 | "license": "MIT", 965 | "dependencies": { 966 | "safe-buffer": "~5.2.0" 967 | } 968 | }, 969 | "node_modules/superstruct": { 970 | "version": "2.0.2", 971 | "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", 972 | "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", 973 | "license": "MIT", 974 | "engines": { 975 | "node": ">=14.0.0" 976 | } 977 | }, 978 | "node_modules/supports-color": { 979 | "version": "7.2.0", 980 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 981 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 982 | "license": "MIT", 983 | "dependencies": { 984 | "has-flag": "^4.0.0" 985 | }, 986 | "engines": { 987 | "node": ">=8" 988 | } 989 | }, 990 | "node_modules/text-encoding-utf-8": { 991 | "version": "1.0.2", 992 | "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", 993 | "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" 994 | }, 995 | "node_modules/text-hex": { 996 | "version": "1.0.0", 997 | "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", 998 | "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", 999 | "license": "MIT" 1000 | }, 1001 | "node_modules/through": { 1002 | "version": "2.3.8", 1003 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1004 | "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", 1005 | "license": "MIT" 1006 | }, 1007 | "node_modules/tr46": { 1008 | "version": "0.0.3", 1009 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 1010 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", 1011 | "license": "MIT" 1012 | }, 1013 | "node_modules/triple-beam": { 1014 | "version": "1.4.1", 1015 | "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", 1016 | "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", 1017 | "license": "MIT", 1018 | "engines": { 1019 | "node": ">= 14.0.0" 1020 | } 1021 | }, 1022 | "node_modules/tslib": { 1023 | "version": "2.6.3", 1024 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", 1025 | "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", 1026 | "license": "0BSD" 1027 | }, 1028 | "node_modules/utf-8-validate": { 1029 | "version": "5.0.10", 1030 | "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", 1031 | "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", 1032 | "hasInstallScript": true, 1033 | "license": "MIT", 1034 | "optional": true, 1035 | "dependencies": { 1036 | "node-gyp-build": "^4.3.0" 1037 | }, 1038 | "engines": { 1039 | "node": ">=6.14.2" 1040 | } 1041 | }, 1042 | "node_modules/util-deprecate": { 1043 | "version": "1.0.2", 1044 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1045 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 1046 | "license": "MIT" 1047 | }, 1048 | "node_modules/uuid": { 1049 | "version": "8.3.2", 1050 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 1051 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", 1052 | "license": "MIT", 1053 | "bin": { 1054 | "uuid": "dist/bin/uuid" 1055 | } 1056 | }, 1057 | "node_modules/webidl-conversions": { 1058 | "version": "3.0.1", 1059 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 1060 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", 1061 | "license": "BSD-2-Clause" 1062 | }, 1063 | "node_modules/whatwg-url": { 1064 | "version": "5.0.0", 1065 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 1066 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 1067 | "license": "MIT", 1068 | "dependencies": { 1069 | "tr46": "~0.0.3", 1070 | "webidl-conversions": "^3.0.0" 1071 | } 1072 | }, 1073 | "node_modules/winston": { 1074 | "version": "3.13.1", 1075 | "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.1.tgz", 1076 | "integrity": "sha512-SvZit7VFNvXRzbqGHsv5KSmgbEYR5EiQfDAL9gxYkRqa934Hnk++zze0wANKtMHcy/gI4W/3xmSDwlhf865WGw==", 1077 | "license": "MIT", 1078 | "dependencies": { 1079 | "@colors/colors": "^1.6.0", 1080 | "@dabh/diagnostics": "^2.0.2", 1081 | "async": "^3.2.3", 1082 | "is-stream": "^2.0.0", 1083 | "logform": "^2.6.0", 1084 | "one-time": "^1.0.0", 1085 | "readable-stream": "^3.4.0", 1086 | "safe-stable-stringify": "^2.3.1", 1087 | "stack-trace": "0.0.x", 1088 | "triple-beam": "^1.3.0", 1089 | "winston-transport": "^4.7.0" 1090 | }, 1091 | "engines": { 1092 | "node": ">= 12.0.0" 1093 | } 1094 | }, 1095 | "node_modules/winston-transport": { 1096 | "version": "4.7.1", 1097 | "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.1.tgz", 1098 | "integrity": "sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA==", 1099 | "license": "MIT", 1100 | "dependencies": { 1101 | "logform": "^2.6.1", 1102 | "readable-stream": "^3.6.2", 1103 | "triple-beam": "^1.3.0" 1104 | }, 1105 | "engines": { 1106 | "node": ">= 12.0.0" 1107 | } 1108 | }, 1109 | "node_modules/ws": { 1110 | "version": "7.5.10", 1111 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", 1112 | "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", 1113 | "license": "MIT", 1114 | "engines": { 1115 | "node": ">=8.3.0" 1116 | }, 1117 | "peerDependencies": { 1118 | "bufferutil": "^4.0.1", 1119 | "utf-8-validate": "^5.0.2" 1120 | }, 1121 | "peerDependenciesMeta": { 1122 | "bufferutil": { 1123 | "optional": true 1124 | }, 1125 | "utf-8-validate": { 1126 | "optional": true 1127 | } 1128 | } 1129 | } 1130 | } 1131 | } 1132 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solana-volume-bot", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "description": "", 11 | "dependencies": { 12 | "chalk": "4.1.0", 13 | "dotenv": "^16.4.5", 14 | "solana-swap": "^1.1.2", 15 | "winston": "^3.13.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /services/ws.js: -------------------------------------------------------------------------------- 1 | const WebSocket = require('ws'); 2 | const EventEmitter = require('events'); 3 | 4 | module.exports = class WebSocketService { 5 | constructor(wsUrl) { 6 | this.wsUrl = wsUrl; 7 | this.socket = null; 8 | this.emitter = new EventEmitter(); 9 | this.emitter.setMaxListeners(0); 10 | this.subscribedRooms = new Set(); 11 | this.connect(); 12 | } 13 | 14 | connect() { 15 | this.socket = new WebSocket(this.wsUrl); 16 | 17 | this.socket.on("open", () => { 18 | this.resubscribeToRooms(); 19 | }); 20 | 21 | this.socket.on("message", (data) => { 22 | try { 23 | const message = JSON.parse(data); 24 | if (message.type === "message") { 25 | this.emitter.emit(message.room, message.data); 26 | } 27 | } catch (error) { 28 | console.error("Error processing message:", error); 29 | } 30 | }); 31 | 32 | this.socket.on("close", () => { 33 | console.info("Disconnected from WebSocket server"); 34 | setTimeout(() => this.connect(), 5000); 35 | }); 36 | } 37 | 38 | joinRoom(room) { 39 | this.subscribedRooms.add(room); 40 | if (this.socket.readyState === WebSocket.OPEN) { 41 | this.socket.send(JSON.stringify({ type: "join", room })); 42 | } 43 | } 44 | 45 | leaveRoom(room) { 46 | this.subscribedRooms.delete(room); 47 | if (this.socket.readyState === WebSocket.OPEN) { 48 | this.socket.send(JSON.stringify({ type: "leave", room })); 49 | } 50 | } 51 | 52 | on(room, listener) { 53 | this.emitter.on(room, listener); 54 | } 55 | 56 | resubscribeToRooms() { 57 | if (this.socket.readyState === WebSocket.OPEN) { 58 | for (const room of this.subscribedRooms) { 59 | this.socket.send(JSON.stringify({ type: "join", room })); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /websocket.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const { SolanaTracker } = require("solana-swap"); 3 | const { Keypair, PublicKey, Connection } = require("@solana/web3.js"); 4 | const bs58 = require("bs58"); 5 | const winston = require("winston"); 6 | const chalk = require("chalk"); 7 | const fs = require("fs").promises; 8 | const WebSocketService = require("./services/ws"); 9 | 10 | const logger = winston.createLogger({ 11 | level: "info", 12 | format: winston.format.combine( 13 | winston.format.timestamp({ 14 | format: "YYYY-MM-DD HH:mm:ss", 15 | }), 16 | winston.format.printf( 17 | (info) => `${info.timestamp} ${info.level}: ${info.message}` 18 | ) 19 | ), 20 | transports: [ 21 | new winston.transports.Console(), 22 | new winston.transports.File({ filename: "trading-bot.log" }), 23 | ], 24 | }); 25 | 26 | class TradingBot { 27 | constructor() { 28 | this.config = { 29 | amount: parseFloat(process.env.AMOUNT), 30 | slippage: parseInt(process.env.SLIPPAGE), 31 | priorityFee: parseFloat(process.env.PRIORITY_FEE), 32 | useJito: process.env.JITO === "true", 33 | rpcUrl: process.env.RPC_URL, 34 | minLiquidity: parseFloat(process.env.MIN_LIQUIDITY) || 0, 35 | maxLiquidity: parseFloat(process.env.MAX_LIQUIDITY) || Infinity, 36 | minMarketCap: parseFloat(process.env.MIN_MARKET_CAP) || 0, 37 | maxMarketCap: parseFloat(process.env.MAX_MARKET_CAP) || Infinity, 38 | minRiskScore: parseInt(process.env.MIN_RISK_SCORE) || 0, 39 | maxRiskScore: parseInt(process.env.MAX_RISK_SCORE) || 10, 40 | requireSocialData: process.env.REQUIRE_SOCIAL_DATA === "true", 41 | maxNegativePnL: parseFloat(process.env.MAX_NEGATIVE_PNL) || -Infinity, 42 | maxPositivePnL: parseFloat(process.env.MAX_POSITIVE_PNL) || Infinity, 43 | markets: process.env.MARKETS?.split(",").map((m) => m.trim()) || ['raydium', 'orca', 'pumpfun', 'moonshot', 'raydium-cpmm'], 44 | }; 45 | 46 | 47 | this.privateKey = process.env.PRIVATE_KEY; 48 | this.SOL_ADDRESS = "So11111111111111111111111111111111111111112"; 49 | this.positions = new Map(); 50 | this.positionsFile = "positions.json"; 51 | this.soldPositionsFile = "sold_positions.json"; 52 | this.soldPositions = []; 53 | this.seenTokens = new Set(); 54 | this.buyingTokens = new Set(); 55 | this.sellingPositions = new Set(); 56 | 57 | this.connection = new Connection(this.config.rpcUrl); 58 | this.wsService = new WebSocketService(process.env.WS_URL); 59 | } 60 | 61 | async initialize() { 62 | this.keypair = Keypair.fromSecretKey(bs58.decode(this.privateKey)); 63 | this.solanaTracker = new SolanaTracker(this.keypair, this.config.rpcUrl); 64 | await this.loadPositions(); 65 | await this.loadSoldPositions(); 66 | this.setupWebSocketListeners(); 67 | } 68 | 69 | setupWebSocketListeners() { 70 | logger.info("Monitoring for new tokens"); 71 | this.wsService.joinRoom('latest'); 72 | this.wsService.on('latest', (data) => this.handleNewToken(data)); 73 | 74 | // Setup listeners for existing positions 75 | for (const [tokenMint, position] of this.positions) { 76 | this.setupPriceListener(tokenMint, position.poolId); 77 | } 78 | } 79 | 80 | setupPriceListener(tokenMint, poolId) { 81 | this.wsService.joinRoom(`pool:${poolId}`); 82 | this.wsService.on(`pool:${poolId}`, (data) => this.handlePriceUpdate(tokenMint, data)); 83 | } 84 | 85 | handleNewToken(token) { 86 | if (this.filterToken(token)) { 87 | this.seenTokens.add(token.token.mint); 88 | this.performSwap(token, true).catch((error) => { 89 | logger.error(`Error buying new token: ${error.message}`, { error }); 90 | }); 91 | } 92 | } 93 | 94 | handlePriceUpdate(tokenMint, data) { 95 | const position = this.positions.get(tokenMint); 96 | if (position && !this.sellingPositions.has(tokenMint)) { 97 | const currentPrice = data.price.quote; 98 | const pnlPercentage = ((currentPrice - position.entryPrice) / position.entryPrice) * 100; 99 | 100 | logger.info( 101 | `PnL for position [${position.symbol}] [${chalk[ 102 | pnlPercentage > 0 ? "green" : "red" 103 | ](pnlPercentage.toFixed(2))}%]` 104 | ); 105 | 106 | if ( 107 | pnlPercentage <= this.config.maxNegativePnL || 108 | pnlPercentage >= this.config.maxPositivePnL 109 | ) { 110 | this.sellingPositions.add(tokenMint); 111 | const token = { 112 | token: { mint: tokenMint, symbol: position.symbol }, 113 | pools: [{ poolId: position.poolId, price: { quote: currentPrice } }] 114 | }; 115 | this.performSwap(token, false).catch((error) => { 116 | logger.error(`Error selling position: ${error.message}`, { error }); 117 | this.sellingPositions.delete(tokenMint); 118 | }); 119 | } 120 | } 121 | } 122 | 123 | filterToken(token) { 124 | const pool = token.pools[0]; 125 | const liquidity = pool.liquidity.usd; 126 | const marketCap = pool.marketCap.usd; 127 | const riskScore = token.risk.score; 128 | const hasSocialData = !!( 129 | token.token.twitter || 130 | token.token.telegram || 131 | token.token.website 132 | ); 133 | const isInAllowedMarket = this.config.markets.includes(pool.market); 134 | 135 | return ( 136 | liquidity >= this.config.minLiquidity && 137 | liquidity <= this.config.maxLiquidity && 138 | marketCap >= this.config.minMarketCap && 139 | marketCap <= this.config.maxMarketCap && 140 | riskScore >= this.config.minRiskScore && 141 | riskScore <= this.config.maxRiskScore && 142 | (!this.config.requireSocialData || hasSocialData) && 143 | isInAllowedMarket && 144 | !this.seenTokens.has(token.token.mint) && 145 | !this.buyingTokens.has(token.token.mint) 146 | ); 147 | } 148 | 149 | async performSwap(token, isBuy) { 150 | logger.info( 151 | `${ 152 | isBuy ? chalk.white("[BUYING]") : chalk.white("[SELLING]") 153 | } [${this.keypair.publicKey.toBase58()}] [${token.token.symbol}] [${ 154 | token.token.mint 155 | }]` 156 | ); 157 | const { amount, slippage, priorityFee } = this.config; 158 | const [fromToken, toToken] = isBuy 159 | ? [this.SOL_ADDRESS, token.token.mint] 160 | : [token.token.mint, this.SOL_ADDRESS]; 161 | 162 | try { 163 | let swapAmount; 164 | if (isBuy) { 165 | swapAmount = amount; 166 | } else { 167 | const position = this.positions.get(token.token.mint); 168 | if (!position) { 169 | logger.error( 170 | `No position found for ${token.token.symbol} when trying to sell` 171 | ); 172 | return false; 173 | } 174 | swapAmount = position.amount; 175 | } 176 | 177 | const swapResponse = await this.solanaTracker.getSwapInstructions( 178 | fromToken, 179 | toToken, 180 | swapAmount, 181 | slippage, 182 | this.keypair.publicKey.toBase58(), 183 | priorityFee 184 | ); 185 | 186 | const swapOptions = this.buildSwapOptions(); 187 | const txid = await this.solanaTracker.performSwap( 188 | swapResponse, 189 | swapOptions 190 | ); 191 | this.logTransaction(txid, isBuy, token); 192 | 193 | if (isBuy) { 194 | const tokenAmount = await this.getWalletAmount( 195 | this.keypair.publicKey.toBase58(), 196 | token.token.mint 197 | ); 198 | if (!tokenAmount) { 199 | logger.error( 200 | `Swap failed ${token.token.mint}` 201 | ); 202 | return false; 203 | } 204 | this.positions.set(token.token.mint, { 205 | txid, 206 | poolId: token.pools[0].poolId, 207 | symbol: token.token.symbol, 208 | entryPrice: token.pools[0].price.quote, 209 | amount: tokenAmount, 210 | openTime: Date.now(), 211 | }); 212 | this.buyingTokens.delete(token.token.mint); 213 | this.setupPriceListener(token.token.mint, token.pools[0].poolId); 214 | } else { 215 | const position = this.positions.get(token.token.mint); 216 | if (position) { 217 | const exitPrice = token.pools[0].price.quote; 218 | const pnl = (exitPrice - position.entryPrice) * position.amount; 219 | const pnlPercentage = 220 | (pnl / (position.entryPrice * position.amount)) * 100; 221 | 222 | const soldPosition = { 223 | ...position, 224 | exitPrice, 225 | pnl, 226 | pnlPercentage, 227 | closeTime: Date.now(), 228 | closeTxid: txid, 229 | }; 230 | 231 | this.soldPositions.push(soldPosition); 232 | 233 | logger.info( 234 | `Closed position for ${token.token.symbol}. PnL: (${pnlPercentage.toFixed(2)}%)` 235 | ); 236 | this.positions.delete(token.token.mint); 237 | this.sellingPositions.delete(token.token.mint); 238 | this.wsService.leaveRoom(`pool:${position.poolId}`); 239 | 240 | await this.saveSoldPositions(); 241 | } 242 | } 243 | 244 | await this.savePositions(); 245 | return txid; 246 | } catch (error) { 247 | logger.error( 248 | `Error performing ${isBuy ? "buy" : "sell"}: ${error.message}`, 249 | { error } 250 | ); 251 | if (isBuy) { 252 | this.buyingTokens.delete(token.token.mint); 253 | } else { 254 | this.sellingPositions.delete(token.token.mint); 255 | } 256 | return false; 257 | } 258 | } 259 | 260 | buildSwapOptions() { 261 | return { 262 | sendOptions: { skipPreflight: true }, 263 | confirmationRetries: 30, 264 | confirmationRetryTimeout: 1000, 265 | lastValidBlockHeightBuffer: 150, 266 | resendInterval: 1000, 267 | confirmationCheckInterval: 1000, 268 | commitment: "processed", 269 | jito: this.config.useJito ? { enabled: true, tip: 0.0001 } : undefined, 270 | }; 271 | } 272 | 273 | logTransaction(txid, isBuy, token) { 274 | logger.info( 275 | `${isBuy ? chalk.green("[BOUGHT]") : chalk.red("[SOLD]")} ${ 276 | token.token.symbol 277 | } [${txid}]` 278 | ); 279 | } 280 | 281 | async getWalletAmount(wallet, mint, retries = 3) { 282 | for (let attempt = 0; attempt <= retries; attempt++) { 283 | try { 284 | const tokenAccountInfo = 285 | await this.connection.getParsedTokenAccountsByOwner( 286 | new PublicKey(wallet), 287 | { 288 | mint: new PublicKey(mint), 289 | } 290 | ); 291 | 292 | if (tokenAccountInfo.value) { 293 | const balance = 294 | tokenAccountInfo.value[0].account.data.parsed.info.tokenAmount 295 | .uiAmount; 296 | 297 | if (balance > 0) { 298 | return balance; 299 | } 300 | } 301 | 302 | if (attempt < retries) { 303 | await new Promise(resolve => setTimeout(resolve, 10000)); 304 | } 305 | } catch (error) { 306 | if (attempt < retries) { 307 | await new Promise(resolve => setTimeout(resolve, 10000)); 308 | } else { 309 | logger.error( 310 | `All attempts failed. Error getting wallet amount for token ${mint}:`, 311 | error 312 | ); 313 | } 314 | } 315 | } 316 | 317 | logger.warn( 318 | `Failed to get wallet amount for token ${mint} after ${retries} retries.` 319 | ); 320 | return null; 321 | } 322 | 323 | async loadSoldPositions() { 324 | try { 325 | const data = await fs.readFile(this.soldPositionsFile, "utf8"); 326 | this.soldPositions = JSON.parse(data); 327 | logger.info( 328 | `Loaded ${this.soldPositions.length} sold positions from file` 329 | ); 330 | } catch (error) { 331 | if (error.code !== "ENOENT") { 332 | logger.error("Error loading sold positions", { error }); 333 | } 334 | } 335 | } 336 | 337 | async saveSoldPositions() { 338 | try { 339 | await fs.writeFile( 340 | this.soldPositionsFile, 341 | JSON.stringify(this.soldPositions, null, 2) 342 | ); 343 | logger.info(`Saved ${this.soldPositions.length} sold positions to file`); 344 | } catch (error) { 345 | logger.error("Error saving sold positions", { error }); 346 | } 347 | } 348 | 349 | async loadPositions() { 350 | try { 351 | const data = await fs.readFile(this.positionsFile, "utf8"); 352 | const loadedPositions = JSON.parse(data); 353 | this.positions = new Map(Object.entries(loadedPositions)); 354 | this.seenTokens = new Set(this.positions.keys()); 355 | logger.info(`Loaded ${this.positions.size} positions from file`); 356 | } catch (error) { 357 | if (error.code !== "ENOENT") { 358 | logger.error("Error loading positions", { error }); 359 | } 360 | } 361 | } 362 | 363 | async savePositions() { 364 | try { 365 | const positionsObject = Object.fromEntries(this.positions); 366 | await fs.writeFile( 367 | this.positionsFile, 368 | JSON.stringify(positionsObject, null, 2) 369 | ); 370 | logger.info(`Saved ${this.positions.size} positions to file`); 371 | } catch (error) { 372 | logger.error("Error saving positions", { error }); 373 | } 374 | } 375 | 376 | async start() { 377 | logger.info("Starting Trading Bot"); 378 | await this.initialize(); 379 | } 380 | } 381 | 382 | const bot = new TradingBot(); 383 | bot.start().catch((error) => logger.error("Error in bot execution", { error })); --------------------------------------------------------------------------------