├── utils ├── utils.js ├── index.js ├── logger.js └── getPoolKeys.js ├── types ├── mint.js └── index.js ├── market ├── index.js └── market.js ├── constants ├── index.js └── constants.js ├── liquidity ├── index.js └── liquidity.js ├── package.json ├── .env ├── executor ├── legacy.js ├── jito.js └── jitoWithAxios.js ├── monitor.js ├── .gitignore ├── tokenFilter └── index.js ├── README.md └── buy.js /utils/utils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.retrieveEnvVariable = void 0; 7 | const dotenv_1 = __importDefault(require("dotenv")); 8 | dotenv_1.default.config(); 9 | const retrieveEnvVariable = (variableName, logger) => { 10 | const variable = process.env[variableName] || ''; 11 | if (!variable) { 12 | console.log(`${variableName} is not set`); 13 | process.exit(1); 14 | } 15 | return variable; 16 | }; 17 | exports.retrieveEnvVariable = retrieveEnvVariable; 18 | -------------------------------------------------------------------------------- /types/mint.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.MintLayout = void 0; 4 | const buffer_layout_1 = require("@solana/buffer-layout"); 5 | const buffer_layout_utils_1 = require("@solana/buffer-layout-utils"); 6 | /** Buffer layout for de/serializing a mint */ 7 | exports.MintLayout = (0, buffer_layout_1.struct)([ 8 | (0, buffer_layout_1.u32)('mintAuthorityOption'), 9 | (0, buffer_layout_utils_1.publicKey)('mintAuthority'), 10 | (0, buffer_layout_utils_1.u64)('supply'), 11 | (0, buffer_layout_1.u8)('decimals'), 12 | (0, buffer_layout_utils_1.bool)('isInitialized'), 13 | (0, buffer_layout_1.u32)('freezeAuthorityOption'), 14 | (0, buffer_layout_utils_1.publicKey)('freezeAuthority'), 15 | ]); 16 | -------------------------------------------------------------------------------- /market/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./market"), exports); 18 | -------------------------------------------------------------------------------- /types/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./mint"), exports); 18 | -------------------------------------------------------------------------------- /constants/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./constants"), exports); 18 | -------------------------------------------------------------------------------- /liquidity/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./liquidity"), exports); 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solana-sniper-bot", 3 | "author": "Filip Dundjer", 4 | "scripts": { 5 | "buy": "ts-node buy.ts", 6 | "sell": "ts-node sell.ts", 7 | "tsc": "tsc " 8 | }, 9 | "dependencies": { 10 | "@metaplex-foundation/mpl-token-metadata": "^3.2.1", 11 | "@metaplex-foundation/umi": "^0.9.1", 12 | "@raydium-io/raydium-sdk": "^1.3.1-beta.47", 13 | "@solana/spl-token": "^0.4.0", 14 | "@solana/web3.js": "^1.89.1", 15 | "axios": "^1.6.8", 16 | "bigint-buffer": "^1.1.5", 17 | "bn.js": "^5.2.1", 18 | "bs58": "^5.0.0", 19 | "dotenv": "^16.4.1", 20 | "jito-ts": "^3.0.1", 21 | "pino": "^8.18.0", 22 | "pino-pretty": "^10.3.1", 23 | "pino-std-serializers": "^6.2.2" 24 | }, 25 | "devDependencies": { 26 | "@types/bn.js": "^5.1.5", 27 | "prettier": "^3.2.4", 28 | "ts-node": "^10.9.2", 29 | "typescript": "^5.3.3" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /utils/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./utils"), exports); 18 | __exportStar(require("./logger"), exports); 19 | -------------------------------------------------------------------------------- /utils/logger.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.deleteConsoleLines = exports.logger = void 0; 7 | const pino_1 = __importDefault(require("pino")); 8 | const readline_1 = require("readline"); 9 | const transport = pino_1.default.transport({ 10 | target: 'pino-pretty', 11 | }); 12 | exports.logger = (0, pino_1.default)({ 13 | level: 'info', 14 | redact: ['poolKeys'], 15 | serializers: { 16 | error: pino_1.default.stdSerializers.err, 17 | }, 18 | base: undefined, 19 | }, transport); 20 | function deleteConsoleLines(numLines) { 21 | for (let i = 0; i < numLines; i++) { 22 | process.stdout.moveCursor(0, -1); // Move cursor up one line 23 | (0, readline_1.clearLine)(process.stdout, 0); // Clear the line 24 | } 25 | } 26 | exports.deleteConsoleLines = deleteConsoleLines; 27 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY= 2 | RPC_ENDPOINT=https://staked.helius-rpc.com/?api-key= 3 | RPC_WEBSOCKET_ENDPOINT=wss://mainnet.helius-rpc.com/?api-key= 4 | 5 | ##### Buy #### 6 | QUOTE_MINT=WSOL 7 | QUOTE_AMOUNT=0.002 8 | MAX_BUY_RETRIES=10 9 | 10 | ##### SELL ##### 11 | AUTO_SELL=true 12 | MAX_SELL_RETRIES=5 13 | PRICE_CHECK_INTERVAL=1000 14 | PRICE_CHECK_DURATION=60000 15 | TAKE_PROFIT1=10 16 | TAKE_PROFIT2=200 17 | SELL_AT_TP1=70 18 | 19 | STOP_LOSS=30 20 | SELL_SLIPPAGE=80 21 | 22 | ####### Filters ######## 23 | USE_SNIPE_LIST=false 24 | SNIPE_LIST_REFRESH_INTERVAL=10000 25 | 26 | CHECK_IF_MINT_IS_RENOUNCED=false 27 | CHECK_IF_MINT_IS_MUTABLE=false 28 | CHECK_IF_MINT_IS_BURNED=false 29 | CHECK_SOCIAL=false 30 | LOG_LEVEL=info 31 | MIN_POOL_SIZE=1 32 | MAX_POOL_SIZE=1000 33 | 34 | ###### General setting ###### 35 | ONE_TOKEN_AT_A_TIME=true 36 | BLOCKENGINE_URL=tokyo.mainnet.block-engine.jito.wtf 37 | COMMITMENT_LEVEL=confirmed 38 | JITO_FEE=0.002 39 | JITO_KEY=66xqL9aFZJ8k9YpjNBexNASfuoDgNE1ZpGRXB28zoTfS4u2czzVBhMNMqgZYFeMN8FnUi6gMzXWgVYRHkTZ6yuLC 40 | 41 | ##### Transaction mode #### 42 | JITO_MODE=true 43 | JITO_ALL=false -------------------------------------------------------------------------------- /market/market.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.getMinimalMarketV3 = void 0; 13 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk"); 14 | const liquidity_1 = require("../liquidity"); 15 | function getMinimalMarketV3(connection, marketId, commitment) { 16 | return __awaiter(this, void 0, void 0, function* () { 17 | const marketInfo = yield connection.getAccountInfo(marketId, { 18 | commitment, 19 | dataSlice: { 20 | offset: raydium_sdk_1.MARKET_STATE_LAYOUT_V3.offsetOf('eventQueue'), 21 | length: 32 * 3, 22 | }, 23 | }); 24 | return liquidity_1.MINIMAL_MARKET_STATE_LAYOUT_V3.decode(marketInfo.data); 25 | }); 26 | } 27 | exports.getMinimalMarketV3 = getMinimalMarketV3; 28 | -------------------------------------------------------------------------------- /executor/legacy.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.execute = void 0; 13 | const web3_js_1 = require("@solana/web3.js"); 14 | const constants_1 = require("../constants"); 15 | const utils_1 = require("../utils"); 16 | const execute = (transaction, latestBlockhash) => __awaiter(void 0, void 0, void 0, function* () { 17 | const solanaConnection = new web3_js_1.Connection(constants_1.RPC_ENDPOINT, { 18 | wsEndpoint: constants_1.RPC_WEBSOCKET_ENDPOINT, 19 | }); 20 | const signature = yield solanaConnection.sendRawTransaction(transaction.serialize(), { 21 | preflightCommitment: constants_1.COMMITMENT_LEVEL, 22 | }); 23 | utils_1.logger.debug({ signature }, 'Confirming transaction...'); 24 | const confirmation = yield solanaConnection.confirmTransaction({ 25 | signature, 26 | lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, 27 | blockhash: latestBlockhash.blockhash, 28 | }, constants_1.COMMITMENT_LEVEL); 29 | if (confirmation.value.err) { 30 | console.log("Confrimtaion error"); 31 | return; 32 | } 33 | else { 34 | console.log("https://solscan.io/tx/", signature); 35 | } 36 | }); 37 | exports.execute = execute; 38 | -------------------------------------------------------------------------------- /monitor.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.clearMonitor = exports.monitor = void 0; 13 | let monitorTimer; 14 | const monitor = (poolId) => __awaiter(void 0, void 0, void 0, function* () { 15 | monitorTimer = setInterval(() => { 16 | (() => __awaiter(void 0, void 0, void 0, function* () { 17 | try { 18 | const res = yield fetch(`https://api.dexscreener.com/latest/dex/pairs/solana/${poolId === null || poolId === void 0 ? void 0 : poolId.toBase58()}`, { 19 | method: 'GET', 20 | headers: { 21 | Accept: 'application/json', 22 | 'Content-Type': 'application/json' 23 | } 24 | }); 25 | const data = yield res.clone().json(); 26 | if (data.pair) 27 | console.log(`Token price : ${data.pair.priceNative}SOL / ${data.pair.priceUsd}USD <<<=====>>> Liquidity: ${data.pair.liquidity.usd}USD / ${data.pair.liquidity.quote}SOL`); 28 | } 29 | catch (e) { 30 | // console.log("error in fetching price of pool", e) 31 | } 32 | }))(); 33 | }, 2000); 34 | }); 35 | exports.monitor = monitor; 36 | const clearMonitor = () => { 37 | clearInterval(monitorTimer); 38 | }; 39 | exports.clearMonitor = clearMonitor; 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # PNPM 126 | pnpm-lock.yaml 127 | 128 | # yarn v2 129 | .yarn/cache 130 | .yarn/unplugged 131 | .yarn/build-state.yml 132 | .yarn/install-state.gz 133 | .pnp.* 134 | 135 | # JetBrains 136 | .idea 137 | 138 | # Visual Studio Code 139 | *.code-workspace 140 | 141 | data.json -------------------------------------------------------------------------------- /tokenFilter/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.checkSocial = exports.checkMutable = exports.checkBurn = void 0; 13 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk"); 14 | const mpl_token_metadata_1 = require("@metaplex-foundation/mpl-token-metadata"); 15 | const checkBurn = (connection, lpMint, commitment) => __awaiter(void 0, void 0, void 0, function* () { 16 | try { 17 | const amount = yield connection.getTokenSupply(lpMint, commitment); 18 | const burned = amount.value.uiAmount === 0; 19 | return burned; 20 | } 21 | catch (error) { 22 | return false; 23 | } 24 | }); 25 | exports.checkBurn = checkBurn; 26 | const checkMutable = (connection, baseMint) => __awaiter(void 0, void 0, void 0, function* () { 27 | try { 28 | const metadataPDA = (0, raydium_sdk_1.getPdaMetadataKey)(baseMint); 29 | const metadataAccount = yield connection.getAccountInfo(metadataPDA.publicKey); 30 | if (!(metadataAccount === null || metadataAccount === void 0 ? void 0 : metadataAccount.data)) { 31 | return { ok: false, message: 'Mutable -> Failed to fetch account data' }; 32 | } 33 | const serializer = (0, mpl_token_metadata_1.getMetadataAccountDataSerializer)(); 34 | const deserialize = serializer.deserialize(metadataAccount.data); 35 | const mutable = deserialize[0].isMutable; 36 | return !mutable; 37 | } 38 | catch (e) { 39 | return false; 40 | } 41 | }); 42 | exports.checkMutable = checkMutable; 43 | const checkSocial = (connection, baseMint, commitment) => __awaiter(void 0, void 0, void 0, function* () { 44 | try { 45 | const serializer = (0, mpl_token_metadata_1.getMetadataAccountDataSerializer)(); 46 | const metadataPDA = (0, raydium_sdk_1.getPdaMetadataKey)(baseMint); 47 | const metadataAccount = yield connection.getAccountInfo(metadataPDA.publicKey, commitment); 48 | if (!(metadataAccount === null || metadataAccount === void 0 ? void 0 : metadataAccount.data)) { 49 | return { ok: false, message: 'Mutable -> Failed to fetch account data' }; 50 | } 51 | const deserialize = serializer.deserialize(metadataAccount.data); 52 | const social = yield hasSocials(deserialize[0]); 53 | return social; 54 | } 55 | catch (error) { 56 | return false; 57 | } 58 | }); 59 | exports.checkSocial = checkSocial; 60 | function hasSocials(metadata) { 61 | return __awaiter(this, void 0, void 0, function* () { 62 | var _a; 63 | const response = yield fetch(metadata.uri); 64 | const data = yield response.json(); 65 | return Object.values((_a = data === null || data === void 0 ? void 0 : data.extensions) !== null && _a !== void 0 ? _a : {}).some((value) => value !== null && value.length > 0); 66 | }); 67 | } 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Solana Raydium Sniper 2 | 3 | Solana Raydium Sniper is a bot that fetches new token pools and executes buys using the Jito technique to optimize for faster transaction speeds and potential profits. 4 | 5 | ## GitHub Repository 6 | 7 | [Raydium Sniper GitHub Repository](https://github.com/Rabnail-SOL/Solana-Raydium-Sniper) 8 | 9 | ## Features 10 | 11 | - **Automated Pool Detection**: Detects new pools on Raydium and buys tokens automatically. 12 | - **Jito Integration**: Leverages Jito block engine for rapid transaction processing. 13 | - **Configurable Environment Variables**: Customize bot behavior using environment variables. 14 | - **Auto-Sell Functionality**: Automatizes selling with multiple take-profit options and stop-loss settings. 15 | - **Advanced Filters and Configuration**: Fine-tune sniping behavior using extensive filter options. 16 | 17 | ## Environment Variables 18 | 19 | Set the following environment variables in your `.env` file: 20 | 21 | ```plaintext 22 | PRIVATE_KEY= 23 | RPC_ENDPOINT=https://staked.helius-rpc.com/?api-key= 24 | RPC_WEBSOCKET_ENDPOINT=wss://mainnet.helius-rpc.com/?api-key= 25 | 26 | ### Buy Configuration 27 | - `QUOTE_MINT`: The mint address of the token you're using to buy (e.g., WSOL). 28 | - `QUOTE_AMOUNT`: The amount of token used for buying. 29 | - `MAX_BUY_RETRIES`: Maximum number of attempts to retry buying. 30 | 31 | ### Sell Configuration 32 | - `AUTO_SELL`: Enable or disable auto-sell. 33 | - `MAX_SELL_RETRIES`: Maximum number of retries for selling. 34 | - `PRICE_CHECK_INTERVAL`: Interval between price checks in milliseconds. 35 | - `PRICE_CHECK_DURATION`: Duration for price checks in milliseconds. 36 | - `TAKE_PROFIT1` and `TAKE_PROFIT2`: Target profit levels. 37 | - `SELL_AT_TP1`: Percentage of holding to sell at the first take-profit level. 38 | - `STOP_LOSS`: Stop-loss percentage. 39 | - `SELL_SLIPPAGE`: Allowed sell slippage percentage. 40 | 41 | ### Filters 42 | - `USE_SNIPE_LIST`: Use a predefined list of tokens to snipe. 43 | - `SNIPE_LIST_REFRESH_INTERVAL`: Time interval to refresh the snipe list. 44 | - `CHECK_IF_MINT_IS_RENOUNCED`, `CHECK_IF_MINT_IS_MUTABLE`, `CHECK_IF_MINT_IS_BURNED`: Options for mint conditions. 45 | - `CHECK_SOCIAL`: Enable social checks. 46 | - `LOG_LEVEL`: Set the logging level (e.g., `info`). 47 | - `MIN_POOL_SIZE`, `MAX_POOL_SIZE`: Limits for pool sizes eligible for sniping. 48 | 49 | ### General Settings 50 | - `ONE_TOKEN_AT_A_TIME`: Restriction to one token trade at a time. 51 | - `BLOCKENGINE_URL`: URL of the Jito block engine server. 52 | - `COMMITMENT_LEVEL`: Solana network commitment level (e.g., `confirmed`). 53 | - `JITO_FEE`: Fee incurred per Jito transaction. 54 | - `JITO_KEY`: API key for Jito transactions. 55 | 56 | ### Transaction Mode 57 | - `JITO_MODE`: Enable Jito transaction mode. 58 | - `JITO_ALL`: Option to apply Jito to all transactions. 59 | ``` 60 | ## Usage Guide 61 | 62 | 1. **Setup Environment**: Fill out your `.env` file with your private key and RPC endpoints. 63 | 2. **Run the Bot**: Execute the bot using your preferred Node.js environment. 64 | 65 | ```bash 66 | npm install 67 | 68 | npm run buy 69 | ``` 70 | 71 | 72 | ## 👤 Author 73 | 74 | ### Discord: rabnail_15 in discord 75 | 76 | ### Twitter: [@Rabnail_SOL](https://twitter.com/Rabnail_SOL) 77 | 78 | ### Telegram: [@Rabnail_SOL](https://t.me/Rabnail_SOL) 79 | 80 | 81 | You can always find me here, for help, or for other projects. 82 | -------------------------------------------------------------------------------- /liquidity/liquidity.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.getTokenAccounts = exports.createPoolKeys = exports.MINIMAL_MARKET_STATE_LAYOUT_V3 = exports.OPENBOOK_PROGRAM_ID = exports.RAYDIUM_LIQUIDITY_PROGRAM_ID_V4 = void 0; 13 | const web3_js_1 = require("@solana/web3.js"); 14 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk"); 15 | const spl_token_1 = require("@solana/spl-token"); 16 | exports.RAYDIUM_LIQUIDITY_PROGRAM_ID_V4 = raydium_sdk_1.MAINNET_PROGRAM_ID.AmmV4; 17 | exports.OPENBOOK_PROGRAM_ID = raydium_sdk_1.MAINNET_PROGRAM_ID.OPENBOOK_MARKET; 18 | exports.MINIMAL_MARKET_STATE_LAYOUT_V3 = (0, raydium_sdk_1.struct)([ 19 | (0, raydium_sdk_1.publicKey)('eventQueue'), 20 | (0, raydium_sdk_1.publicKey)('bids'), 21 | (0, raydium_sdk_1.publicKey)('asks'), 22 | ]); 23 | function createPoolKeys(id, accountData, minimalMarketLayoutV3) { 24 | return { 25 | id, 26 | baseMint: accountData.baseMint, 27 | quoteMint: accountData.quoteMint, 28 | lpMint: accountData.lpMint, 29 | baseDecimals: accountData.baseDecimal.toNumber(), 30 | quoteDecimals: accountData.quoteDecimal.toNumber(), 31 | lpDecimals: 5, 32 | version: 4, 33 | programId: exports.RAYDIUM_LIQUIDITY_PROGRAM_ID_V4, 34 | authority: raydium_sdk_1.Liquidity.getAssociatedAuthority({ 35 | programId: exports.RAYDIUM_LIQUIDITY_PROGRAM_ID_V4, 36 | }).publicKey, 37 | openOrders: accountData.openOrders, 38 | targetOrders: accountData.targetOrders, 39 | baseVault: accountData.baseVault, 40 | quoteVault: accountData.quoteVault, 41 | marketVersion: 3, 42 | marketProgramId: accountData.marketProgramId, 43 | marketId: accountData.marketId, 44 | marketAuthority: raydium_sdk_1.Market.getAssociatedAuthority({ 45 | programId: accountData.marketProgramId, 46 | marketId: accountData.marketId, 47 | }).publicKey, 48 | marketBaseVault: accountData.baseVault, 49 | marketQuoteVault: accountData.quoteVault, 50 | marketBids: minimalMarketLayoutV3.bids, 51 | marketAsks: minimalMarketLayoutV3.asks, 52 | marketEventQueue: minimalMarketLayoutV3.eventQueue, 53 | withdrawQueue: accountData.withdrawQueue, 54 | lpVault: accountData.lpVault, 55 | lookupTableAccount: web3_js_1.PublicKey.default, 56 | }; 57 | } 58 | exports.createPoolKeys = createPoolKeys; 59 | function getTokenAccounts(connection, owner, commitment) { 60 | return __awaiter(this, void 0, void 0, function* () { 61 | const tokenResp = yield connection.getTokenAccountsByOwner(owner, { 62 | programId: spl_token_1.TOKEN_PROGRAM_ID, 63 | }, commitment); 64 | const accounts = []; 65 | for (const { pubkey, account } of tokenResp.value) { 66 | accounts.push({ 67 | pubkey, 68 | programId: account.owner, 69 | accountInfo: raydium_sdk_1.SPL_ACCOUNT_LAYOUT.decode(account.data), 70 | }); 71 | } 72 | return accounts; 73 | }); 74 | } 75 | exports.getTokenAccounts = getTokenAccounts; 76 | -------------------------------------------------------------------------------- /constants/constants.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.SELL_AT_TP1 = exports.SELL_SLIPPAGE = exports.STOP_LOSS = exports.TAKE_PROFIT2 = exports.TAKE_PROFIT1 = exports.PRICE_CHECK_DURATION = exports.PRICE_CHECK_INTERVAL = exports.MAX_BUY_RETRIES = exports.JITO_FEE = exports.JITO_AUTH_KEYPAIR = exports.BLOCKENGINE_URL = exports.JITO_ALL = exports.JITO_MODE = exports.CHECK_SOCIAL = exports.CHECK_IF_MINT_IS_BURNED = exports.CHECK_IF_MINT_IS_MUTABLE = exports.ONE_TOKEN_AT_A_TIME = exports.MAX_POOL_SIZE = exports.MIN_POOL_SIZE = exports.QUOTE_AMOUNT = exports.QUOTE_MINT = exports.PRIVATE_KEY = exports.MAX_SELL_RETRIES = exports.SNIPE_LIST_REFRESH_INTERVAL = exports.USE_SNIPE_LIST = exports.CHECK_IF_MINT_IS_RENOUNCED = exports.LOG_LEVEL = exports.RPC_WEBSOCKET_ENDPOINT = exports.RPC_ENDPOINT = exports.COMMITMENT_LEVEL = exports.NETWORK = void 0; 4 | const utils_1 = require("../utils"); 5 | exports.NETWORK = 'mainnet-beta'; 6 | exports.COMMITMENT_LEVEL = (0, utils_1.retrieveEnvVariable)('COMMITMENT_LEVEL', utils_1.logger); 7 | exports.RPC_ENDPOINT = (0, utils_1.retrieveEnvVariable)('RPC_ENDPOINT', utils_1.logger); 8 | exports.RPC_WEBSOCKET_ENDPOINT = (0, utils_1.retrieveEnvVariable)('RPC_WEBSOCKET_ENDPOINT', utils_1.logger); 9 | exports.LOG_LEVEL = (0, utils_1.retrieveEnvVariable)('LOG_LEVEL', utils_1.logger); 10 | exports.CHECK_IF_MINT_IS_RENOUNCED = (0, utils_1.retrieveEnvVariable)('CHECK_IF_MINT_IS_RENOUNCED', utils_1.logger) === 'true'; 11 | exports.USE_SNIPE_LIST = (0, utils_1.retrieveEnvVariable)('USE_SNIPE_LIST', utils_1.logger) === 'true'; 12 | exports.SNIPE_LIST_REFRESH_INTERVAL = Number((0, utils_1.retrieveEnvVariable)('SNIPE_LIST_REFRESH_INTERVAL', utils_1.logger)); 13 | exports.MAX_SELL_RETRIES = Number((0, utils_1.retrieveEnvVariable)('MAX_SELL_RETRIES', utils_1.logger)); 14 | exports.PRIVATE_KEY = (0, utils_1.retrieveEnvVariable)('PRIVATE_KEY', utils_1.logger); 15 | exports.QUOTE_MINT = (0, utils_1.retrieveEnvVariable)('QUOTE_MINT', utils_1.logger); 16 | exports.QUOTE_AMOUNT = (0, utils_1.retrieveEnvVariable)('QUOTE_AMOUNT', utils_1.logger); 17 | exports.MIN_POOL_SIZE = (0, utils_1.retrieveEnvVariable)('MIN_POOL_SIZE', utils_1.logger); 18 | exports.MAX_POOL_SIZE = (0, utils_1.retrieveEnvVariable)('MAX_POOL_SIZE', utils_1.logger); 19 | exports.ONE_TOKEN_AT_A_TIME = (0, utils_1.retrieveEnvVariable)('ONE_TOKEN_AT_A_TIME', utils_1.logger) === 'true'; 20 | exports.CHECK_IF_MINT_IS_MUTABLE = (0, utils_1.retrieveEnvVariable)('CHECK_IF_MINT_IS_MUTABLE', utils_1.logger) === 'true'; 21 | exports.CHECK_IF_MINT_IS_BURNED = (0, utils_1.retrieveEnvVariable)('CHECK_IF_MINT_IS_BURNED', utils_1.logger) === 'true'; 22 | exports.CHECK_SOCIAL = (0, utils_1.retrieveEnvVariable)('CHECK_SOCIAL', utils_1.logger) === 'true'; 23 | exports.JITO_MODE = (0, utils_1.retrieveEnvVariable)('JITO_MODE', utils_1.logger) === 'true'; 24 | exports.JITO_ALL = (0, utils_1.retrieveEnvVariable)('JITO_ALL', utils_1.logger) === 'true'; 25 | exports.BLOCKENGINE_URL = (0, utils_1.retrieveEnvVariable)('BLOCKENGINE_URL', utils_1.logger); 26 | exports.JITO_AUTH_KEYPAIR = (0, utils_1.retrieveEnvVariable)('JITO_KEY', utils_1.logger); 27 | exports.JITO_FEE = Number((0, utils_1.retrieveEnvVariable)('JITO_FEE', utils_1.logger)) * 10 ** 9; 28 | exports.MAX_BUY_RETRIES = Number((0, utils_1.retrieveEnvVariable)('MAX_BUY_RETRIES', utils_1.logger)); 29 | exports.PRICE_CHECK_INTERVAL = Number((0, utils_1.retrieveEnvVariable)('PRICE_CHECK_INTERVAL', utils_1.logger)); 30 | exports.PRICE_CHECK_DURATION = Number((0, utils_1.retrieveEnvVariable)('PRICE_CHECK_DURATION', utils_1.logger)); 31 | exports.TAKE_PROFIT1 = Number((0, utils_1.retrieveEnvVariable)('TAKE_PROFIT1', utils_1.logger)); 32 | exports.TAKE_PROFIT2 = Number((0, utils_1.retrieveEnvVariable)('TAKE_PROFIT2', utils_1.logger)); 33 | exports.STOP_LOSS = Number((0, utils_1.retrieveEnvVariable)('STOP_LOSS', utils_1.logger)); 34 | exports.SELL_SLIPPAGE = Number((0, utils_1.retrieveEnvVariable)('SELL_SLIPPAGE', utils_1.logger)); 35 | exports.SELL_AT_TP1 = Number((0, utils_1.retrieveEnvVariable)('SELL_AT_TP1', utils_1.logger)); 36 | -------------------------------------------------------------------------------- /executor/jito.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Jito Bundling part 3 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 4 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 5 | return new (P || (P = Promise))(function (resolve, reject) { 6 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 7 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 8 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 9 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 10 | }); 11 | }; 12 | var __importDefault = (this && this.__importDefault) || function (mod) { 13 | return (mod && mod.__esModule) ? mod : { "default": mod }; 14 | }; 15 | Object.defineProperty(exports, "__esModule", { value: true }); 16 | exports.onBundleResult = exports.bull_dozer = exports.bundle = void 0; 17 | const web3_js_1 = require("@solana/web3.js"); 18 | const constants_1 = require("../constants"); 19 | const bs58_1 = __importDefault(require("bs58")); 20 | const searcher_1 = require("jito-ts/dist/sdk/block-engine/searcher"); 21 | const types_1 = require("jito-ts/dist/sdk/block-engine/types"); 22 | const utils_1 = require("jito-ts/dist/sdk/block-engine/utils"); 23 | const solanaConnection = new web3_js_1.Connection(constants_1.RPC_ENDPOINT, { 24 | wsEndpoint: constants_1.RPC_WEBSOCKET_ENDPOINT, 25 | }); 26 | function bundle(txs, keypair) { 27 | return __awaiter(this, void 0, void 0, function* () { 28 | console.log("🚀 ~ bundle ~ txs:", txs); 29 | try { 30 | const txNum = Math.ceil(txs.length / 3); 31 | let successNum = 0; 32 | for (let i = 0; i < txNum; i++) { 33 | const upperIndex = (i + 1) * 3; 34 | const downIndex = i * 3; 35 | const newTxs = []; 36 | for (let j = downIndex; j < upperIndex; j++) { 37 | if (txs[j]) 38 | newTxs.push(txs[j]); 39 | } 40 | let success = yield bull_dozer(newTxs, keypair); 41 | return success; 42 | } 43 | if (successNum == txNum) 44 | return true; 45 | else 46 | return false; 47 | } 48 | catch (error) { 49 | return false; 50 | } 51 | }); 52 | } 53 | exports.bundle = bundle; 54 | function bull_dozer(txs, keypair) { 55 | return __awaiter(this, void 0, void 0, function* () { 56 | try { 57 | const bundleTransactionLimit = parseInt('4'); 58 | const jitoKey = web3_js_1.Keypair.fromSecretKey(bs58_1.default.decode(constants_1.JITO_AUTH_KEYPAIR)); 59 | const search = (0, searcher_1.searcherClient)(constants_1.BLOCKENGINE_URL, jitoKey); 60 | console.log("🚀 BLOCKENGINE_URL:", constants_1.BLOCKENGINE_URL); 61 | yield build_bundle(search, bundleTransactionLimit, txs, keypair); 62 | const bundle_result = yield (0, exports.onBundleResult)(search); 63 | return bundle_result; 64 | } 65 | catch (error) { 66 | return 0; 67 | } 68 | }); 69 | } 70 | exports.bull_dozer = bull_dozer; 71 | function build_bundle(search, bundleTransactionLimit, txs, keypair) { 72 | return __awaiter(this, void 0, void 0, function* () { 73 | const accounts = yield search.getTipAccounts(); 74 | const _tipAccount = accounts[Math.min(Math.floor(Math.random() * accounts.length), 3)]; 75 | const tipAccount = new web3_js_1.PublicKey(_tipAccount); 76 | console.log("🚀 ~ tipAccount:", tipAccount); 77 | const bund = new types_1.Bundle([], bundleTransactionLimit); 78 | const resp = yield solanaConnection.getLatestBlockhash("processed"); 79 | bund.addTransactions(...txs); 80 | let maybeBundle = bund.addTipTx(keypair, constants_1.JITO_FEE, tipAccount, resp.blockhash); 81 | console.log("🚀 ~ maybeBundle:", maybeBundle); 82 | if ((0, utils_1.isError)(maybeBundle)) { 83 | throw maybeBundle; 84 | } 85 | try { 86 | yield search.sendBundle(maybeBundle); 87 | } 88 | catch (e) { } 89 | return maybeBundle; 90 | }); 91 | } 92 | const onBundleResult = (c) => { 93 | let first = 0; 94 | let isResolved = false; 95 | return new Promise((resolve) => { 96 | // Set a timeout to reject the promise if no bundle is accepted within 5 seconds 97 | setTimeout(() => { 98 | resolve(first); 99 | isResolved = true; 100 | }, 30000); 101 | c.onBundleResult((result) => { 102 | if (isResolved) 103 | return first; 104 | // clearTimeout(timeout) // Clear the timeout if a bundle is accepted 105 | const isAccepted = result.accepted; 106 | const isRejected = result.rejected; 107 | if (isResolved == false) { 108 | if (isAccepted) { 109 | // console.log(`bundle accepted, ID: ${result.bundleId} | Slot: ${result.accepted!.slot}`) 110 | first += 1; 111 | isResolved = true; 112 | resolve(first); // Resolve with 'first' when a bundle is accepted 113 | } 114 | if (isRejected) { 115 | // Do not resolve or reject the promise here 116 | } 117 | } 118 | }, (e) => { 119 | // Do not reject the promise here 120 | }); 121 | }); 122 | }; 123 | exports.onBundleResult = onBundleResult; 124 | -------------------------------------------------------------------------------- /executor/jitoWithAxios.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 26 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 27 | return new (P || (P = Promise))(function (resolve, reject) { 28 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 29 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 30 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 31 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 32 | }); 33 | }; 34 | var __importDefault = (this && this.__importDefault) || function (mod) { 35 | return (mod && mod.__esModule) ? mod : { "default": mod }; 36 | }; 37 | Object.defineProperty(exports, "__esModule", { value: true }); 38 | exports.jitoWithAxios = void 0; 39 | const web3_js_1 = require("@solana/web3.js"); 40 | const utils_1 = require("../utils"); 41 | const constants_1 = require("../constants"); 42 | const bs58_1 = __importDefault(require("bs58")); 43 | const axios_1 = __importStar(require("axios")); 44 | const solanaConnection = new web3_js_1.Connection(constants_1.RPC_ENDPOINT, { 45 | wsEndpoint: constants_1.RPC_WEBSOCKET_ENDPOINT, 46 | }); 47 | const jitoWithAxios = (transaction, payer, latestBlockhash) => __awaiter(void 0, void 0, void 0, function* () { 48 | utils_1.logger.debug('Starting Jito transaction execution...'); 49 | const tipAccounts = [ 50 | 'Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY', 51 | 'DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL', 52 | '96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5', 53 | '3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT', 54 | 'HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe', 55 | 'ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49', 56 | 'ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt', 57 | 'DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh', 58 | ]; 59 | const jitoFeeWallet = new web3_js_1.PublicKey(tipAccounts[Math.floor(tipAccounts.length * Math.random())]); 60 | console.log(`Selected Jito fee wallet: ${jitoFeeWallet.toBase58()}`); 61 | try { 62 | console.log(`Calculated fee: ${constants_1.JITO_FEE / 10 ** 9} sol`); 63 | const jitTipTxFeeMessage = new web3_js_1.TransactionMessage({ 64 | payerKey: payer.publicKey, 65 | recentBlockhash: latestBlockhash.blockhash, 66 | instructions: [ 67 | web3_js_1.SystemProgram.transfer({ 68 | fromPubkey: payer.publicKey, 69 | toPubkey: jitoFeeWallet, 70 | lamports: constants_1.JITO_FEE, 71 | }), 72 | ], 73 | }).compileToV0Message(); 74 | const jitoFeeTx = new web3_js_1.VersionedTransaction(jitTipTxFeeMessage); 75 | jitoFeeTx.sign([payer]); 76 | const jitoTxsignature = bs58_1.default.encode(jitoFeeTx.signatures[0]); 77 | // Serialize the transactions once here 78 | const serializedjitoFeeTx = bs58_1.default.encode(jitoFeeTx.serialize()); 79 | const serializedTransaction = bs58_1.default.encode(transaction.serialize()); 80 | const serializedTransactions = [serializedjitoFeeTx, serializedTransaction]; 81 | const endpoints = [ 82 | 'https://mainnet.block-engine.jito.wtf/api/v1/bundles', 83 | 'https://amsterdam.mainnet.block-engine.jito.wtf/api/v1/bundles', 84 | 'https://frankfurt.mainnet.block-engine.jito.wtf/api/v1/bundles', 85 | 'https://ny.mainnet.block-engine.jito.wtf/api/v1/bundles', 86 | 'https://tokyo.mainnet.block-engine.jito.wtf/api/v1/bundles', 87 | ]; 88 | const requests = endpoints.map((url) => axios_1.default.post(url, { 89 | jsonrpc: '2.0', 90 | id: 1, 91 | method: 'sendBundle', 92 | params: [serializedTransactions], 93 | })); 94 | console.log('Sending transactions to endpoints...'); 95 | const results = yield Promise.all(requests.map((p) => p.catch((e) => e))); 96 | const successfulResults = results.filter((result) => !(result instanceof Error)); 97 | if (successfulResults.length > 0) { 98 | console.log(`Successful response`); 99 | // console.log(`Confirming jito transaction...`); 100 | const confirmation = yield solanaConnection.confirmTransaction({ 101 | signature: jitoTxsignature, 102 | lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, 103 | blockhash: latestBlockhash.blockhash, 104 | }, constants_1.COMMITMENT_LEVEL); 105 | return { confirmed: !confirmation.value.err, jitoTxsignature }; 106 | } 107 | else { 108 | console.log(`No successful responses received for jito`); 109 | } 110 | return { confirmed: false }; 111 | } 112 | catch (error) { 113 | if (error instanceof axios_1.AxiosError) { 114 | console.log('Failed to execute jito transaction'); 115 | } 116 | console.log('Error during transaction execution', error); 117 | return { confirmed: false }; 118 | } 119 | }); 120 | exports.jitoWithAxios = jitoWithAxios; 121 | -------------------------------------------------------------------------------- /utils/getPoolKeys.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __importDefault = (this && this.__importDefault) || function (mod) { 12 | return (mod && mod.__esModule) ? mod : { "default": mod }; 13 | }; 14 | Object.defineProperty(exports, "__esModule", { value: true }); 15 | exports.PoolKeys = void 0; 16 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk"); 17 | const web3_js_1 = require("@solana/web3.js"); 18 | const dotenv_1 = __importDefault(require("dotenv")); 19 | const constants_1 = require("../constants"); 20 | dotenv_1.default.config(); 21 | class PoolKeys { 22 | static fetchMarketId(connection, baseMint, quoteMint, commitment) { 23 | return __awaiter(this, void 0, void 0, function* () { 24 | const accounts = yield connection.getProgramAccounts(new web3_js_1.PublicKey('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX'), { 25 | commitment, 26 | filters: [ 27 | { dataSize: raydium_sdk_1.MARKET_STATE_LAYOUT_V3.span }, 28 | { 29 | memcmp: { 30 | offset: raydium_sdk_1.MARKET_STATE_LAYOUT_V3.offsetOf("baseMint"), 31 | bytes: baseMint.toBase58(), 32 | }, 33 | }, 34 | { 35 | memcmp: { 36 | offset: raydium_sdk_1.MARKET_STATE_LAYOUT_V3.offsetOf("quoteMint"), 37 | bytes: quoteMint.toBase58(), 38 | }, 39 | }, 40 | ], 41 | }); 42 | return accounts.map(({ account }) => raydium_sdk_1.MARKET_STATE_LAYOUT_V3.decode(account.data))[0].ownAddress; 43 | }); 44 | } 45 | static fetchMarketInfo(marketId) { 46 | return __awaiter(this, void 0, void 0, function* () { 47 | const marketAccountInfo = yield this.connection.getAccountInfo(marketId, "processed"); 48 | if (!marketAccountInfo) { 49 | throw new Error('Failed to fetch market info for market id ' + marketId.toBase58()); 50 | } 51 | return raydium_sdk_1.MARKET_STATE_LAYOUT_V3.decode(marketAccountInfo.data); 52 | }); 53 | } 54 | static generateV4PoolInfo(baseMint, baseDecimals, quoteMint, marketID) { 55 | return __awaiter(this, void 0, void 0, function* () { 56 | const poolInfo = raydium_sdk_1.Liquidity.getAssociatedPoolKeys({ 57 | version: 4, 58 | marketVersion: 3, 59 | baseMint: baseMint, 60 | quoteMint: quoteMint, 61 | baseDecimals: 0, 62 | quoteDecimals: this.SOL_DECIMALS, 63 | programId: new web3_js_1.PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'), 64 | marketId: marketID, 65 | marketProgramId: new web3_js_1.PublicKey('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX'), 66 | }); 67 | return { poolInfo }; 68 | }); 69 | } 70 | static fetchPoolKeyInfo(baseMint, quoteMint) { 71 | return __awaiter(this, void 0, void 0, function* () { 72 | const marketId = yield this.fetchMarketId(this.connection, baseMint, quoteMint, 'processed'); 73 | const marketInfo = yield this.fetchMarketInfo(marketId); 74 | const baseMintInfo = yield this.connection.getParsedAccountInfo(baseMint, "processed"); 75 | const baseDecimals = baseMintInfo.value.data.parsed.info.decimals; 76 | const V4PoolInfo = yield this.generateV4PoolInfo(baseMint, baseDecimals, quoteMint, marketId); 77 | const lpMintInfo = yield this.connection.getParsedAccountInfo(V4PoolInfo.poolInfo.lpMint, "processed"); 78 | return { 79 | id: V4PoolInfo.poolInfo.id, 80 | marketId: marketId, 81 | baseMint: baseMint, 82 | quoteMint: quoteMint, 83 | baseVault: V4PoolInfo.poolInfo.baseVault, 84 | quoteVault: V4PoolInfo.poolInfo.quoteVault, 85 | lpMint: V4PoolInfo.poolInfo.lpMint, 86 | baseDecimals: baseDecimals, 87 | quoteDecimals: this.SOL_DECIMALS, 88 | lpDecimals: lpMintInfo.value.data.parsed.info.decimals, 89 | version: 4, 90 | programId: new web3_js_1.PublicKey(this.RAYDIUM_POOL_V4_PROGRAM_ID), 91 | authority: V4PoolInfo.poolInfo.authority, 92 | openOrders: V4PoolInfo.poolInfo.openOrders, 93 | targetOrders: V4PoolInfo.poolInfo.targetOrders, 94 | withdrawQueue: new web3_js_1.PublicKey("11111111111111111111111111111111"), 95 | lpVault: new web3_js_1.PublicKey("11111111111111111111111111111111"), 96 | marketVersion: 3, 97 | marketProgramId: new web3_js_1.PublicKey(this.OPENBOOK_ADDRESS), 98 | marketAuthority: raydium_sdk_1.Market.getAssociatedAuthority({ programId: new web3_js_1.PublicKey(this.OPENBOOK_ADDRESS), marketId: marketId }).publicKey, 99 | marketBaseVault: marketInfo.baseVault, 100 | marketQuoteVault: marketInfo.quoteVault, 101 | marketBids: marketInfo.bids, 102 | marketAsks: marketInfo.asks, 103 | marketEventQueue: marketInfo.eventQueue, 104 | lookupTableAccount: web3_js_1.PublicKey.default 105 | }; 106 | }); 107 | } 108 | } 109 | exports.PoolKeys = PoolKeys; 110 | PoolKeys.SOLANA_ADDRESS = 'So11111111111111111111111111111111111111112'; 111 | PoolKeys.RAYDIUM_POOL_V4_PROGRAM_ID = '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'; 112 | PoolKeys.OPENBOOK_ADDRESS = 'srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX'; 113 | PoolKeys.SOL_DECIMALS = 9; 114 | PoolKeys.connection = new web3_js_1.Connection(constants_1.RPC_ENDPOINT, { 115 | wsEndpoint: constants_1.RPC_WEBSOCKET_ENDPOINT, 116 | }); 117 | -------------------------------------------------------------------------------- /buy.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 26 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 27 | return new (P || (P = Promise))(function (resolve, reject) { 28 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 29 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 30 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 31 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 32 | }); 33 | }; 34 | var __importDefault = (this && this.__importDefault) || function (mod) { 35 | return (mod && mod.__esModule) ? mod : { "default": mod }; 36 | }; 37 | Object.defineProperty(exports, "__esModule", { value: true }); 38 | exports.sell = exports.processOpenBookMarket = exports.checkMintable = exports.processRaydiumPool = void 0; 39 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk"); 40 | const spl_token_1 = require("@solana/spl-token"); 41 | const web3_js_1 = require("@solana/web3.js"); 42 | const liquidity_1 = require("./liquidity"); 43 | const utils_1 = require("./utils"); 44 | const market_1 = require("./market"); 45 | const types_1 = require("./types"); 46 | const bs58_1 = __importDefault(require("bs58")); 47 | const fs = __importStar(require("fs")); 48 | const path = __importStar(require("path")); 49 | const readline_1 = __importDefault(require("readline")); 50 | const constants_1 = require("./constants"); 51 | const bn_js_1 = require("bn.js"); 52 | const tokenFilter_1 = require("./tokenFilter"); 53 | const jito_1 = require("./executor/jito"); 54 | const legacy_1 = require("./executor/legacy"); 55 | const jitoWithAxios_1 = require("./executor/jitoWithAxios"); 56 | const solanaConnection = new web3_js_1.Connection(constants_1.RPC_ENDPOINT, { 57 | wsEndpoint: constants_1.RPC_WEBSOCKET_ENDPOINT, 58 | }); 59 | const rl = readline_1.default.createInterface({ 60 | input: process.stdin, 61 | output: process.stdout 62 | }); 63 | const existingLiquidityPools = new Set(); 64 | const existingOpenBookMarkets = new Set(); 65 | const existingTokenAccounts = new Map(); 66 | let wallet; 67 | let quoteToken; 68 | let quoteTokenAssociatedAddress; 69 | let quoteAmount; 70 | let quoteMinPoolSizeAmount; 71 | let quoteMaxPoolSizeAmount; 72 | let processingToken = false; 73 | let poolId; 74 | let tokenAccountInCommon; 75 | let accountDataInCommon; 76 | let idDealt = spl_token_1.NATIVE_MINT.toBase58(); 77 | let snipeList = []; 78 | let timesChecked = 0; 79 | let soldSome = false; 80 | function init() { 81 | return __awaiter(this, void 0, void 0, function* () { 82 | utils_1.logger.level = constants_1.LOG_LEVEL; 83 | // get wallet 84 | wallet = web3_js_1.Keypair.fromSecretKey(bs58_1.default.decode(constants_1.PRIVATE_KEY)); 85 | const solBalance = yield solanaConnection.getBalance(wallet.publicKey); 86 | console.log(`Wallet Address: ${wallet.publicKey}`); 87 | console.log(`SOL balance: ${(solBalance / 10 ** 9).toFixed(3)}SOL`); 88 | // get quote mint and amount 89 | switch (constants_1.QUOTE_MINT) { 90 | case 'WSOL': { 91 | quoteToken = raydium_sdk_1.Token.WSOL; 92 | quoteAmount = new raydium_sdk_1.TokenAmount(raydium_sdk_1.Token.WSOL, constants_1.QUOTE_AMOUNT, false); 93 | quoteMinPoolSizeAmount = new raydium_sdk_1.TokenAmount(quoteToken, constants_1.MIN_POOL_SIZE, false); 94 | quoteMaxPoolSizeAmount = new raydium_sdk_1.TokenAmount(quoteToken, constants_1.MAX_POOL_SIZE, false); 95 | break; 96 | } 97 | case 'USDC': { 98 | quoteToken = new raydium_sdk_1.Token(spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'), 6, 'USDC', 'USDC'); 99 | quoteAmount = new raydium_sdk_1.TokenAmount(quoteToken, constants_1.QUOTE_AMOUNT, false); 100 | quoteMinPoolSizeAmount = new raydium_sdk_1.TokenAmount(quoteToken, constants_1.MIN_POOL_SIZE, false); 101 | quoteMaxPoolSizeAmount = new raydium_sdk_1.TokenAmount(quoteToken, constants_1.MAX_POOL_SIZE, false); 102 | break; 103 | } 104 | default: { 105 | throw new Error(`Unsupported quote mint "${constants_1.QUOTE_MINT}". Supported values are USDC and WSOL`); 106 | } 107 | } 108 | console.log(`Snipe list: ${constants_1.USE_SNIPE_LIST}`); 109 | console.log(`Check mint renounced: ${constants_1.CHECK_IF_MINT_IS_RENOUNCED}`); 110 | console.log(`Check token socials: ${constants_1.CHECK_SOCIAL}`); 111 | console.log(`Min pool size: ${quoteMinPoolSizeAmount.isZero() ? 'false' : quoteMinPoolSizeAmount.toFixed(2)} ${quoteToken.symbol}`); 112 | console.log(`Max pool size: ${quoteMaxPoolSizeAmount.isZero() ? 'false' : quoteMaxPoolSizeAmount.toFixed(2)} ${quoteToken.symbol}`); 113 | console.log(`One token at a time: ${constants_1.ONE_TOKEN_AT_A_TIME}`); 114 | console.log(`Buy amount: ${quoteAmount.toFixed()} ${quoteToken.symbol}`); 115 | // check existing wallet for associated token account of quote mint 116 | const tokenAccounts = yield (0, liquidity_1.getTokenAccounts)(solanaConnection, wallet.publicKey, constants_1.COMMITMENT_LEVEL); 117 | for (const ta of tokenAccounts) { 118 | existingTokenAccounts.set(ta.accountInfo.mint.toString(), { 119 | mint: ta.accountInfo.mint, 120 | address: ta.pubkey, 121 | }); 122 | } 123 | quoteTokenAssociatedAddress = yield (0, spl_token_1.getAssociatedTokenAddress)(spl_token_1.NATIVE_MINT, wallet.publicKey); 124 | const wsolBalance = yield solanaConnection.getBalance(quoteTokenAssociatedAddress); 125 | console.log(`WSOL Balance: ${wsolBalance}`); 126 | if (!(!wsolBalance || wsolBalance == 0)) 127 | // await unwrapSol(quoteTokenAssociatedAddress) 128 | // load tokens to snipe 129 | loadSnipeList(); 130 | }); 131 | } 132 | function saveTokenAccount(mint, accountData) { 133 | const ata = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, wallet.publicKey); 134 | const tokenAccount = { 135 | address: ata, 136 | mint: mint, 137 | market: { 138 | bids: accountData.bids, 139 | asks: accountData.asks, 140 | eventQueue: accountData.eventQueue, 141 | }, 142 | }; 143 | existingTokenAccounts.set(mint.toString(), tokenAccount); 144 | return tokenAccount; 145 | } 146 | function processRaydiumPool(id, poolState) { 147 | return __awaiter(this, void 0, void 0, function* () { 148 | if (idDealt == id.toString()) 149 | return; 150 | idDealt = id.toBase58(); 151 | try { 152 | const quoteBalance = (yield solanaConnection.getBalance(poolState.quoteVault, "processed")) / 10 ** 9; 153 | if (!shouldBuy(poolState.baseMint.toString())) { 154 | return; 155 | } 156 | console.log(`Detected a new pool: https://dexscreener.com/solana/${id.toString()}`); 157 | if (!quoteMinPoolSizeAmount.isZero()) { 158 | console.log(`Processing pool: ${id.toString()} with ${quoteBalance.toFixed(2)} ${quoteToken.symbol} in liquidity`); 159 | // if (poolSize.lt(quoteMinPoolSizeAmount)) { 160 | if (parseFloat(constants_1.MIN_POOL_SIZE) > quoteBalance) { 161 | console.log(`Skipping pool, smaller than ${constants_1.MIN_POOL_SIZE} ${quoteToken.symbol}`); 162 | console.log(`-------------------------------------- \n`); 163 | return; 164 | } 165 | } 166 | if (!quoteMaxPoolSizeAmount.isZero()) { 167 | const poolSize = new raydium_sdk_1.TokenAmount(quoteToken, poolState.swapQuoteInAmount, true); 168 | // if (poolSize.gt(quoteMaxPoolSizeAmount)) { 169 | if (parseFloat(constants_1.MAX_POOL_SIZE) < quoteBalance) { 170 | console.log(`Skipping pool, larger than ${constants_1.MIN_POOL_SIZE} ${quoteToken.symbol}`); 171 | console.log(`Skipping pool, bigger than ${quoteMaxPoolSizeAmount.toFixed()} ${quoteToken.symbol}`, `Swap quote in amount: ${poolSize.toFixed()}`); 172 | console.log(`-------------------------------------- \n`); 173 | return; 174 | } 175 | } 176 | } 177 | catch (error) { 178 | console.log(`Error in getting new pool balance, ${error}`); 179 | } 180 | if (constants_1.CHECK_IF_MINT_IS_RENOUNCED) { 181 | const mintOption = yield checkMintable(poolState.baseMint); 182 | if (mintOption !== true) { 183 | console.log('Skipping, owner can mint tokens!', poolState.baseMint); 184 | return; 185 | } 186 | } 187 | if (constants_1.CHECK_SOCIAL) { 188 | const isSocial = yield (0, tokenFilter_1.checkSocial)(solanaConnection, poolState.baseMint, constants_1.COMMITMENT_LEVEL); 189 | if (isSocial !== true) { 190 | console.log('Skipping, token does not have socials', poolState.baseMint); 191 | return; 192 | } 193 | } 194 | if (constants_1.CHECK_IF_MINT_IS_MUTABLE) { 195 | const mutable = yield (0, tokenFilter_1.checkMutable)(solanaConnection, poolState.baseMint); 196 | if (mutable == true) { 197 | console.log('Skipping, token is mutable!', poolState.baseMint); 198 | return; 199 | } 200 | } 201 | if (constants_1.CHECK_IF_MINT_IS_BURNED) { 202 | const burned = yield (0, tokenFilter_1.checkBurn)(solanaConnection, poolState.lpMint, constants_1.COMMITMENT_LEVEL); 203 | if (burned !== true) { 204 | console.log('Skipping, token is not burned!', poolState.baseMint); 205 | return; 206 | } 207 | } 208 | processingToken = true; 209 | yield buy(id, poolState); 210 | }); 211 | } 212 | exports.processRaydiumPool = processRaydiumPool; 213 | function checkMintable(vault) { 214 | return __awaiter(this, void 0, void 0, function* () { 215 | try { 216 | let { data } = (yield solanaConnection.getAccountInfo(vault)) || {}; 217 | if (!data) { 218 | return; 219 | } 220 | const deserialize = types_1.MintLayout.decode(data); 221 | return deserialize.mintAuthorityOption === 0; 222 | } 223 | catch (e) { 224 | utils_1.logger.debug(e); 225 | console.log(`Failed to check if mint is renounced`, vault); 226 | } 227 | }); 228 | } 229 | exports.checkMintable = checkMintable; 230 | function processOpenBookMarket(updatedAccountInfo) { 231 | return __awaiter(this, void 0, void 0, function* () { 232 | let accountData; 233 | try { 234 | accountData = raydium_sdk_1.MARKET_STATE_LAYOUT_V3.decode(updatedAccountInfo.accountInfo.data); 235 | // to be competitive, we collect market data before buying the token... 236 | if (existingTokenAccounts.has(accountData.baseMint.toString())) { 237 | return; 238 | } 239 | saveTokenAccount(accountData.baseMint, accountData); 240 | } 241 | catch (e) { 242 | utils_1.logger.debug(e); 243 | console.log(`Failed to process market, mint: `, accountData === null || accountData === void 0 ? void 0 : accountData.baseMint); 244 | } 245 | }); 246 | } 247 | exports.processOpenBookMarket = processOpenBookMarket; 248 | function buy(accountId, accountData) { 249 | return __awaiter(this, void 0, void 0, function* () { 250 | console.log(`Buy action triggered`); 251 | try { 252 | let tokenAccount = existingTokenAccounts.get(accountData.baseMint.toString()); 253 | tokenAccountInCommon = tokenAccount; 254 | accountDataInCommon = accountData; 255 | if (!tokenAccount) { 256 | // it's possible that we didn't have time to fetch open book data 257 | const market = yield (0, market_1.getMinimalMarketV3)(solanaConnection, accountData.marketId, constants_1.COMMITMENT_LEVEL); 258 | tokenAccount = saveTokenAccount(accountData.baseMint, market); 259 | } 260 | tokenAccount.poolKeys = (0, liquidity_1.createPoolKeys)(accountId, accountData, tokenAccount.market); 261 | const { innerTransaction } = raydium_sdk_1.Liquidity.makeSwapFixedInInstruction({ 262 | poolKeys: tokenAccount.poolKeys, 263 | userKeys: { 264 | tokenAccountIn: quoteTokenAssociatedAddress, 265 | tokenAccountOut: tokenAccount.address, 266 | owner: wallet.publicKey, 267 | }, 268 | amountIn: quoteAmount.raw, 269 | minAmountOut: 0, 270 | }, tokenAccount.poolKeys.version); 271 | const latestBlockhash = yield solanaConnection.getLatestBlockhash({ 272 | commitment: constants_1.COMMITMENT_LEVEL, 273 | }); 274 | const instructions = []; 275 | if (!(yield solanaConnection.getAccountInfo(quoteTokenAssociatedAddress))) 276 | instructions.push((0, spl_token_1.createAssociatedTokenAccountInstruction)(wallet.publicKey, quoteTokenAssociatedAddress, wallet.publicKey, spl_token_1.NATIVE_MINT)); 277 | instructions.push(web3_js_1.SystemProgram.transfer({ 278 | fromPubkey: wallet.publicKey, 279 | toPubkey: quoteTokenAssociatedAddress, 280 | lamports: Math.ceil(parseFloat(constants_1.QUOTE_AMOUNT) * 10 ** 9), 281 | }), (0, spl_token_1.createSyncNativeInstruction)(quoteTokenAssociatedAddress, spl_token_1.TOKEN_PROGRAM_ID), (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, tokenAccount.address, wallet.publicKey, accountData.baseMint), ...innerTransaction.instructions); 282 | const messageV0 = new web3_js_1.TransactionMessage({ 283 | payerKey: wallet.publicKey, 284 | recentBlockhash: latestBlockhash.blockhash, 285 | instructions, 286 | }).compileToV0Message(); 287 | const transaction = new web3_js_1.VersionedTransaction(messageV0); 288 | transaction.sign([wallet, ...innerTransaction.signers]); 289 | if (constants_1.JITO_MODE) { 290 | if (constants_1.JITO_ALL) { 291 | yield (0, jitoWithAxios_1.jitoWithAxios)(transaction, wallet, latestBlockhash); 292 | } 293 | else { 294 | const result = yield (0, jito_1.bundle)([transaction], wallet); 295 | } 296 | } 297 | else { 298 | yield (0, legacy_1.execute)(transaction, latestBlockhash); 299 | } 300 | } 301 | catch (e) { 302 | utils_1.logger.debug(e); 303 | console.log(`Failed to buy token, ${accountData.baseMint}`); 304 | } 305 | }); 306 | } 307 | function sell(mint_1, amount_1) { 308 | return __awaiter(this, arguments, void 0, function* (mint, amount, isTp1Sell = false) { 309 | try { 310 | const tokenAccount = existingTokenAccounts.get(mint.toString()); 311 | if (!tokenAccount) { 312 | console.log("Sell token account not exist"); 313 | return; 314 | } 315 | if (!tokenAccount.poolKeys) { 316 | console.log('No pool keys found: ', mint); 317 | return; 318 | } 319 | if (amount == "0") { 320 | console.log(`Checking: Sold already`, tokenAccount.mint); 321 | return; 322 | } 323 | const { innerTransaction } = raydium_sdk_1.Liquidity.makeSwapFixedInInstruction({ 324 | poolKeys: tokenAccount.poolKeys, 325 | userKeys: { 326 | tokenAccountOut: quoteTokenAssociatedAddress, 327 | tokenAccountIn: tokenAccount.address, 328 | owner: wallet.publicKey, 329 | }, 330 | amountIn: amount, 331 | minAmountOut: 0, 332 | }, tokenAccount.poolKeys.version); 333 | const tx = new web3_js_1.Transaction().add(...innerTransaction.instructions); 334 | tx.feePayer = wallet.publicKey; 335 | tx.recentBlockhash = (yield solanaConnection.getLatestBlockhash()).blockhash; 336 | const latestBlockhash = yield solanaConnection.getLatestBlockhash({ 337 | commitment: constants_1.COMMITMENT_LEVEL, 338 | }); 339 | const messageV0 = new web3_js_1.TransactionMessage({ 340 | payerKey: wallet.publicKey, 341 | recentBlockhash: latestBlockhash.blockhash, 342 | instructions: [ 343 | ...innerTransaction.instructions, 344 | (0, spl_token_1.createCloseAccountInstruction)(quoteTokenAssociatedAddress, wallet.publicKey, wallet.publicKey), 345 | ], 346 | }).compileToV0Message(); 347 | const transaction = new web3_js_1.VersionedTransaction(messageV0); 348 | transaction.sign([wallet, ...innerTransaction.signers]); 349 | if (constants_1.JITO_MODE) { 350 | if (constants_1.JITO_ALL) { 351 | yield (0, jitoWithAxios_1.jitoWithAxios)(transaction, wallet, latestBlockhash); 352 | } 353 | else { 354 | yield (0, jito_1.bundle)([transaction], wallet); 355 | } 356 | } 357 | else { 358 | yield (0, legacy_1.execute)(transaction, latestBlockhash); 359 | } 360 | } 361 | catch (e) { 362 | yield sleep(1000); 363 | utils_1.logger.debug(e); 364 | } 365 | if (!isTp1Sell) { 366 | yield sell(mint, amount, true); 367 | processingToken = false; 368 | } 369 | }); 370 | } 371 | exports.sell = sell; 372 | function loadSnipeList() { 373 | if (!constants_1.USE_SNIPE_LIST) { 374 | return; 375 | } 376 | const count = snipeList.length; 377 | const data = fs.readFileSync(path.join(__dirname, 'snipe-list.txt'), 'utf-8'); 378 | snipeList = data 379 | .split('\n') 380 | .map((a) => a.trim()) 381 | .filter((a) => a); 382 | if (snipeList.length != count) { 383 | console.log(`Loaded snipe list: ${snipeList.length}`); 384 | } 385 | } 386 | function shouldBuy(key) { 387 | return constants_1.USE_SNIPE_LIST ? snipeList.includes(key) : constants_1.ONE_TOKEN_AT_A_TIME ? !processingToken : true; 388 | } 389 | const runListener = () => __awaiter(void 0, void 0, void 0, function* () { 390 | yield init(); 391 | trackWallet(solanaConnection); 392 | const runTimestamp = Math.floor(new Date().getTime() / 1000); 393 | const raydiumSubscriptionId = solanaConnection.onProgramAccountChange(liquidity_1.RAYDIUM_LIQUIDITY_PROGRAM_ID_V4, (updatedAccountInfo) => __awaiter(void 0, void 0, void 0, function* () { 394 | const key = updatedAccountInfo.accountId.toString(); 395 | const poolState = raydium_sdk_1.LIQUIDITY_STATE_LAYOUT_V4.decode(updatedAccountInfo.accountInfo.data); 396 | const poolOpenTime = parseInt(poolState.poolOpenTime.toString()); 397 | const existing = existingLiquidityPools.has(key); 398 | if (poolOpenTime > runTimestamp && !existing) { 399 | existingLiquidityPools.add(key); 400 | const _ = processRaydiumPool(updatedAccountInfo.accountId, poolState); 401 | poolId = updatedAccountInfo.accountId; 402 | } 403 | }), constants_1.COMMITMENT_LEVEL, [ 404 | { dataSize: raydium_sdk_1.LIQUIDITY_STATE_LAYOUT_V4.span }, 405 | { 406 | memcmp: { 407 | offset: raydium_sdk_1.LIQUIDITY_STATE_LAYOUT_V4.offsetOf('quoteMint'), 408 | bytes: quoteToken.mint.toBase58(), 409 | }, 410 | }, 411 | { 412 | memcmp: { 413 | offset: raydium_sdk_1.LIQUIDITY_STATE_LAYOUT_V4.offsetOf('marketProgramId'), 414 | bytes: liquidity_1.OPENBOOK_PROGRAM_ID.toBase58(), 415 | }, 416 | }, 417 | { 418 | memcmp: { 419 | offset: raydium_sdk_1.LIQUIDITY_STATE_LAYOUT_V4.offsetOf('status'), 420 | bytes: bs58_1.default.encode([6, 0, 0, 0, 0, 0, 0, 0]), 421 | }, 422 | }, 423 | ]); 424 | const openBookSubscriptionId = solanaConnection.onProgramAccountChange(liquidity_1.OPENBOOK_PROGRAM_ID, (updatedAccountInfo) => __awaiter(void 0, void 0, void 0, function* () { 425 | const key = updatedAccountInfo.accountId.toString(); 426 | const existing = existingOpenBookMarkets.has(key); 427 | if (!existing) { 428 | existingOpenBookMarkets.add(key); 429 | const _ = processOpenBookMarket(updatedAccountInfo); 430 | } 431 | }), constants_1.COMMITMENT_LEVEL, [ 432 | { dataSize: raydium_sdk_1.MARKET_STATE_LAYOUT_V3.span }, 433 | { 434 | memcmp: { 435 | offset: raydium_sdk_1.MARKET_STATE_LAYOUT_V3.offsetOf('quoteMint'), 436 | bytes: quoteToken.mint.toBase58(), 437 | }, 438 | }, 439 | ]); 440 | const walletSubscriptionId = solanaConnection.onProgramAccountChange(spl_token_1.TOKEN_PROGRAM_ID, (updatedAccountInfo) => __awaiter(void 0, void 0, void 0, function* () { 441 | yield walletChange(updatedAccountInfo); 442 | }), constants_1.COMMITMENT_LEVEL, [ 443 | { 444 | dataSize: 165, 445 | }, 446 | { 447 | memcmp: { 448 | offset: 32, 449 | bytes: wallet.publicKey.toBase58(), 450 | }, 451 | }, 452 | ]); 453 | console.log(`Listening for wallet changes: ${walletSubscriptionId}`); 454 | // } 455 | console.log(`Listening for raydium changes: ${raydiumSubscriptionId}`); 456 | console.log(`Listening for open book changes: ${openBookSubscriptionId}`); 457 | console.log('----------------------------------------'); 458 | console.log('Bot is running! Press CTRL + C to stop it.'); 459 | console.log('----------------------------------------'); 460 | if (constants_1.USE_SNIPE_LIST) { 461 | setInterval(loadSnipeList, constants_1.SNIPE_LIST_REFRESH_INTERVAL); 462 | } 463 | }); 464 | const unwrapSol = (wSolAccount) => __awaiter(void 0, void 0, void 0, function* () { 465 | try { 466 | const wsolAccountInfo = yield solanaConnection.getAccountInfo(wSolAccount); 467 | if (wsolAccountInfo) { 468 | const wsolBalanace = yield solanaConnection.getBalance(wSolAccount); 469 | console.log(`Trying to unwrap ${wsolBalanace / 10 ** 9}wsol to sol`); 470 | const instructions = []; 471 | instructions.push((0, spl_token_1.createCloseAccountInstruction)(wSolAccount, wallet.publicKey, wallet.publicKey)); 472 | const latestBlockhash = yield solanaConnection.getLatestBlockhash({ 473 | commitment: constants_1.COMMITMENT_LEVEL, 474 | }); 475 | const messageV0 = new web3_js_1.TransactionMessage({ 476 | payerKey: wallet.publicKey, 477 | recentBlockhash: latestBlockhash.blockhash, 478 | instructions: [...instructions], 479 | }).compileToV0Message(); 480 | const transaction = new web3_js_1.VersionedTransaction(messageV0); 481 | transaction.sign([wallet]); 482 | if (constants_1.JITO_MODE) { 483 | if (constants_1.JITO_ALL) { 484 | const result = yield (0, jitoWithAxios_1.jitoWithAxios)(transaction, wallet, latestBlockhash); 485 | } 486 | else { 487 | const result = yield (0, jito_1.bundle)([transaction], wallet); 488 | } 489 | } 490 | else { 491 | yield (0, legacy_1.execute)(transaction, latestBlockhash); 492 | } 493 | yield sleep(5000); 494 | const wBal = yield solanaConnection.getBalance(wSolAccount); 495 | if (wBal > 0) { 496 | console.log("Unwrapping WSOL failed"); 497 | } 498 | else { 499 | console.log("Successfully unwrapped WSOL to SOL"); 500 | } 501 | } 502 | } 503 | catch (error) { 504 | console.log("Error unwrapping WSOL"); 505 | } 506 | }); 507 | const inputAction = (accountId, mint, amount) => __awaiter(void 0, void 0, void 0, function* () { 508 | console.log("\n\n\n==========================================================\n\n\n"); 509 | rl.question('If you want to sell, plz input "sell" and press enter: \n\n', (data) => __awaiter(void 0, void 0, void 0, function* () { 510 | const input = data.toString().trim(); 511 | if (input === 'sell') { 512 | timesChecked = 1000000; 513 | } 514 | else { 515 | console.log('Received input invalid :\t', input); 516 | inputAction(accountId, mint, amount); 517 | } 518 | })); 519 | }); 520 | const priceMatch = (amountIn, poolKeys) => __awaiter(void 0, void 0, void 0, function* () { 521 | try { 522 | if (constants_1.PRICE_CHECK_DURATION === 0 || constants_1.PRICE_CHECK_INTERVAL === 0) { 523 | return; 524 | } 525 | let priceMatchAtOne = false; 526 | const timesToCheck = constants_1.PRICE_CHECK_DURATION / constants_1.PRICE_CHECK_INTERVAL; 527 | const temp = amountIn.raw.toString(); 528 | const tokenAmount = new bn_js_1.BN(temp.substring(0, temp.length - 2)); 529 | const sellAt1 = tokenAmount.mul(new bn_js_1.BN(constants_1.SELL_AT_TP1)).toString(); 530 | const slippage = new raydium_sdk_1.Percent(constants_1.SELL_SLIPPAGE, 100); 531 | const tp1 = Number((Number(constants_1.QUOTE_AMOUNT) * (100 + constants_1.TAKE_PROFIT1) / 100).toFixed(4)); 532 | const tp2 = Number((Number(constants_1.QUOTE_AMOUNT) * (100 + constants_1.TAKE_PROFIT2) / 100).toFixed(4)); 533 | const sl = Number((Number(constants_1.QUOTE_AMOUNT) * (100 - constants_1.STOP_LOSS) / 100).toFixed(4)); 534 | timesChecked = 0; 535 | do { 536 | try { 537 | const poolInfo = yield raydium_sdk_1.Liquidity.fetchInfo({ 538 | connection: solanaConnection, 539 | poolKeys, 540 | }); 541 | const { amountOut } = raydium_sdk_1.Liquidity.computeAmountOut({ 542 | poolKeys, 543 | poolInfo, 544 | amountIn, 545 | currencyOut: quoteToken, 546 | slippage, 547 | }); 548 | const pnl = (Number(amountOut.toFixed(6)) - Number(constants_1.QUOTE_AMOUNT)) / Number(constants_1.QUOTE_AMOUNT) * 100; 549 | if (timesChecked > 0) { 550 | (0, utils_1.deleteConsoleLines)(1); 551 | } 552 | const data = yield getPrice(); 553 | if (data) { 554 | const { priceUsd, liquidity, fdv, txns, marketCap, pairCreatedAt, volume_m5, volume_h1, volume_h6, priceChange_m5, priceChange_h1, priceChange_h6 } = data; 555 | // console.log(`Take profit1: ${tp1} SOL | Take profit2: ${tp2} SOL | Stop loss: ${sl} SOL | Buy amount: ${QUOTE_AMOUNT} SOL | Current: ${amountOut.toFixed(4)} SOL | PNL: ${pnl.toFixed(3)}%`) 556 | console.log(`TP1: ${tp1} | TP2: ${tp2} | SL: ${sl} | Lq: $${(liquidity.usd / 1000).toFixed(3)}K | MC: $${(marketCap / 1000).toFixed(3)}K | Price: $${Number(priceUsd).toFixed(3)} | 5M: ${priceChange_m5}% | 1H: ${priceChange_h1}% | TXs: ${(txns.h1.buys + txns.h1.sells)} | Buy: ${txns.h1.buys} | Sell: ${txns.h1.sells} | Vol: $${(volume_h1 / 1000).toFixed(3)}K`); 557 | } 558 | const amountOutNum = Number(amountOut.toFixed(7)); 559 | if (amountOutNum < sl) { 560 | console.log("Token is on stop loss point, will sell with loss"); 561 | break; 562 | } 563 | // if (amountOutNum > tp1) { 564 | if (pnl > constants_1.TAKE_PROFIT1) { 565 | if (!priceMatchAtOne) { 566 | console.log("Token is on first level profit, will sell some and wait for second level higher profit"); 567 | priceMatchAtOne = true; 568 | soldSome = true; 569 | sell(poolKeys.baseMint, sellAt1, true); 570 | // break 571 | } 572 | } 573 | // if (amountOutNum < tp1 && priceMatchAtOne) { 574 | if (pnl < constants_1.TAKE_PROFIT1 && priceMatchAtOne) { 575 | console.log("Token is on first level profit again, will sell with first level"); 576 | break; 577 | } 578 | // if (amountOutNum > tp2) { 579 | if (pnl > constants_1.TAKE_PROFIT2) { 580 | console.log("Token is on second level profit, will sell with second level profit"); 581 | break; 582 | } 583 | } 584 | catch (e) { 585 | } 586 | finally { 587 | timesChecked++; 588 | } 589 | yield sleep(constants_1.PRICE_CHECK_INTERVAL); 590 | } while (timesChecked < timesToCheck); 591 | } 592 | catch (error) { 593 | console.log("Error when setting profit amounts", error); 594 | } 595 | }); 596 | const sleep = (ms) => __awaiter(void 0, void 0, void 0, function* () { 597 | yield new Promise((resolve) => setTimeout(resolve, ms)); 598 | }); 599 | let bought = spl_token_1.NATIVE_MINT.toBase58(); 600 | const walletChange = (updatedAccountInfo) => __awaiter(void 0, void 0, void 0, function* () { 601 | const accountData = spl_token_1.AccountLayout.decode(updatedAccountInfo.accountInfo.data); 602 | if (updatedAccountInfo.accountId.equals(quoteTokenAssociatedAddress)) { 603 | return; 604 | } 605 | if (tokenAccountInCommon && accountDataInCommon) { 606 | if (bought != accountDataInCommon.baseMint.toBase58()) { 607 | console.log(`\n--------------- bought token successfully ---------------------- \n`); 608 | console.log(`https://dexscreener.com/solana/${accountDataInCommon.baseMint.toBase58()}`); 609 | console.log(`PHOTON: https://photon-sol.tinyastro.io/en/lp/${tokenAccountInCommon.poolKeys.id.toString()}`); 610 | console.log(`DEXSCREENER: https://dexscreener.com/solana/${tokenAccountInCommon.poolKeys.id.toString()}`); 611 | console.log(`JUPITER: https://jup.ag/swap/${accountDataInCommon.baseMint.toBase58()}-SOL`); 612 | console.log(`BIRDEYE: https://birdeye.so/token/${accountDataInCommon.baseMint.toBase58()}?chain=solana\n\n`); 613 | bought = accountDataInCommon.baseMint.toBase58(); 614 | const tokenAccount = yield (0, spl_token_1.getAssociatedTokenAddress)(accountData.mint, wallet.publicKey); 615 | const tokenBalance = yield getTokenBalance(tokenAccount); 616 | if (tokenBalance == "0") { 617 | console.log(`Detected a new pool, but didn't confirm buy action`); 618 | return; 619 | } 620 | const tokenIn = new raydium_sdk_1.Token(spl_token_1.TOKEN_PROGRAM_ID, tokenAccountInCommon.poolKeys.baseMint, tokenAccountInCommon.poolKeys.baseDecimals); 621 | const tokenAmountIn = new raydium_sdk_1.TokenAmount(tokenIn, tokenBalance, true); 622 | inputAction(updatedAccountInfo.accountId, accountData.mint, tokenBalance); 623 | yield priceMatch(tokenAmountIn, tokenAccountInCommon.poolKeys); 624 | const tokenBalanceAfterCheck = yield getTokenBalance(tokenAccount); 625 | if (tokenBalanceAfterCheck == "0") { 626 | return; 627 | } 628 | if (soldSome) { 629 | soldSome = false; 630 | const _ = yield sell(tokenAccountInCommon.poolKeys.baseMint, tokenBalanceAfterCheck); 631 | } 632 | else { 633 | const _ = yield sell(tokenAccountInCommon.poolKeys.baseMint, accountData.amount); 634 | } 635 | } 636 | } 637 | }); 638 | const getTokenBalance = (tokenAccount) => __awaiter(void 0, void 0, void 0, function* () { 639 | let tokenBalance = "0"; 640 | let index = 0; 641 | do { 642 | try { 643 | const tokenBal = (yield solanaConnection.getTokenAccountBalance(tokenAccount, 'processed')).value; 644 | const uiAmount = tokenBal.uiAmount; 645 | if (index > 10) { 646 | break; 647 | } 648 | if (uiAmount && uiAmount > 0) { 649 | tokenBalance = tokenBal.amount; 650 | console.log(`Token balance is ${uiAmount}`); 651 | break; 652 | } 653 | yield sleep(1000); 654 | index++; 655 | } 656 | catch (error) { 657 | yield sleep(500); 658 | } 659 | } while (true); 660 | return tokenBalance; 661 | }); 662 | function trackWallet(connection) { 663 | return __awaiter(this, void 0, void 0, function* () { 664 | try { 665 | const wsolAta = yield (0, spl_token_1.getAssociatedTokenAddress)(spl_token_1.NATIVE_MINT, wallet.publicKey); 666 | connection.onLogs(wsolAta, (_a) => __awaiter(this, [_a], void 0, function* ({ logs, err, signature }) { 667 | if (err) 668 | console.log("Transaction failed"); 669 | else { 670 | console.log(`\nTransaction success: https://solscan.io/tx/${signature}\n`); 671 | } 672 | }), "confirmed"); 673 | } 674 | catch (error) { 675 | console.log("Transaction error : ", error); 676 | } 677 | }); 678 | } 679 | const getPrice = () => __awaiter(void 0, void 0, void 0, function* () { 680 | if (!poolId) 681 | return; 682 | try { 683 | // let poolId = new PublicKey("13bqEPVQewKAVbprEZVgqkmaCgSMsdBN9up5xfvLtXDV") 684 | const res = yield fetch(`https://api.dexscreener.com/latest/dex/pairs/solana/${poolId === null || poolId === void 0 ? void 0 : poolId.toBase58()}`, { 685 | method: 'GET', 686 | headers: { 687 | Accept: 'application/json', 688 | 'Content-Type': 'application/json' 689 | } 690 | }); 691 | const data = yield res.clone().json(); 692 | if (!data.pair) { 693 | return; 694 | } 695 | // console.log("🚀 ~ getprice ~ data:", data) 696 | // console.log("price data => ", data.pair.priceUsd) 697 | const { priceUsd, priceNative, volume, priceChange, liquidity, fdv, marketCap, pairCreatedAt, txns } = data.pair; 698 | const { m5: volume_m5, h1: volume_h1, h6: volume_h6 } = volume; 699 | const { m5: priceChange_m5, h1: priceChange_h1, h6: priceChange_h6 } = priceChange; 700 | // console.log(`Lq: $${(liquidity.usd / 1000).toFixed(3)}K | MC: $${(marketCap / 1000).toFixed(3)}K | Price: $${Number(priceUsd).toFixed(3)} | 5M: ${priceChange_m5}% | 1H: ${priceChange_h1}% | TXs: ${txns.h1.buys + txns.h1.sells} | Buy: ${txns.h1.buys} | Sell: ${txns.h1.sells} | Vol: $${(volume_h1 / 1000).toFixed(3)}K`) 701 | // console.log(`${priceUsd} ${priceNative} ${liquidity.usd} ${fdv} ${marketCap} ${pairCreatedAt} ${volume_m5} ${volume_h1} ${volume_h6} ${priceChange_m5} ${priceChange_h1} ${priceChange_h6}`) 702 | return { 703 | priceUsd, 704 | priceNative, 705 | liquidity, 706 | fdv, 707 | txns, 708 | marketCap, 709 | pairCreatedAt, 710 | volume_m5, 711 | volume_h1, 712 | volume_h6, 713 | priceChange_m5, 714 | priceChange_h1, 715 | priceChange_h6 716 | }; 717 | } 718 | catch (e) { 719 | console.log("error in fetching price of pool", e); 720 | return; 721 | } 722 | }); 723 | runListener(); 724 | // getPrice() 725 | --------------------------------------------------------------------------------