├── .gitignore ├── LICENSE.txt ├── README.md ├── dist ├── cjs │ ├── index.d.ts │ ├── index.js │ ├── lib │ │ ├── jito.d.ts │ │ ├── jito.js │ │ ├── sender.d.ts │ │ ├── sender.js │ │ ├── signature.d.ts │ │ ├── signature.js │ │ ├── wait.d.ts │ │ └── wait.js │ ├── package.json │ ├── tests │ │ ├── example.d.ts │ │ └── example.js │ ├── types.d.ts │ └── types.js ├── esm │ ├── index.d.ts │ ├── index.js │ ├── lib │ │ ├── jito.d.ts │ │ ├── jito.js │ │ ├── sender.d.ts │ │ ├── sender.js │ │ ├── signature.d.ts │ │ ├── signature.js │ │ ├── wait.d.ts │ │ └── wait.js │ ├── package.json │ ├── tests │ │ ├── example.d.ts │ │ └── example.js │ ├── types.d.ts │ └── types.js ├── types │ ├── index.d.ts │ ├── lib │ │ ├── jito.d.ts │ │ ├── sender.d.ts │ │ ├── signature.d.ts │ │ └── wait.d.ts │ ├── tests │ │ └── example.d.ts │ └── types.d.ts └── umd │ ├── index.d.ts │ ├── index.js │ ├── lib │ ├── jito.d.ts │ ├── jito.js │ ├── sender.d.ts │ ├── sender.js │ ├── signature.d.ts │ ├── signature.js │ ├── wait.d.ts │ └── wait.js │ ├── tests │ ├── example.d.ts │ └── example.js │ ├── types.d.ts │ └── types.js ├── package-lock.json ├── package.cjs.json ├── package.esm.json ├── package.json ├── src ├── index.ts ├── lib │ ├── jito.ts │ ├── sender.ts │ ├── signature.ts │ └── wait.ts ├── tests │ └── example.ts └── types.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 - Solana Tracker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Solana Swap 2 | 3 | > The most efficient solution for integrating Solana-based token swaps into your projects. 4 | 5 | ![Solana Swap](https://img.shields.io/npm/v/solana-swap) 6 | ![License](https://img.shields.io/npm/l/solana-swap) 7 | ![Downloads](https://img.shields.io/npm/dm/solana-swap) 8 | 9 | ## Overview 10 | 11 | Solana Swap provides a streamlined API for executing token swaps on the Solana blockchain. Built and maintained by [Solana Tracker](https://www.solanatracker.io), this library offers fast market updates and comprehensive access to multiple Solana DEXs through a unified interface. 12 | 13 | ## Features 14 | 15 | - **Fast Market Updates**: Fastest Solana swap api available. 16 | - **Multi-DEX Support**: Integrated with major Solana DEXs 17 | - **High Performance**: Optimized for speed and reliability, even during network congestion 18 | - **Developer-Friendly**: Simple interface with comprehensive documentation 19 | - **Jito Integration**: Support for Jito bundles for MEV protection 20 | 21 | ## Supported DEXs 22 | 23 | - Raydium 24 | - Raydium CPMM 25 | - Pump.fun 26 | - Pump.fun CLMM 27 | - Meteora Dynamic 28 | - Moonshot 29 | - Orca 30 | - Jupiter (Private Self-Hosted API) 31 | 32 | ## Installation 33 | 34 | ```bash 35 | # Using npm 36 | npm install solana-swap 37 | 38 | # Using yarn 39 | yarn add solana-swap 40 | 41 | # Using pnpm 42 | pnpm add solana-swap 43 | ``` 44 | 45 | Or clone the repository: 46 | 47 | ```bash 48 | git clone https://github.com/YZYLAB/solana-swap.git 49 | ``` 50 | 51 | ## Quick Start 52 | 53 | ```javascript 54 | import { Keypair } from "@solana/web3.js"; 55 | import bs58 from "bs58"; 56 | import { SolanaTracker } from "solana-swap"; 57 | 58 | async function swap() { 59 | // Initialize wallet 60 | const keypair = Keypair.fromSecretKey( 61 | bs58.decode("YOUR_SECRET_KEY_HERE") 62 | ); 63 | 64 | // Create instance with RPC endpoint 65 | const solanaTracker = new SolanaTracker( 66 | keypair, 67 | "https://rpc.solanatracker.io/public?advancedTx=true" 68 | ); 69 | 70 | // Get swap instructions 71 | const swapResponse = await solanaTracker.getSwapInstructions( 72 | "So11111111111111111111111111111111111111112", // From Token (SOL) 73 | "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", // To Token 74 | 0.0001, // Amount to swap 75 | 30, // Slippage (%) 76 | keypair.publicKey.toBase58(), // Payer public key 77 | 0.0005, // Priority fee 78 | ); 79 | 80 | // Execute the swap 81 | try { 82 | const txid = await solanaTracker.performSwap(swapResponse, { 83 | sendOptions: { skipPreflight: true }, 84 | confirmationRetries: 30, 85 | confirmationRetryTimeout: 500, 86 | lastValidBlockHeightBuffer: 150, 87 | resendInterval: 1000, 88 | confirmationCheckInterval: 1000, 89 | commitment: "processed", 90 | skipConfirmationCheck: false // Set to true to return txid immediately 91 | }); 92 | 93 | console.log("Transaction ID:", txid); 94 | console.log("Transaction URL:", `https://solscan.io/tx/${txid}`); 95 | } catch (error) { 96 | const {signature, message} = error; 97 | console.error("Error performing swap:", message, signature); 98 | } 99 | } 100 | 101 | swap(); 102 | ``` 103 | 104 | ## New Features 105 | 106 | ### Auto Amount (July 12 Update) 107 | 108 | You can now use `"auto"` as the amount parameter to automatically use the entire balance of the specified token: 109 | 110 | ```javascript 111 | // Will use the entire balance of the "from" token in the wallet 112 | const swapResponse = await solanaTracker.getSwapInstructions( 113 | fromToken, 114 | toToken, 115 | "auto", // Uses entire balance 116 | slippage, 117 | payerPublicKey, 118 | priorityFee 119 | ); 120 | ``` 121 | 122 | **Note:** The auto amount feature works only with Swap endpoints, not Rate endpoints. 123 | 124 | ### Jito Integration 125 | 126 | Execute transactions with Jito bundles for MEV protection: 127 | 128 | ```javascript 129 | const txid = await solanaTracker.performSwap(swapResponse, { 130 | sendOptions: { skipPreflight: true }, 131 | confirmationRetries: 30, 132 | confirmationCheckInterval: 500, 133 | commitment: "processed", 134 | jito: { 135 | enabled: true, 136 | tip: 0.0001, 137 | }, 138 | }); 139 | ``` 140 | 141 | ## Example Projects 142 | 143 | - [Volume Bot](https://github.com/YZYLAB/solana-volume-bot) 144 | - [Trading Bot](https://github.com/YZYLAB/solana-trade-bot) 145 | 146 | ## Production Usage 147 | 148 | Solana Swap is currently being used in production at: 149 | - [Solana Tracker](https://www.solanatracker.io) 150 | 151 | *Using this library in production? [Let us know](mailto:swap-api@solanatracker.io) to be featured here.* 152 | 153 | ## CommonJS Usage 154 | 155 | For projects using CommonJS: 156 | 157 | ```javascript 158 | const { SolanaTracker } = require("solana-swap"); 159 | ``` 160 | 161 | ## Pricing 162 | 163 | Our standard fee is 0.5% on successful transactions. For high-volume applications, we offer discounted rates (as low as 0.1%) for qualified projects. 164 | 165 | ## Contact 166 | 167 | For business inquiries or volume discounts: 168 | - Email: [swap-api@solanatracker.io](mailto:swap-api@solanatracker.io) 169 | - Discord: [Join our community](https://discord.gg/JH2e9rR9fc) 170 | 171 | ## Documentation 172 | 173 | For full documentation, visit our [API Docs](https://docs.solanatracker.io). 174 | 175 | ## License 176 | 177 | [MIT](LICENSE) -------------------------------------------------------------------------------- /dist/cjs/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from "@solana/web3.js"; 2 | import { TransactionSenderAndConfirmationWaiterOptions } from "./lib/sender"; 3 | import { RateResponse, SwapResponse } from "./types"; 4 | export declare class SolanaTracker { 5 | private baseUrl; 6 | private readonly connection; 7 | private readonly keypair; 8 | private readonly apiKey; 9 | constructor(keypair: Keypair, rpc: string, apiKey?: string); 10 | setBaseUrl(url: string): Promise; 11 | getRate(from: string, to: string, amount: number, slippage: number): Promise; 12 | getSwapInstructions(from: string, to: string, fromAmount: number | string, slippage: number, payer: string, priorityFee?: number, forceLegacy?: boolean): Promise; 13 | performSwap(swapResponse: SwapResponse, options?: TransactionSenderAndConfirmationWaiterOptions): Promise; 14 | } 15 | -------------------------------------------------------------------------------- /dist/cjs/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 | 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.SolanaTracker = void 0; 16 | const axios_1 = __importDefault(require("axios")); 17 | const bs58_1 = __importDefault(require("bs58")); 18 | const web3_js_1 = require("@solana/web3.js"); 19 | const sender_1 = require("./lib/sender"); 20 | const jito_1 = require("./lib/jito"); 21 | class SolanaTracker { 22 | constructor(keypair, rpc, apiKey) { 23 | this.baseUrl = "https://swap-v2.solanatracker.io"; 24 | this.connection = new web3_js_1.Connection(rpc); 25 | this.keypair = keypair; 26 | this.apiKey = apiKey || ""; 27 | } 28 | setBaseUrl(url) { 29 | return __awaiter(this, void 0, void 0, function* () { 30 | this.baseUrl = url; 31 | }); 32 | } 33 | getRate(from, to, amount, slippage) { 34 | return __awaiter(this, void 0, void 0, function* () { 35 | const params = new URLSearchParams({ 36 | from, 37 | to, 38 | amount: amount.toString(), 39 | slippage: slippage.toString(), 40 | }); 41 | const url = `${this.baseUrl}/rate?${params}`; 42 | try { 43 | const response = yield axios_1.default.get(url); 44 | return response.data; 45 | } 46 | catch (error) { 47 | throw error; 48 | } 49 | }); 50 | } 51 | getSwapInstructions(from, to, fromAmount, slippage, payer, priorityFee, forceLegacy) { 52 | return __awaiter(this, void 0, void 0, function* () { 53 | const params = new URLSearchParams({ 54 | from, 55 | to, 56 | fromAmount: fromAmount.toString(), 57 | slippage: slippage.toString(), 58 | payer, 59 | forceLegacy: forceLegacy ? "true" : "false", 60 | }); 61 | if (priorityFee) { 62 | params.append("priorityFee", priorityFee.toString()); 63 | } 64 | const url = `${this.baseUrl}/swap?${params}`; 65 | try { 66 | const response = yield axios_1.default.get(url, { 67 | headers: { 68 | "x-api-key": this.apiKey, 69 | }, 70 | }); 71 | return response.data; 72 | } 73 | catch (error) { 74 | throw error; 75 | } 76 | }); 77 | } 78 | performSwap(swapResponse_1) { 79 | return __awaiter(this, arguments, void 0, function* (swapResponse, options = { 80 | sendOptions: { skipPreflight: true }, 81 | confirmationRetries: 30, 82 | confirmationRetryTimeout: 1000, 83 | lastValidBlockHeightBuffer: 150, 84 | commitment: "processed", 85 | resendInterval: 1000, 86 | confirmationCheckInterval: 1000, 87 | skipConfirmationCheck: false, 88 | jito: { 89 | enabled: false, 90 | tip: 0 91 | } 92 | }) { 93 | var _a; 94 | let serializedTransactionBuffer; 95 | try { 96 | serializedTransactionBuffer = Buffer.from(swapResponse.txn, "base64"); 97 | } 98 | catch (error) { 99 | const base64Str = swapResponse.txn; 100 | const binaryStr = atob(base64Str); 101 | const buffer = new Uint8Array(binaryStr.length); 102 | for (let i = 0; i < binaryStr.length; i++) { 103 | buffer[i] = binaryStr.charCodeAt(i); 104 | } 105 | serializedTransactionBuffer = buffer; 106 | } 107 | let txn; 108 | const blockhash = yield this.connection.getLatestBlockhash(); 109 | const blockhashWithExpiryBlockHeight = { 110 | blockhash: blockhash.blockhash, 111 | lastValidBlockHeight: blockhash.lastValidBlockHeight, 112 | }; 113 | if (swapResponse.txVersion === 'v0') { 114 | txn = web3_js_1.VersionedTransaction.deserialize(serializedTransactionBuffer); 115 | txn.sign([this.keypair]); 116 | } 117 | else { 118 | txn = web3_js_1.Transaction.from(serializedTransactionBuffer); 119 | txn.sign(this.keypair); 120 | } 121 | if ((_a = options.jito) === null || _a === void 0 ? void 0 : _a.enabled) { 122 | // Create a tip transaction for the Jito block engine 123 | const tipTxn = yield (0, jito_1.createTipTransaction)(this.keypair.publicKey.toBase58(), options.jito.tip); 124 | tipTxn.recentBlockhash = blockhash.blockhash; 125 | tipTxn.sign(this.keypair); 126 | const response = yield (0, jito_1.sendBundle)([bs58_1.default.encode(txn.serialize()), bs58_1.default.encode(tipTxn.serialize())]); 127 | if (response.result) { 128 | const txid = yield (0, jito_1.checkBundleStatus)(response.result, options.confirmationRetries, options.commitment, options.confirmationCheckInterval); 129 | return txid; 130 | } 131 | } 132 | const txid = yield (0, sender_1.transactionSenderAndConfirmationWaiter)({ 133 | connection: this.connection, 134 | serializedTransaction: txn.serialize(), 135 | blockhashWithExpiryBlockHeight, 136 | options: options, 137 | }); 138 | return txid.toString(); 139 | }); 140 | } 141 | } 142 | exports.SolanaTracker = SolanaTracker; 143 | -------------------------------------------------------------------------------- /dist/cjs/lib/jito.d.ts: -------------------------------------------------------------------------------- 1 | import { Transaction } from "@solana/web3.js"; 2 | export declare function sendBundle(transactions: Array): Promise; 3 | export declare const createTipTransaction: (wallet: string, tip: number) => Promise; 4 | export declare function getBundleStatuses(bundleIds: string[]): Promise; 5 | export declare function checkBundleStatus(bundleId: string, maxRetries?: number, commitmentLevel?: 'processed' | 'confirmed' | 'finalized', retryInterval?: number): Promise<'success' | 'not_included' | 'max_retries_reached' | 'error'>; 6 | -------------------------------------------------------------------------------- /dist/cjs/lib/jito.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.checkBundleStatus = exports.getBundleStatuses = exports.createTipTransaction = exports.sendBundle = void 0; 16 | const web3_js_1 = require("@solana/web3.js"); 17 | const axios_1 = __importDefault(require("axios")); 18 | // Jito Tip Accounts: https://jito-labs.gitbook.io/mev/searcher-resources/json-rpc-api-reference/bundles/gettipaccounts 19 | const tipAccounts = [ 20 | "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5", 21 | "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe", 22 | "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY", 23 | "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49", 24 | "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh", 25 | "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt", 26 | "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL", 27 | "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT" 28 | ]; 29 | function sendBundle(transactions) { 30 | return __awaiter(this, void 0, void 0, function* () { 31 | const bundleData = { 32 | jsonrpc: "2.0", 33 | id: 1, 34 | method: "sendBundle", 35 | params: [transactions], 36 | }; 37 | try { 38 | const response = yield axios_1.default.post(`https://mainnet.block-engine.jito.wtf/api/v1/bundles`, bundleData, { 39 | headers: { 40 | "Content-Type": "application/json", 41 | }, 42 | }); 43 | return response.data; 44 | } 45 | catch (error) { 46 | if (error === null || error === void 0 ? void 0 : error.response.data.error) { 47 | throw new Error(JSON.stringify(error === null || error === void 0 ? void 0 : error.response.data.error)); 48 | } 49 | throw new Error("Failed to send bundle."); 50 | } 51 | }); 52 | } 53 | exports.sendBundle = sendBundle; 54 | const createTipTransaction = (wallet, tip) => __awaiter(void 0, void 0, void 0, function* () { 55 | return new web3_js_1.Transaction().add(web3_js_1.SystemProgram.transfer({ 56 | fromPubkey: new web3_js_1.PublicKey(wallet), 57 | toPubkey: new web3_js_1.PublicKey(tipAccounts[Math.floor(Math.random() * tipAccounts.length)]), 58 | lamports: tip * web3_js_1.LAMPORTS_PER_SOL, 59 | })); 60 | }); 61 | exports.createTipTransaction = createTipTransaction; 62 | function getBundleStatuses(bundleIds) { 63 | return __awaiter(this, void 0, void 0, function* () { 64 | var _a, _b; 65 | const bundleData = { 66 | jsonrpc: "2.0", 67 | id: 1, 68 | method: "getBundleStatuses", 69 | params: [bundleIds], 70 | }; 71 | try { 72 | const response = yield axios_1.default.post(`https://mainnet.block-engine.jito.wtf/api/v1/bundles`, bundleData, { 73 | headers: { 74 | "Content-Type": "application/json", 75 | }, 76 | }); 77 | return response.data; 78 | } 79 | catch (error) { 80 | if ((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.error) { 81 | throw new Error(JSON.stringify(error.response.data.error)); 82 | } 83 | throw new Error("Failed to get bundle statuses."); 84 | } 85 | }); 86 | } 87 | exports.getBundleStatuses = getBundleStatuses; 88 | function checkBundleStatus(bundleId_1) { 89 | return __awaiter(this, arguments, void 0, function* (bundleId, maxRetries = 10, commitmentLevel = 'confirmed', retryInterval = 1000) { 90 | let retries = 0; 91 | while (retries < maxRetries) { 92 | try { 93 | const response = yield getBundleStatuses([bundleId]); 94 | const bundleInfo = response.result.value.find((bundle) => bundle.bundle_id === bundleId); 95 | if (!bundleInfo) { 96 | yield new Promise(resolve => setTimeout(resolve, retryInterval)); 97 | } 98 | const status = bundleInfo.confirmation_status; 99 | const isStatusSufficient = (commitmentLevel === 'processed' && ['processed', 'confirmed', 'finalized'].includes(status)) || 100 | (commitmentLevel === 'confirmed' && ['confirmed', 'finalized'].includes(status)) || 101 | (commitmentLevel === 'finalized' && status === 'finalized'); 102 | if (isStatusSufficient) { 103 | if (bundleInfo.err.Ok === null) { 104 | return bundleInfo.transactions[0]; 105 | } 106 | else { 107 | throw new Error('Jito Bundle Error:' + JSON.stringify(bundleInfo.err)); 108 | } 109 | } 110 | yield new Promise(resolve => setTimeout(resolve, retryInterval)); 111 | retries++; 112 | } 113 | catch (error) { 114 | yield new Promise(resolve => setTimeout(resolve, retryInterval)); 115 | retries++; 116 | } 117 | } 118 | throw new Error('Max retries reached while checking bundle status.'); 119 | }); 120 | } 121 | exports.checkBundleStatus = checkBundleStatus; 122 | -------------------------------------------------------------------------------- /dist/cjs/lib/sender.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Connection, SendOptions, TransactionSignature, Commitment } from "@solana/web3.js"; 3 | interface BlockhashWithExpiryBlockHeight { 4 | blockhash: string; 5 | lastValidBlockHeight: number; 6 | } 7 | export declare const COMMITMENT_LEVELS: Record; 8 | export type SupportedCommitment = 'processed' | 'confirmed' | 'finalized'; 9 | export interface TransactionSenderAndConfirmationWaiterOptions { 10 | sendOptions?: SendOptions; 11 | confirmationRetries?: number; 12 | confirmationRetryTimeout?: number; 13 | lastValidBlockHeightBuffer?: number; 14 | resendInterval?: number; 15 | confirmationCheckInterval?: number; 16 | skipConfirmationCheck?: boolean; 17 | commitment?: SupportedCommitment; 18 | jito?: { 19 | enabled: boolean; 20 | tip: number; 21 | }; 22 | } 23 | declare function transactionSenderAndConfirmationWaiter({ connection, serializedTransaction, blockhashWithExpiryBlockHeight, options, }: { 24 | connection: Connection; 25 | serializedTransaction: Buffer; 26 | blockhashWithExpiryBlockHeight: BlockhashWithExpiryBlockHeight; 27 | options?: Partial; 28 | }): Promise; 29 | export { transactionSenderAndConfirmationWaiter }; 30 | -------------------------------------------------------------------------------- /dist/cjs/lib/sender.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.transactionSenderAndConfirmationWaiter = exports.COMMITMENT_LEVELS = void 0; 13 | class TransactionError extends Error { 14 | constructor(message, signature) { 15 | super(message); 16 | this.name = 'TransactionError'; 17 | this.signature = signature; 18 | } 19 | } 20 | exports.COMMITMENT_LEVELS = { 21 | processed: 0, 22 | confirmed: 1, 23 | finalized: 2, 24 | recent: 0, // Equivalent to 'processed' 25 | single: 1, // Equivalent to 'confirmed' 26 | singleGossip: 1, // Equivalent to 'confirmed' 27 | root: 2, // Equivalent to 'finalized' 28 | max: 2, // Equivalent to 'finalized' 29 | }; 30 | const DEFAULT_OPTIONS = { 31 | sendOptions: { skipPreflight: true }, 32 | confirmationRetries: 30, 33 | confirmationRetryTimeout: 1000, 34 | lastValidBlockHeightBuffer: 150, 35 | resendInterval: 1000, 36 | confirmationCheckInterval: 1000, 37 | skipConfirmationCheck: false, 38 | commitment: "processed", 39 | jito: { 40 | enabled: false, 41 | tip: 0, 42 | } 43 | }; 44 | function transactionSenderAndConfirmationWaiter(_a) { 45 | return __awaiter(this, arguments, void 0, function* ({ connection, serializedTransaction, blockhashWithExpiryBlockHeight, options = DEFAULT_OPTIONS, }) { 46 | const { sendOptions, confirmationRetries, confirmationRetryTimeout, lastValidBlockHeightBuffer, resendInterval, confirmationCheckInterval, skipConfirmationCheck, commitment } = Object.assign(Object.assign({}, DEFAULT_OPTIONS), options); 47 | const lastValidBlockHeight = blockhashWithExpiryBlockHeight.lastValidBlockHeight + 48 | (lastValidBlockHeightBuffer || 150); 49 | // Send the transaction initially 50 | let signature; 51 | try { 52 | signature = yield connection.sendRawTransaction(serializedTransaction, sendOptions); 53 | } 54 | catch (error) { 55 | throw new TransactionError(`Failed to send transaction: ${error.message}`, ''); 56 | } 57 | if (skipConfirmationCheck) { 58 | return signature; 59 | } 60 | // Set up transaction resend interval 61 | const resendIntervalId = resendInterval ? setInterval(() => __awaiter(this, void 0, void 0, function* () { 62 | try { 63 | yield connection.sendRawTransaction(serializedTransaction, sendOptions); 64 | } 65 | catch (error) { } 66 | }), resendInterval < 1000 ? 1000 : resendInterval) : null; 67 | // Loop for confirmation check 68 | let retryCount = 0; 69 | while (retryCount <= (confirmationRetries || 30)) { 70 | try { 71 | const status = yield connection.getSignatureStatus(signature); 72 | if (status.value && status.value.confirmationStatus) { 73 | if (resendIntervalId) { 74 | clearInterval(resendIntervalId); 75 | } 76 | } 77 | if (status.value && status.value.confirmationStatus && 78 | exports.COMMITMENT_LEVELS[status.value.confirmationStatus] >= exports.COMMITMENT_LEVELS[commitment]) { 79 | if (resendIntervalId) { 80 | clearInterval(resendIntervalId); 81 | } 82 | return signature; 83 | } 84 | if (status.value && status.value.err) { 85 | if (resendIntervalId) { 86 | clearInterval(resendIntervalId); 87 | } 88 | throw new TransactionError(`Transaction failed: ${status.value.err}`, signature); 89 | } 90 | const blockHeight = yield connection.getBlockHeight(); 91 | if (blockHeight > lastValidBlockHeight) { 92 | if (resendIntervalId) { 93 | clearInterval(resendIntervalId); 94 | } 95 | throw new TransactionError("Transaction expired", signature); 96 | } 97 | yield new Promise((resolve) => setTimeout(resolve, confirmationCheckInterval)); 98 | retryCount++; 99 | } 100 | catch (error) { 101 | if (resendIntervalId) { 102 | clearInterval(resendIntervalId); 103 | } 104 | if (error instanceof TransactionError) { 105 | throw error; 106 | } 107 | throw new TransactionError(`Confirmation check failed: ${error.message}`, signature); 108 | } 109 | } 110 | if (resendIntervalId) { 111 | clearInterval(resendIntervalId); 112 | } 113 | throw new TransactionError("Transaction failed after maximum retries", signature); 114 | }); 115 | } 116 | exports.transactionSenderAndConfirmationWaiter = transactionSenderAndConfirmationWaiter; 117 | -------------------------------------------------------------------------------- /dist/cjs/lib/signature.d.ts: -------------------------------------------------------------------------------- 1 | import { Transaction, VersionedTransaction } from "@solana/web3.js"; 2 | export declare function getSignature(transaction: Transaction | VersionedTransaction): string; 3 | -------------------------------------------------------------------------------- /dist/cjs/lib/signature.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.getSignature = void 0; 7 | const bs58_1 = __importDefault(require("bs58")); 8 | function getSignature(transaction) { 9 | const signature = "signature" in transaction 10 | ? transaction.signature 11 | : transaction.signatures[0]; 12 | if (!signature) { 13 | throw new Error("Missing transaction signature, the transaction was not signed by the fee payer"); 14 | } 15 | return bs58_1.default.encode(signature); 16 | } 17 | exports.getSignature = getSignature; 18 | -------------------------------------------------------------------------------- /dist/cjs/lib/wait.d.ts: -------------------------------------------------------------------------------- 1 | export declare const wait: (time: number) => Promise; 2 | -------------------------------------------------------------------------------- /dist/cjs/lib/wait.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.wait = void 0; 4 | const wait = (time) => new Promise((resolve) => setTimeout(resolve, time)); 5 | exports.wait = wait; 6 | -------------------------------------------------------------------------------- /dist/cjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./index.js" 3 | } -------------------------------------------------------------------------------- /dist/cjs/tests/example.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /dist/cjs/tests/example.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 | const web3_js_1 = require("@solana/web3.js"); 16 | const bs58_1 = __importDefault(require("bs58")); 17 | const __1 = require("../"); 18 | function swap() { 19 | return __awaiter(this, void 0, void 0, function* () { 20 | const keypair = web3_js_1.Keypair.fromSecretKey(bs58_1.default.decode("YOUR_SECRET_KEY")); 21 | const solanaTracker = new __1.SolanaTracker(keypair, "https://rpc-mainnet.solanatracker.io/?api_key=YOUR_API_KEY" // Staked RPC: https://www.solanatracker.io/solana-rpc 22 | ); 23 | const swapResponse = yield solanaTracker.getSwapInstructions("So11111111111111111111111111111111111111112", // From Token 24 | "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", // To Token 25 | 0.0001, // Amount to swap 26 | 30, // Slippage 27 | keypair.publicKey.toBase58(), // Payer public key 28 | 0.0005); 29 | // Regular transaction 30 | try { 31 | const txid = yield solanaTracker.performSwap(swapResponse, { 32 | sendOptions: { skipPreflight: true }, 33 | confirmationRetries: 30, 34 | confirmationRetryTimeout: 500, 35 | lastValidBlockHeightBuffer: 150, 36 | resendInterval: 1000, 37 | confirmationCheckInterval: 1000, 38 | commitment: "processed", 39 | skipConfirmationCheck: false // Set to true if you want to skip confirmation checks and return txid immediately 40 | }); 41 | // Returns txid when the swap is successful or throws an error if the swap fails 42 | console.log("Transaction ID:", txid); 43 | console.log("Transaction URL:", `https://solscan.io/tx/${txid}`); 44 | } 45 | catch (error) { 46 | const { signature, message } = error; 47 | console.error("Error performing swap:", message, signature); 48 | } 49 | // Jito transaction 50 | try { 51 | const txid = yield solanaTracker.performSwap(swapResponse, { 52 | sendOptions: { skipPreflight: true }, 53 | confirmationRetries: 30, 54 | confirmationCheckInterval: 500, 55 | commitment: "processed", 56 | jito: { 57 | enabled: true, 58 | tip: 0.0001, 59 | }, 60 | }); 61 | // Returns txid when the swap is successful or throws an error if the swap fails 62 | console.log("Transaction ID:", txid); 63 | console.log("Transaction URL:", `https://solscan.io/tx/${txid}`); 64 | } 65 | catch (error) { 66 | const { signature, message } = error; 67 | console.error("Error performing swap:", message, signature); 68 | } 69 | }); 70 | } 71 | swap(); 72 | -------------------------------------------------------------------------------- /dist/cjs/types.d.ts: -------------------------------------------------------------------------------- 1 | export interface RateResponse { 2 | amountIn: number; 3 | amountOut: number; 4 | minAmountOut: number; 5 | currentPrice: number; 6 | executionPrice: number; 7 | priceImpact: number; 8 | fee: number; 9 | baseCurrency: { 10 | decimals: number; 11 | mint: string; 12 | }; 13 | quoteCurrency: { 14 | decimals: number; 15 | mint: string; 16 | }; 17 | platformFee: number; 18 | platformFeeUI: number; 19 | rawQuoteResponse: any; 20 | } 21 | export interface SwapResponse { 22 | txn: string; 23 | txVersion: string; 24 | rate: RateResponse; 25 | forceLegacy?: boolean; 26 | } 27 | -------------------------------------------------------------------------------- /dist/cjs/types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /dist/esm/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from "@solana/web3.js"; 2 | import { TransactionSenderAndConfirmationWaiterOptions } from "./lib/sender"; 3 | import { RateResponse, SwapResponse } from "./types"; 4 | export declare class SolanaTracker { 5 | private baseUrl; 6 | private readonly connection; 7 | private readonly keypair; 8 | private readonly apiKey; 9 | constructor(keypair: Keypair, rpc: string, apiKey?: string); 10 | setBaseUrl(url: string): Promise; 11 | getRate(from: string, to: string, amount: number, slippage: number): Promise; 12 | getSwapInstructions(from: string, to: string, fromAmount: number | string, slippage: number, payer: string, priorityFee?: number, forceLegacy?: boolean): Promise; 13 | performSwap(swapResponse: SwapResponse, options?: TransactionSenderAndConfirmationWaiterOptions): Promise; 14 | } 15 | -------------------------------------------------------------------------------- /dist/esm/index.js: -------------------------------------------------------------------------------- 1 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | import axios from "axios"; 11 | import bs58 from "bs58"; 12 | import { Connection, Transaction, VersionedTransaction, } from "@solana/web3.js"; 13 | import { transactionSenderAndConfirmationWaiter } from "./lib/sender.js"; 14 | import { sendBundle, createTipTransaction, checkBundleStatus } from "./lib/jito.js"; 15 | export class SolanaTracker { 16 | constructor(keypair, rpc, apiKey) { 17 | this.baseUrl = "https://swap-v2.solanatracker.io"; 18 | this.connection = new Connection(rpc); 19 | this.keypair = keypair; 20 | this.apiKey = apiKey || ""; 21 | } 22 | setBaseUrl(url) { 23 | return __awaiter(this, void 0, void 0, function* () { 24 | this.baseUrl = url; 25 | }); 26 | } 27 | getRate(from, to, amount, slippage) { 28 | return __awaiter(this, void 0, void 0, function* () { 29 | const params = new URLSearchParams({ 30 | from, 31 | to, 32 | amount: amount.toString(), 33 | slippage: slippage.toString(), 34 | }); 35 | const url = `${this.baseUrl}/rate?${params}`; 36 | try { 37 | const response = yield axios.get(url); 38 | return response.data; 39 | } 40 | catch (error) { 41 | throw error; 42 | } 43 | }); 44 | } 45 | getSwapInstructions(from, to, fromAmount, slippage, payer, priorityFee, forceLegacy) { 46 | return __awaiter(this, void 0, void 0, function* () { 47 | const params = new URLSearchParams({ 48 | from, 49 | to, 50 | fromAmount: fromAmount.toString(), 51 | slippage: slippage.toString(), 52 | payer, 53 | forceLegacy: forceLegacy ? "true" : "false", 54 | }); 55 | if (priorityFee) { 56 | params.append("priorityFee", priorityFee.toString()); 57 | } 58 | const url = `${this.baseUrl}/swap?${params}`; 59 | try { 60 | const response = yield axios.get(url, { 61 | headers: { 62 | "x-api-key": this.apiKey, 63 | }, 64 | }); 65 | return response.data; 66 | } 67 | catch (error) { 68 | throw error; 69 | } 70 | }); 71 | } 72 | performSwap(swapResponse_1) { 73 | return __awaiter(this, arguments, void 0, function* (swapResponse, options = { 74 | sendOptions: { skipPreflight: true }, 75 | confirmationRetries: 30, 76 | confirmationRetryTimeout: 1000, 77 | lastValidBlockHeightBuffer: 150, 78 | commitment: "processed", 79 | resendInterval: 1000, 80 | confirmationCheckInterval: 1000, 81 | skipConfirmationCheck: false, 82 | jito: { 83 | enabled: false, 84 | tip: 0 85 | } 86 | }) { 87 | var _a; 88 | let serializedTransactionBuffer; 89 | try { 90 | serializedTransactionBuffer = Buffer.from(swapResponse.txn, "base64"); 91 | } 92 | catch (error) { 93 | const base64Str = swapResponse.txn; 94 | const binaryStr = atob(base64Str); 95 | const buffer = new Uint8Array(binaryStr.length); 96 | for (let i = 0; i < binaryStr.length; i++) { 97 | buffer[i] = binaryStr.charCodeAt(i); 98 | } 99 | serializedTransactionBuffer = buffer; 100 | } 101 | let txn; 102 | const blockhash = yield this.connection.getLatestBlockhash(); 103 | const blockhashWithExpiryBlockHeight = { 104 | blockhash: blockhash.blockhash, 105 | lastValidBlockHeight: blockhash.lastValidBlockHeight, 106 | }; 107 | if (swapResponse.txVersion === 'v0') { 108 | txn = VersionedTransaction.deserialize(serializedTransactionBuffer); 109 | txn.sign([this.keypair]); 110 | } 111 | else { 112 | txn = Transaction.from(serializedTransactionBuffer); 113 | txn.sign(this.keypair); 114 | } 115 | if ((_a = options.jito) === null || _a === void 0 ? void 0 : _a.enabled) { 116 | // Create a tip transaction for the Jito block engine 117 | const tipTxn = yield createTipTransaction(this.keypair.publicKey.toBase58(), options.jito.tip); 118 | tipTxn.recentBlockhash = blockhash.blockhash; 119 | tipTxn.sign(this.keypair); 120 | const response = yield sendBundle([bs58.encode(txn.serialize()), bs58.encode(tipTxn.serialize())]); 121 | if (response.result) { 122 | const txid = yield checkBundleStatus(response.result, options.confirmationRetries, options.commitment, options.confirmationCheckInterval); 123 | return txid; 124 | } 125 | } 126 | const txid = yield transactionSenderAndConfirmationWaiter({ 127 | connection: this.connection, 128 | serializedTransaction: txn.serialize(), 129 | blockhashWithExpiryBlockHeight, 130 | options: options, 131 | }); 132 | return txid.toString(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /dist/esm/lib/jito.d.ts: -------------------------------------------------------------------------------- 1 | import { Transaction } from "@solana/web3.js"; 2 | export declare function sendBundle(transactions: Array): Promise; 3 | export declare const createTipTransaction: (wallet: string, tip: number) => Promise; 4 | export declare function getBundleStatuses(bundleIds: string[]): Promise; 5 | export declare function checkBundleStatus(bundleId: string, maxRetries?: number, commitmentLevel?: 'processed' | 'confirmed' | 'finalized', retryInterval?: number): Promise<'success' | 'not_included' | 'max_retries_reached' | 'error'>; 6 | -------------------------------------------------------------------------------- /dist/esm/lib/jito.js: -------------------------------------------------------------------------------- 1 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | import { Transaction, SystemProgram, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; 11 | import axios from "axios"; 12 | // Jito Tip Accounts: https://jito-labs.gitbook.io/mev/searcher-resources/json-rpc-api-reference/bundles/gettipaccounts 13 | const tipAccounts = [ 14 | "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5", 15 | "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe", 16 | "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY", 17 | "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49", 18 | "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh", 19 | "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt", 20 | "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL", 21 | "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT" 22 | ]; 23 | export function sendBundle(transactions) { 24 | return __awaiter(this, void 0, void 0, function* () { 25 | const bundleData = { 26 | jsonrpc: "2.0", 27 | id: 1, 28 | method: "sendBundle", 29 | params: [transactions], 30 | }; 31 | try { 32 | const response = yield axios.post(`https://mainnet.block-engine.jito.wtf/api/v1/bundles`, bundleData, { 33 | headers: { 34 | "Content-Type": "application/json", 35 | }, 36 | }); 37 | return response.data; 38 | } 39 | catch (error) { 40 | if (error === null || error === void 0 ? void 0 : error.response.data.error) { 41 | throw new Error(JSON.stringify(error === null || error === void 0 ? void 0 : error.response.data.error)); 42 | } 43 | throw new Error("Failed to send bundle."); 44 | } 45 | }); 46 | } 47 | export const createTipTransaction = (wallet, tip) => __awaiter(void 0, void 0, void 0, function* () { 48 | return new Transaction().add(SystemProgram.transfer({ 49 | fromPubkey: new PublicKey(wallet), 50 | toPubkey: new PublicKey(tipAccounts[Math.floor(Math.random() * tipAccounts.length)]), 51 | lamports: tip * LAMPORTS_PER_SOL, 52 | })); 53 | }); 54 | export function getBundleStatuses(bundleIds) { 55 | return __awaiter(this, void 0, void 0, function* () { 56 | var _a, _b; 57 | const bundleData = { 58 | jsonrpc: "2.0", 59 | id: 1, 60 | method: "getBundleStatuses", 61 | params: [bundleIds], 62 | }; 63 | try { 64 | const response = yield axios.post(`https://mainnet.block-engine.jito.wtf/api/v1/bundles`, bundleData, { 65 | headers: { 66 | "Content-Type": "application/json", 67 | }, 68 | }); 69 | return response.data; 70 | } 71 | catch (error) { 72 | if ((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.error) { 73 | throw new Error(JSON.stringify(error.response.data.error)); 74 | } 75 | throw new Error("Failed to get bundle statuses."); 76 | } 77 | }); 78 | } 79 | export function checkBundleStatus(bundleId_1) { 80 | return __awaiter(this, arguments, void 0, function* (bundleId, maxRetries = 10, commitmentLevel = 'confirmed', retryInterval = 1000) { 81 | let retries = 0; 82 | while (retries < maxRetries) { 83 | try { 84 | const response = yield getBundleStatuses([bundleId]); 85 | const bundleInfo = response.result.value.find((bundle) => bundle.bundle_id === bundleId); 86 | if (!bundleInfo) { 87 | yield new Promise(resolve => setTimeout(resolve, retryInterval)); 88 | } 89 | const status = bundleInfo.confirmation_status; 90 | const isStatusSufficient = (commitmentLevel === 'processed' && ['processed', 'confirmed', 'finalized'].includes(status)) || 91 | (commitmentLevel === 'confirmed' && ['confirmed', 'finalized'].includes(status)) || 92 | (commitmentLevel === 'finalized' && status === 'finalized'); 93 | if (isStatusSufficient) { 94 | if (bundleInfo.err.Ok === null) { 95 | return bundleInfo.transactions[0]; 96 | } 97 | else { 98 | throw new Error('Jito Bundle Error:' + JSON.stringify(bundleInfo.err)); 99 | } 100 | } 101 | yield new Promise(resolve => setTimeout(resolve, retryInterval)); 102 | retries++; 103 | } 104 | catch (error) { 105 | yield new Promise(resolve => setTimeout(resolve, retryInterval)); 106 | retries++; 107 | } 108 | } 109 | throw new Error('Max retries reached while checking bundle status.'); 110 | }); 111 | } 112 | -------------------------------------------------------------------------------- /dist/esm/lib/sender.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Connection, SendOptions, TransactionSignature, Commitment } from "@solana/web3.js"; 3 | interface BlockhashWithExpiryBlockHeight { 4 | blockhash: string; 5 | lastValidBlockHeight: number; 6 | } 7 | export declare const COMMITMENT_LEVELS: Record; 8 | export type SupportedCommitment = 'processed' | 'confirmed' | 'finalized'; 9 | export interface TransactionSenderAndConfirmationWaiterOptions { 10 | sendOptions?: SendOptions; 11 | confirmationRetries?: number; 12 | confirmationRetryTimeout?: number; 13 | lastValidBlockHeightBuffer?: number; 14 | resendInterval?: number; 15 | confirmationCheckInterval?: number; 16 | skipConfirmationCheck?: boolean; 17 | commitment?: SupportedCommitment; 18 | jito?: { 19 | enabled: boolean; 20 | tip: number; 21 | }; 22 | } 23 | declare function transactionSenderAndConfirmationWaiter({ connection, serializedTransaction, blockhashWithExpiryBlockHeight, options, }: { 24 | connection: Connection; 25 | serializedTransaction: Buffer; 26 | blockhashWithExpiryBlockHeight: BlockhashWithExpiryBlockHeight; 27 | options?: Partial; 28 | }): Promise; 29 | export { transactionSenderAndConfirmationWaiter }; 30 | -------------------------------------------------------------------------------- /dist/esm/lib/sender.js: -------------------------------------------------------------------------------- 1 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | class TransactionError extends Error { 11 | constructor(message, signature) { 12 | super(message); 13 | this.name = 'TransactionError'; 14 | this.signature = signature; 15 | } 16 | } 17 | export const COMMITMENT_LEVELS = { 18 | processed: 0, 19 | confirmed: 1, 20 | finalized: 2, 21 | recent: 0, // Equivalent to 'processed' 22 | single: 1, // Equivalent to 'confirmed' 23 | singleGossip: 1, // Equivalent to 'confirmed' 24 | root: 2, // Equivalent to 'finalized' 25 | max: 2, // Equivalent to 'finalized' 26 | }; 27 | const DEFAULT_OPTIONS = { 28 | sendOptions: { skipPreflight: true }, 29 | confirmationRetries: 30, 30 | confirmationRetryTimeout: 1000, 31 | lastValidBlockHeightBuffer: 150, 32 | resendInterval: 1000, 33 | confirmationCheckInterval: 1000, 34 | skipConfirmationCheck: false, 35 | commitment: "processed", 36 | jito: { 37 | enabled: false, 38 | tip: 0, 39 | } 40 | }; 41 | function transactionSenderAndConfirmationWaiter(_a) { 42 | return __awaiter(this, arguments, void 0, function* ({ connection, serializedTransaction, blockhashWithExpiryBlockHeight, options = DEFAULT_OPTIONS, }) { 43 | const { sendOptions, confirmationRetries, confirmationRetryTimeout, lastValidBlockHeightBuffer, resendInterval, confirmationCheckInterval, skipConfirmationCheck, commitment } = Object.assign(Object.assign({}, DEFAULT_OPTIONS), options); 44 | const lastValidBlockHeight = blockhashWithExpiryBlockHeight.lastValidBlockHeight + 45 | (lastValidBlockHeightBuffer || 150); 46 | // Send the transaction initially 47 | let signature; 48 | try { 49 | signature = yield connection.sendRawTransaction(serializedTransaction, sendOptions); 50 | } 51 | catch (error) { 52 | throw new TransactionError(`Failed to send transaction: ${error.message}`, ''); 53 | } 54 | if (skipConfirmationCheck) { 55 | return signature; 56 | } 57 | // Set up transaction resend interval 58 | const resendIntervalId = resendInterval ? setInterval(() => __awaiter(this, void 0, void 0, function* () { 59 | try { 60 | yield connection.sendRawTransaction(serializedTransaction, sendOptions); 61 | } 62 | catch (error) { } 63 | }), resendInterval < 1000 ? 1000 : resendInterval) : null; 64 | // Loop for confirmation check 65 | let retryCount = 0; 66 | while (retryCount <= (confirmationRetries || 30)) { 67 | try { 68 | const status = yield connection.getSignatureStatus(signature); 69 | if (status.value && status.value.confirmationStatus) { 70 | if (resendIntervalId) { 71 | clearInterval(resendIntervalId); 72 | } 73 | } 74 | if (status.value && status.value.confirmationStatus && 75 | COMMITMENT_LEVELS[status.value.confirmationStatus] >= COMMITMENT_LEVELS[commitment]) { 76 | if (resendIntervalId) { 77 | clearInterval(resendIntervalId); 78 | } 79 | return signature; 80 | } 81 | if (status.value && status.value.err) { 82 | if (resendIntervalId) { 83 | clearInterval(resendIntervalId); 84 | } 85 | throw new TransactionError(`Transaction failed: ${status.value.err}`, signature); 86 | } 87 | const blockHeight = yield connection.getBlockHeight(); 88 | if (blockHeight > lastValidBlockHeight) { 89 | if (resendIntervalId) { 90 | clearInterval(resendIntervalId); 91 | } 92 | throw new TransactionError("Transaction expired", signature); 93 | } 94 | yield new Promise((resolve) => setTimeout(resolve, confirmationCheckInterval)); 95 | retryCount++; 96 | } 97 | catch (error) { 98 | if (resendIntervalId) { 99 | clearInterval(resendIntervalId); 100 | } 101 | if (error instanceof TransactionError) { 102 | throw error; 103 | } 104 | throw new TransactionError(`Confirmation check failed: ${error.message}`, signature); 105 | } 106 | } 107 | if (resendIntervalId) { 108 | clearInterval(resendIntervalId); 109 | } 110 | throw new TransactionError("Transaction failed after maximum retries", signature); 111 | }); 112 | } 113 | export { transactionSenderAndConfirmationWaiter }; 114 | -------------------------------------------------------------------------------- /dist/esm/lib/signature.d.ts: -------------------------------------------------------------------------------- 1 | import { Transaction, VersionedTransaction } from "@solana/web3.js"; 2 | export declare function getSignature(transaction: Transaction | VersionedTransaction): string; 3 | -------------------------------------------------------------------------------- /dist/esm/lib/signature.js: -------------------------------------------------------------------------------- 1 | import bs58 from "bs58"; 2 | export function getSignature(transaction) { 3 | const signature = "signature" in transaction 4 | ? transaction.signature 5 | : transaction.signatures[0]; 6 | if (!signature) { 7 | throw new Error("Missing transaction signature, the transaction was not signed by the fee payer"); 8 | } 9 | return bs58.encode(signature); 10 | } 11 | -------------------------------------------------------------------------------- /dist/esm/lib/wait.d.ts: -------------------------------------------------------------------------------- 1 | export declare const wait: (time: number) => Promise; 2 | -------------------------------------------------------------------------------- /dist/esm/lib/wait.js: -------------------------------------------------------------------------------- 1 | export const wait = (time) => new Promise((resolve) => setTimeout(resolve, time)); 2 | -------------------------------------------------------------------------------- /dist/esm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "main": "./index.js" 4 | } -------------------------------------------------------------------------------- /dist/esm/tests/example.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /dist/esm/tests/example.js: -------------------------------------------------------------------------------- 1 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | import { Keypair } from "@solana/web3.js"; 11 | import bs58 from "bs58"; 12 | import { SolanaTracker } from "../index.js"; 13 | function swap() { 14 | return __awaiter(this, void 0, void 0, function* () { 15 | const keypair = Keypair.fromSecretKey(bs58.decode("YOUR_SECRET_KEY")); 16 | const solanaTracker = new SolanaTracker(keypair, "https://rpc-mainnet.solanatracker.io/?api_key=YOUR_API_KEY" // Staked RPC: https://www.solanatracker.io/solana-rpc 17 | ); 18 | const swapResponse = yield solanaTracker.getSwapInstructions("So11111111111111111111111111111111111111112", // From Token 19 | "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", // To Token 20 | 0.0001, // Amount to swap 21 | 30, // Slippage 22 | keypair.publicKey.toBase58(), // Payer public key 23 | 0.0005); 24 | // Regular transaction 25 | try { 26 | const txid = yield solanaTracker.performSwap(swapResponse, { 27 | sendOptions: { skipPreflight: true }, 28 | confirmationRetries: 30, 29 | confirmationRetryTimeout: 500, 30 | lastValidBlockHeightBuffer: 150, 31 | resendInterval: 1000, 32 | confirmationCheckInterval: 1000, 33 | commitment: "processed", 34 | skipConfirmationCheck: false // Set to true if you want to skip confirmation checks and return txid immediately 35 | }); 36 | // Returns txid when the swap is successful or throws an error if the swap fails 37 | console.log("Transaction ID:", txid); 38 | console.log("Transaction URL:", `https://solscan.io/tx/${txid}`); 39 | } 40 | catch (error) { 41 | const { signature, message } = error; 42 | console.error("Error performing swap:", message, signature); 43 | } 44 | // Jito transaction 45 | try { 46 | const txid = yield solanaTracker.performSwap(swapResponse, { 47 | sendOptions: { skipPreflight: true }, 48 | confirmationRetries: 30, 49 | confirmationCheckInterval: 500, 50 | commitment: "processed", 51 | jito: { 52 | enabled: true, 53 | tip: 0.0001, 54 | }, 55 | }); 56 | // Returns txid when the swap is successful or throws an error if the swap fails 57 | console.log("Transaction ID:", txid); 58 | console.log("Transaction URL:", `https://solscan.io/tx/${txid}`); 59 | } 60 | catch (error) { 61 | const { signature, message } = error; 62 | console.error("Error performing swap:", message, signature); 63 | } 64 | }); 65 | } 66 | swap(); 67 | -------------------------------------------------------------------------------- /dist/esm/types.d.ts: -------------------------------------------------------------------------------- 1 | export interface RateResponse { 2 | amountIn: number; 3 | amountOut: number; 4 | minAmountOut: number; 5 | currentPrice: number; 6 | executionPrice: number; 7 | priceImpact: number; 8 | fee: number; 9 | baseCurrency: { 10 | decimals: number; 11 | mint: string; 12 | }; 13 | quoteCurrency: { 14 | decimals: number; 15 | mint: string; 16 | }; 17 | platformFee: number; 18 | platformFeeUI: number; 19 | rawQuoteResponse: any; 20 | } 21 | export interface SwapResponse { 22 | txn: string; 23 | txVersion: string; 24 | rate: RateResponse; 25 | forceLegacy?: boolean; 26 | } 27 | -------------------------------------------------------------------------------- /dist/esm/types.js: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /dist/types/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from "@solana/web3.js"; 2 | import { TransactionSenderAndConfirmationWaiterOptions } from "./lib/sender"; 3 | import { RateResponse, SwapResponse } from "./types"; 4 | export declare class SolanaTracker { 5 | private baseUrl; 6 | private readonly connection; 7 | private readonly keypair; 8 | private readonly apiKey; 9 | constructor(keypair: Keypair, rpc: string, apiKey?: string); 10 | setBaseUrl(url: string): Promise; 11 | getRate(from: string, to: string, amount: number, slippage: number): Promise; 12 | getSwapInstructions(from: string, to: string, fromAmount: number | string, slippage: number, payer: string, priorityFee?: number, forceLegacy?: boolean): Promise; 13 | performSwap(swapResponse: SwapResponse, options?: TransactionSenderAndConfirmationWaiterOptions): Promise; 14 | } 15 | -------------------------------------------------------------------------------- /dist/types/lib/jito.d.ts: -------------------------------------------------------------------------------- 1 | import { Transaction } from "@solana/web3.js"; 2 | export declare function sendBundle(transactions: Array): Promise; 3 | export declare const createTipTransaction: (wallet: string, tip: number) => Promise; 4 | export declare function getBundleStatuses(bundleIds: string[]): Promise; 5 | export declare function checkBundleStatus(bundleId: string, maxRetries?: number, commitmentLevel?: 'processed' | 'confirmed' | 'finalized', retryInterval?: number): Promise<'success' | 'not_included' | 'max_retries_reached' | 'error'>; 6 | -------------------------------------------------------------------------------- /dist/types/lib/sender.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Connection, SendOptions, TransactionSignature, Commitment } from "@solana/web3.js"; 3 | interface BlockhashWithExpiryBlockHeight { 4 | blockhash: string; 5 | lastValidBlockHeight: number; 6 | } 7 | export declare const COMMITMENT_LEVELS: Record; 8 | export type SupportedCommitment = 'processed' | 'confirmed' | 'finalized'; 9 | export interface TransactionSenderAndConfirmationWaiterOptions { 10 | sendOptions?: SendOptions; 11 | confirmationRetries?: number; 12 | confirmationRetryTimeout?: number; 13 | lastValidBlockHeightBuffer?: number; 14 | resendInterval?: number; 15 | confirmationCheckInterval?: number; 16 | skipConfirmationCheck?: boolean; 17 | commitment?: SupportedCommitment; 18 | jito?: { 19 | enabled: boolean; 20 | tip: number; 21 | }; 22 | } 23 | declare function transactionSenderAndConfirmationWaiter({ connection, serializedTransaction, blockhashWithExpiryBlockHeight, options, }: { 24 | connection: Connection; 25 | serializedTransaction: Buffer; 26 | blockhashWithExpiryBlockHeight: BlockhashWithExpiryBlockHeight; 27 | options?: Partial; 28 | }): Promise; 29 | export { transactionSenderAndConfirmationWaiter }; 30 | -------------------------------------------------------------------------------- /dist/types/lib/signature.d.ts: -------------------------------------------------------------------------------- 1 | import { Transaction, VersionedTransaction } from "@solana/web3.js"; 2 | export declare function getSignature(transaction: Transaction | VersionedTransaction): string; 3 | -------------------------------------------------------------------------------- /dist/types/lib/wait.d.ts: -------------------------------------------------------------------------------- 1 | export declare const wait: (time: number) => Promise; 2 | -------------------------------------------------------------------------------- /dist/types/tests/example.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /dist/types/types.d.ts: -------------------------------------------------------------------------------- 1 | export interface RateResponse { 2 | amountIn: number; 3 | amountOut: number; 4 | minAmountOut: number; 5 | currentPrice: number; 6 | executionPrice: number; 7 | priceImpact: number; 8 | fee: number; 9 | baseCurrency: { 10 | decimals: number; 11 | mint: string; 12 | }; 13 | quoteCurrency: { 14 | decimals: number; 15 | mint: string; 16 | }; 17 | platformFee: number; 18 | platformFeeUI: number; 19 | rawQuoteResponse: any; 20 | } 21 | export interface SwapResponse { 22 | txn: string; 23 | txVersion: string; 24 | rate: RateResponse; 25 | forceLegacy?: boolean; 26 | } 27 | -------------------------------------------------------------------------------- /dist/umd/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from "@solana/web3.js"; 2 | import { TransactionSenderAndConfirmationWaiterOptions } from "./lib/sender"; 3 | import { RateResponse, SwapResponse } from "./types"; 4 | export declare class SolanaTracker { 5 | private baseUrl; 6 | private readonly connection; 7 | private readonly keypair; 8 | private readonly apiKey; 9 | constructor(keypair: Keypair, rpc: string, apiKey?: string); 10 | setBaseUrl(url: string): Promise; 11 | getRate(from: string, to: string, amount: number, slippage: number): Promise; 12 | getSwapInstructions(from: string, to: string, fromAmount: number | string, slippage: number, payer: string, priorityFee?: number, forceLegacy?: boolean): Promise; 13 | performSwap(swapResponse: SwapResponse, options?: TransactionSenderAndConfirmationWaiterOptions): Promise; 14 | } 15 | -------------------------------------------------------------------------------- /dist/umd/index.js: -------------------------------------------------------------------------------- 1 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | var __importDefault = (this && this.__importDefault) || function (mod) { 11 | return (mod && mod.__esModule) ? mod : { "default": mod }; 12 | }; 13 | (function (factory) { 14 | if (typeof module === "object" && typeof module.exports === "object") { 15 | var v = factory(require, exports); 16 | if (v !== undefined) module.exports = v; 17 | } 18 | else if (typeof define === "function" && define.amd) { 19 | define(["require", "exports", "axios", "bs58", "@solana/web3.js", "./lib/sender", "./lib/jito"], factory); 20 | } 21 | })(function (require, exports) { 22 | "use strict"; 23 | Object.defineProperty(exports, "__esModule", { value: true }); 24 | exports.SolanaTracker = void 0; 25 | const axios_1 = __importDefault(require("axios")); 26 | const bs58_1 = __importDefault(require("bs58")); 27 | const web3_js_1 = require("@solana/web3.js"); 28 | const sender_1 = require("./lib/sender"); 29 | const jito_1 = require("./lib/jito"); 30 | class SolanaTracker { 31 | constructor(keypair, rpc, apiKey) { 32 | this.baseUrl = "https://swap-v2.solanatracker.io"; 33 | this.connection = new web3_js_1.Connection(rpc); 34 | this.keypair = keypair; 35 | this.apiKey = apiKey || ""; 36 | } 37 | setBaseUrl(url) { 38 | return __awaiter(this, void 0, void 0, function* () { 39 | this.baseUrl = url; 40 | }); 41 | } 42 | getRate(from, to, amount, slippage) { 43 | return __awaiter(this, void 0, void 0, function* () { 44 | const params = new URLSearchParams({ 45 | from, 46 | to, 47 | amount: amount.toString(), 48 | slippage: slippage.toString(), 49 | }); 50 | const url = `${this.baseUrl}/rate?${params}`; 51 | try { 52 | const response = yield axios_1.default.get(url); 53 | return response.data; 54 | } 55 | catch (error) { 56 | throw error; 57 | } 58 | }); 59 | } 60 | getSwapInstructions(from, to, fromAmount, slippage, payer, priorityFee, forceLegacy) { 61 | return __awaiter(this, void 0, void 0, function* () { 62 | const params = new URLSearchParams({ 63 | from, 64 | to, 65 | fromAmount: fromAmount.toString(), 66 | slippage: slippage.toString(), 67 | payer, 68 | forceLegacy: forceLegacy ? "true" : "false", 69 | }); 70 | if (priorityFee) { 71 | params.append("priorityFee", priorityFee.toString()); 72 | } 73 | const url = `${this.baseUrl}/swap?${params}`; 74 | try { 75 | const response = yield axios_1.default.get(url, { 76 | headers: { 77 | "x-api-key": this.apiKey, 78 | }, 79 | }); 80 | return response.data; 81 | } 82 | catch (error) { 83 | throw error; 84 | } 85 | }); 86 | } 87 | performSwap(swapResponse_1) { 88 | return __awaiter(this, arguments, void 0, function* (swapResponse, options = { 89 | sendOptions: { skipPreflight: true }, 90 | confirmationRetries: 30, 91 | confirmationRetryTimeout: 1000, 92 | lastValidBlockHeightBuffer: 150, 93 | commitment: "processed", 94 | resendInterval: 1000, 95 | confirmationCheckInterval: 1000, 96 | skipConfirmationCheck: false, 97 | jito: { 98 | enabled: false, 99 | tip: 0 100 | } 101 | }) { 102 | var _a; 103 | let serializedTransactionBuffer; 104 | try { 105 | serializedTransactionBuffer = Buffer.from(swapResponse.txn, "base64"); 106 | } 107 | catch (error) { 108 | const base64Str = swapResponse.txn; 109 | const binaryStr = atob(base64Str); 110 | const buffer = new Uint8Array(binaryStr.length); 111 | for (let i = 0; i < binaryStr.length; i++) { 112 | buffer[i] = binaryStr.charCodeAt(i); 113 | } 114 | serializedTransactionBuffer = buffer; 115 | } 116 | let txn; 117 | const blockhash = yield this.connection.getLatestBlockhash(); 118 | const blockhashWithExpiryBlockHeight = { 119 | blockhash: blockhash.blockhash, 120 | lastValidBlockHeight: blockhash.lastValidBlockHeight, 121 | }; 122 | if (swapResponse.txVersion === 'v0') { 123 | txn = web3_js_1.VersionedTransaction.deserialize(serializedTransactionBuffer); 124 | txn.sign([this.keypair]); 125 | } 126 | else { 127 | txn = web3_js_1.Transaction.from(serializedTransactionBuffer); 128 | txn.sign(this.keypair); 129 | } 130 | if ((_a = options.jito) === null || _a === void 0 ? void 0 : _a.enabled) { 131 | // Create a tip transaction for the Jito block engine 132 | const tipTxn = yield (0, jito_1.createTipTransaction)(this.keypair.publicKey.toBase58(), options.jito.tip); 133 | tipTxn.recentBlockhash = blockhash.blockhash; 134 | tipTxn.sign(this.keypair); 135 | const response = yield (0, jito_1.sendBundle)([bs58_1.default.encode(txn.serialize()), bs58_1.default.encode(tipTxn.serialize())]); 136 | if (response.result) { 137 | const txid = yield (0, jito_1.checkBundleStatus)(response.result, options.confirmationRetries, options.commitment, options.confirmationCheckInterval); 138 | return txid; 139 | } 140 | } 141 | const txid = yield (0, sender_1.transactionSenderAndConfirmationWaiter)({ 142 | connection: this.connection, 143 | serializedTransaction: txn.serialize(), 144 | blockhashWithExpiryBlockHeight, 145 | options: options, 146 | }); 147 | return txid.toString(); 148 | }); 149 | } 150 | } 151 | exports.SolanaTracker = SolanaTracker; 152 | }); 153 | -------------------------------------------------------------------------------- /dist/umd/lib/jito.d.ts: -------------------------------------------------------------------------------- 1 | import { Transaction } from "@solana/web3.js"; 2 | export declare function sendBundle(transactions: Array): Promise; 3 | export declare const createTipTransaction: (wallet: string, tip: number) => Promise; 4 | export declare function getBundleStatuses(bundleIds: string[]): Promise; 5 | export declare function checkBundleStatus(bundleId: string, maxRetries?: number, commitmentLevel?: 'processed' | 'confirmed' | 'finalized', retryInterval?: number): Promise<'success' | 'not_included' | 'max_retries_reached' | 'error'>; 6 | -------------------------------------------------------------------------------- /dist/umd/lib/jito.js: -------------------------------------------------------------------------------- 1 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | var __importDefault = (this && this.__importDefault) || function (mod) { 11 | return (mod && mod.__esModule) ? mod : { "default": mod }; 12 | }; 13 | (function (factory) { 14 | if (typeof module === "object" && typeof module.exports === "object") { 15 | var v = factory(require, exports); 16 | if (v !== undefined) module.exports = v; 17 | } 18 | else if (typeof define === "function" && define.amd) { 19 | define(["require", "exports", "@solana/web3.js", "axios"], factory); 20 | } 21 | })(function (require, exports) { 22 | "use strict"; 23 | Object.defineProperty(exports, "__esModule", { value: true }); 24 | exports.checkBundleStatus = exports.getBundleStatuses = exports.createTipTransaction = exports.sendBundle = void 0; 25 | const web3_js_1 = require("@solana/web3.js"); 26 | const axios_1 = __importDefault(require("axios")); 27 | // Jito Tip Accounts: https://jito-labs.gitbook.io/mev/searcher-resources/json-rpc-api-reference/bundles/gettipaccounts 28 | const tipAccounts = [ 29 | "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5", 30 | "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe", 31 | "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY", 32 | "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49", 33 | "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh", 34 | "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt", 35 | "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL", 36 | "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT" 37 | ]; 38 | function sendBundle(transactions) { 39 | return __awaiter(this, void 0, void 0, function* () { 40 | const bundleData = { 41 | jsonrpc: "2.0", 42 | id: 1, 43 | method: "sendBundle", 44 | params: [transactions], 45 | }; 46 | try { 47 | const response = yield axios_1.default.post(`https://mainnet.block-engine.jito.wtf/api/v1/bundles`, bundleData, { 48 | headers: { 49 | "Content-Type": "application/json", 50 | }, 51 | }); 52 | return response.data; 53 | } 54 | catch (error) { 55 | if (error === null || error === void 0 ? void 0 : error.response.data.error) { 56 | throw new Error(JSON.stringify(error === null || error === void 0 ? void 0 : error.response.data.error)); 57 | } 58 | throw new Error("Failed to send bundle."); 59 | } 60 | }); 61 | } 62 | exports.sendBundle = sendBundle; 63 | const createTipTransaction = (wallet, tip) => __awaiter(void 0, void 0, void 0, function* () { 64 | return new web3_js_1.Transaction().add(web3_js_1.SystemProgram.transfer({ 65 | fromPubkey: new web3_js_1.PublicKey(wallet), 66 | toPubkey: new web3_js_1.PublicKey(tipAccounts[Math.floor(Math.random() * tipAccounts.length)]), 67 | lamports: tip * web3_js_1.LAMPORTS_PER_SOL, 68 | })); 69 | }); 70 | exports.createTipTransaction = createTipTransaction; 71 | function getBundleStatuses(bundleIds) { 72 | return __awaiter(this, void 0, void 0, function* () { 73 | var _a, _b; 74 | const bundleData = { 75 | jsonrpc: "2.0", 76 | id: 1, 77 | method: "getBundleStatuses", 78 | params: [bundleIds], 79 | }; 80 | try { 81 | const response = yield axios_1.default.post(`https://mainnet.block-engine.jito.wtf/api/v1/bundles`, bundleData, { 82 | headers: { 83 | "Content-Type": "application/json", 84 | }, 85 | }); 86 | return response.data; 87 | } 88 | catch (error) { 89 | if ((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.error) { 90 | throw new Error(JSON.stringify(error.response.data.error)); 91 | } 92 | throw new Error("Failed to get bundle statuses."); 93 | } 94 | }); 95 | } 96 | exports.getBundleStatuses = getBundleStatuses; 97 | function checkBundleStatus(bundleId_1) { 98 | return __awaiter(this, arguments, void 0, function* (bundleId, maxRetries = 10, commitmentLevel = 'confirmed', retryInterval = 1000) { 99 | let retries = 0; 100 | while (retries < maxRetries) { 101 | try { 102 | const response = yield getBundleStatuses([bundleId]); 103 | const bundleInfo = response.result.value.find((bundle) => bundle.bundle_id === bundleId); 104 | if (!bundleInfo) { 105 | yield new Promise(resolve => setTimeout(resolve, retryInterval)); 106 | } 107 | const status = bundleInfo.confirmation_status; 108 | const isStatusSufficient = (commitmentLevel === 'processed' && ['processed', 'confirmed', 'finalized'].includes(status)) || 109 | (commitmentLevel === 'confirmed' && ['confirmed', 'finalized'].includes(status)) || 110 | (commitmentLevel === 'finalized' && status === 'finalized'); 111 | if (isStatusSufficient) { 112 | if (bundleInfo.err.Ok === null) { 113 | return bundleInfo.transactions[0]; 114 | } 115 | else { 116 | throw new Error('Jito Bundle Error:' + JSON.stringify(bundleInfo.err)); 117 | } 118 | } 119 | yield new Promise(resolve => setTimeout(resolve, retryInterval)); 120 | retries++; 121 | } 122 | catch (error) { 123 | yield new Promise(resolve => setTimeout(resolve, retryInterval)); 124 | retries++; 125 | } 126 | } 127 | throw new Error('Max retries reached while checking bundle status.'); 128 | }); 129 | } 130 | exports.checkBundleStatus = checkBundleStatus; 131 | }); 132 | -------------------------------------------------------------------------------- /dist/umd/lib/sender.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Connection, SendOptions, TransactionSignature, Commitment } from "@solana/web3.js"; 3 | interface BlockhashWithExpiryBlockHeight { 4 | blockhash: string; 5 | lastValidBlockHeight: number; 6 | } 7 | export declare const COMMITMENT_LEVELS: Record; 8 | export type SupportedCommitment = 'processed' | 'confirmed' | 'finalized'; 9 | export interface TransactionSenderAndConfirmationWaiterOptions { 10 | sendOptions?: SendOptions; 11 | confirmationRetries?: number; 12 | confirmationRetryTimeout?: number; 13 | lastValidBlockHeightBuffer?: number; 14 | resendInterval?: number; 15 | confirmationCheckInterval?: number; 16 | skipConfirmationCheck?: boolean; 17 | commitment?: SupportedCommitment; 18 | jito?: { 19 | enabled: boolean; 20 | tip: number; 21 | }; 22 | } 23 | declare function transactionSenderAndConfirmationWaiter({ connection, serializedTransaction, blockhashWithExpiryBlockHeight, options, }: { 24 | connection: Connection; 25 | serializedTransaction: Buffer; 26 | blockhashWithExpiryBlockHeight: BlockhashWithExpiryBlockHeight; 27 | options?: Partial; 28 | }): Promise; 29 | export { transactionSenderAndConfirmationWaiter }; 30 | -------------------------------------------------------------------------------- /dist/umd/lib/sender.js: -------------------------------------------------------------------------------- 1 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | (function (factory) { 11 | if (typeof module === "object" && typeof module.exports === "object") { 12 | var v = factory(require, exports); 13 | if (v !== undefined) module.exports = v; 14 | } 15 | else if (typeof define === "function" && define.amd) { 16 | define(["require", "exports"], factory); 17 | } 18 | })(function (require, exports) { 19 | "use strict"; 20 | Object.defineProperty(exports, "__esModule", { value: true }); 21 | exports.transactionSenderAndConfirmationWaiter = exports.COMMITMENT_LEVELS = void 0; 22 | class TransactionError extends Error { 23 | constructor(message, signature) { 24 | super(message); 25 | this.name = 'TransactionError'; 26 | this.signature = signature; 27 | } 28 | } 29 | exports.COMMITMENT_LEVELS = { 30 | processed: 0, 31 | confirmed: 1, 32 | finalized: 2, 33 | recent: 0, // Equivalent to 'processed' 34 | single: 1, // Equivalent to 'confirmed' 35 | singleGossip: 1, // Equivalent to 'confirmed' 36 | root: 2, // Equivalent to 'finalized' 37 | max: 2, // Equivalent to 'finalized' 38 | }; 39 | const DEFAULT_OPTIONS = { 40 | sendOptions: { skipPreflight: true }, 41 | confirmationRetries: 30, 42 | confirmationRetryTimeout: 1000, 43 | lastValidBlockHeightBuffer: 150, 44 | resendInterval: 1000, 45 | confirmationCheckInterval: 1000, 46 | skipConfirmationCheck: false, 47 | commitment: "processed", 48 | jito: { 49 | enabled: false, 50 | tip: 0, 51 | } 52 | }; 53 | function transactionSenderAndConfirmationWaiter(_a) { 54 | return __awaiter(this, arguments, void 0, function* ({ connection, serializedTransaction, blockhashWithExpiryBlockHeight, options = DEFAULT_OPTIONS, }) { 55 | const { sendOptions, confirmationRetries, confirmationRetryTimeout, lastValidBlockHeightBuffer, resendInterval, confirmationCheckInterval, skipConfirmationCheck, commitment } = Object.assign(Object.assign({}, DEFAULT_OPTIONS), options); 56 | const lastValidBlockHeight = blockhashWithExpiryBlockHeight.lastValidBlockHeight + 57 | (lastValidBlockHeightBuffer || 150); 58 | // Send the transaction initially 59 | let signature; 60 | try { 61 | signature = yield connection.sendRawTransaction(serializedTransaction, sendOptions); 62 | } 63 | catch (error) { 64 | throw new TransactionError(`Failed to send transaction: ${error.message}`, ''); 65 | } 66 | if (skipConfirmationCheck) { 67 | return signature; 68 | } 69 | // Set up transaction resend interval 70 | const resendIntervalId = resendInterval ? setInterval(() => __awaiter(this, void 0, void 0, function* () { 71 | try { 72 | yield connection.sendRawTransaction(serializedTransaction, sendOptions); 73 | } 74 | catch (error) { } 75 | }), resendInterval < 1000 ? 1000 : resendInterval) : null; 76 | // Loop for confirmation check 77 | let retryCount = 0; 78 | while (retryCount <= (confirmationRetries || 30)) { 79 | try { 80 | const status = yield connection.getSignatureStatus(signature); 81 | if (status.value && status.value.confirmationStatus) { 82 | if (resendIntervalId) { 83 | clearInterval(resendIntervalId); 84 | } 85 | } 86 | if (status.value && status.value.confirmationStatus && 87 | exports.COMMITMENT_LEVELS[status.value.confirmationStatus] >= exports.COMMITMENT_LEVELS[commitment]) { 88 | if (resendIntervalId) { 89 | clearInterval(resendIntervalId); 90 | } 91 | return signature; 92 | } 93 | if (status.value && status.value.err) { 94 | if (resendIntervalId) { 95 | clearInterval(resendIntervalId); 96 | } 97 | throw new TransactionError(`Transaction failed: ${status.value.err}`, signature); 98 | } 99 | const blockHeight = yield connection.getBlockHeight(); 100 | if (blockHeight > lastValidBlockHeight) { 101 | if (resendIntervalId) { 102 | clearInterval(resendIntervalId); 103 | } 104 | throw new TransactionError("Transaction expired", signature); 105 | } 106 | yield new Promise((resolve) => setTimeout(resolve, confirmationCheckInterval)); 107 | retryCount++; 108 | } 109 | catch (error) { 110 | if (resendIntervalId) { 111 | clearInterval(resendIntervalId); 112 | } 113 | if (error instanceof TransactionError) { 114 | throw error; 115 | } 116 | throw new TransactionError(`Confirmation check failed: ${error.message}`, signature); 117 | } 118 | } 119 | if (resendIntervalId) { 120 | clearInterval(resendIntervalId); 121 | } 122 | throw new TransactionError("Transaction failed after maximum retries", signature); 123 | }); 124 | } 125 | exports.transactionSenderAndConfirmationWaiter = transactionSenderAndConfirmationWaiter; 126 | }); 127 | -------------------------------------------------------------------------------- /dist/umd/lib/signature.d.ts: -------------------------------------------------------------------------------- 1 | import { Transaction, VersionedTransaction } from "@solana/web3.js"; 2 | export declare function getSignature(transaction: Transaction | VersionedTransaction): string; 3 | -------------------------------------------------------------------------------- /dist/umd/lib/signature.js: -------------------------------------------------------------------------------- 1 | var __importDefault = (this && this.__importDefault) || function (mod) { 2 | return (mod && mod.__esModule) ? mod : { "default": mod }; 3 | }; 4 | (function (factory) { 5 | if (typeof module === "object" && typeof module.exports === "object") { 6 | var v = factory(require, exports); 7 | if (v !== undefined) module.exports = v; 8 | } 9 | else if (typeof define === "function" && define.amd) { 10 | define(["require", "exports", "bs58"], factory); 11 | } 12 | })(function (require, exports) { 13 | "use strict"; 14 | Object.defineProperty(exports, "__esModule", { value: true }); 15 | exports.getSignature = void 0; 16 | const bs58_1 = __importDefault(require("bs58")); 17 | function getSignature(transaction) { 18 | const signature = "signature" in transaction 19 | ? transaction.signature 20 | : transaction.signatures[0]; 21 | if (!signature) { 22 | throw new Error("Missing transaction signature, the transaction was not signed by the fee payer"); 23 | } 24 | return bs58_1.default.encode(signature); 25 | } 26 | exports.getSignature = getSignature; 27 | }); 28 | -------------------------------------------------------------------------------- /dist/umd/lib/wait.d.ts: -------------------------------------------------------------------------------- 1 | export declare const wait: (time: number) => Promise; 2 | -------------------------------------------------------------------------------- /dist/umd/lib/wait.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.wait = void 0; 13 | const wait = (time) => new Promise((resolve) => setTimeout(resolve, time)); 14 | exports.wait = wait; 15 | }); 16 | -------------------------------------------------------------------------------- /dist/umd/tests/example.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /dist/umd/tests/example.js: -------------------------------------------------------------------------------- 1 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | var __importDefault = (this && this.__importDefault) || function (mod) { 11 | return (mod && mod.__esModule) ? mod : { "default": mod }; 12 | }; 13 | (function (factory) { 14 | if (typeof module === "object" && typeof module.exports === "object") { 15 | var v = factory(require, exports); 16 | if (v !== undefined) module.exports = v; 17 | } 18 | else if (typeof define === "function" && define.amd) { 19 | define(["require", "exports", "@solana/web3.js", "bs58", "../"], factory); 20 | } 21 | })(function (require, exports) { 22 | "use strict"; 23 | Object.defineProperty(exports, "__esModule", { value: true }); 24 | const web3_js_1 = require("@solana/web3.js"); 25 | const bs58_1 = __importDefault(require("bs58")); 26 | const __1 = require("../"); 27 | function swap() { 28 | return __awaiter(this, void 0, void 0, function* () { 29 | const keypair = web3_js_1.Keypair.fromSecretKey(bs58_1.default.decode("YOUR_SECRET_KEY")); 30 | const solanaTracker = new __1.SolanaTracker(keypair, "https://rpc-mainnet.solanatracker.io/?api_key=YOUR_API_KEY" // Staked RPC: https://www.solanatracker.io/solana-rpc 31 | ); 32 | const swapResponse = yield solanaTracker.getSwapInstructions("So11111111111111111111111111111111111111112", // From Token 33 | "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", // To Token 34 | 0.0001, // Amount to swap 35 | 30, // Slippage 36 | keypair.publicKey.toBase58(), // Payer public key 37 | 0.0005); 38 | // Regular transaction 39 | try { 40 | const txid = yield solanaTracker.performSwap(swapResponse, { 41 | sendOptions: { skipPreflight: true }, 42 | confirmationRetries: 30, 43 | confirmationRetryTimeout: 500, 44 | lastValidBlockHeightBuffer: 150, 45 | resendInterval: 1000, 46 | confirmationCheckInterval: 1000, 47 | commitment: "processed", 48 | skipConfirmationCheck: false // Set to true if you want to skip confirmation checks and return txid immediately 49 | }); 50 | // Returns txid when the swap is successful or throws an error if the swap fails 51 | console.log("Transaction ID:", txid); 52 | console.log("Transaction URL:", `https://solscan.io/tx/${txid}`); 53 | } 54 | catch (error) { 55 | const { signature, message } = error; 56 | console.error("Error performing swap:", message, signature); 57 | } 58 | // Jito transaction 59 | try { 60 | const txid = yield solanaTracker.performSwap(swapResponse, { 61 | sendOptions: { skipPreflight: true }, 62 | confirmationRetries: 30, 63 | confirmationCheckInterval: 500, 64 | commitment: "processed", 65 | jito: { 66 | enabled: true, 67 | tip: 0.0001, 68 | }, 69 | }); 70 | // Returns txid when the swap is successful or throws an error if the swap fails 71 | console.log("Transaction ID:", txid); 72 | console.log("Transaction URL:", `https://solscan.io/tx/${txid}`); 73 | } 74 | catch (error) { 75 | const { signature, message } = error; 76 | console.error("Error performing swap:", message, signature); 77 | } 78 | }); 79 | } 80 | swap(); 81 | }); 82 | -------------------------------------------------------------------------------- /dist/umd/types.d.ts: -------------------------------------------------------------------------------- 1 | export interface RateResponse { 2 | amountIn: number; 3 | amountOut: number; 4 | minAmountOut: number; 5 | currentPrice: number; 6 | executionPrice: number; 7 | priceImpact: number; 8 | fee: number; 9 | baseCurrency: { 10 | decimals: number; 11 | mint: string; 12 | }; 13 | quoteCurrency: { 14 | decimals: number; 15 | mint: string; 16 | }; 17 | platformFee: number; 18 | platformFeeUI: number; 19 | rawQuoteResponse: any; 20 | } 21 | export interface SwapResponse { 22 | txn: string; 23 | txVersion: string; 24 | rate: RateResponse; 25 | forceLegacy?: boolean; 26 | } 27 | -------------------------------------------------------------------------------- /dist/umd/types.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | }); 13 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solana-swap", 3 | "version": "1.0.12", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "solana-swap", 9 | "version": "1.0.12", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@solana/web3.js": "^1.91.6", 13 | "axios": "^1.6.8", 14 | "bs58": "^5.0.0", 15 | "promise-retry": "^2.0.1" 16 | }, 17 | "devDependencies": { 18 | "rimraf": "^5.0.7" 19 | } 20 | }, 21 | "node_modules/@babel/runtime": { 22 | "version": "7.24.4", 23 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", 24 | "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", 25 | "dependencies": { 26 | "regenerator-runtime": "^0.14.0" 27 | }, 28 | "engines": { 29 | "node": ">=6.9.0" 30 | } 31 | }, 32 | "node_modules/@isaacs/cliui": { 33 | "version": "8.0.2", 34 | "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", 35 | "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", 36 | "dev": true, 37 | "dependencies": { 38 | "string-width": "^5.1.2", 39 | "string-width-cjs": "npm:string-width@^4.2.0", 40 | "strip-ansi": "^7.0.1", 41 | "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", 42 | "wrap-ansi": "^8.1.0", 43 | "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" 44 | }, 45 | "engines": { 46 | "node": ">=12" 47 | } 48 | }, 49 | "node_modules/@noble/curves": { 50 | "version": "1.4.0", 51 | "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.0.tgz", 52 | "integrity": "sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==", 53 | "dependencies": { 54 | "@noble/hashes": "1.4.0" 55 | }, 56 | "funding": { 57 | "url": "https://paulmillr.com/funding/" 58 | } 59 | }, 60 | "node_modules/@noble/hashes": { 61 | "version": "1.4.0", 62 | "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", 63 | "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", 64 | "engines": { 65 | "node": ">= 16" 66 | }, 67 | "funding": { 68 | "url": "https://paulmillr.com/funding/" 69 | } 70 | }, 71 | "node_modules/@pkgjs/parseargs": { 72 | "version": "0.11.0", 73 | "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", 74 | "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", 75 | "dev": true, 76 | "optional": true, 77 | "engines": { 78 | "node": ">=14" 79 | } 80 | }, 81 | "node_modules/@solana/buffer-layout": { 82 | "version": "4.0.1", 83 | "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", 84 | "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", 85 | "dependencies": { 86 | "buffer": "~6.0.3" 87 | }, 88 | "engines": { 89 | "node": ">=5.10" 90 | } 91 | }, 92 | "node_modules/@solana/web3.js": { 93 | "version": "1.91.6", 94 | "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.91.6.tgz", 95 | "integrity": "sha512-dm20nN6HQvXToo+kM51nxHdtaa2wMSRdeK37p+WIWESfeiVHqV8XbV4XnWupq6ngt5vIckhGFG7ZnTBxUgLzDA==", 96 | "dependencies": { 97 | "@babel/runtime": "^7.23.4", 98 | "@noble/curves": "^1.2.0", 99 | "@noble/hashes": "^1.3.3", 100 | "@solana/buffer-layout": "^4.0.1", 101 | "agentkeepalive": "^4.5.0", 102 | "bigint-buffer": "^1.1.5", 103 | "bn.js": "^5.2.1", 104 | "borsh": "^0.7.0", 105 | "bs58": "^4.0.1", 106 | "buffer": "6.0.3", 107 | "fast-stable-stringify": "^1.0.0", 108 | "jayson": "^4.1.0", 109 | "node-fetch": "^2.7.0", 110 | "rpc-websockets": "^7.5.1", 111 | "superstruct": "^0.14.2" 112 | } 113 | }, 114 | "node_modules/@solana/web3.js/node_modules/base-x": { 115 | "version": "3.0.9", 116 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", 117 | "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", 118 | "dependencies": { 119 | "safe-buffer": "^5.0.1" 120 | } 121 | }, 122 | "node_modules/@solana/web3.js/node_modules/bs58": { 123 | "version": "4.0.1", 124 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 125 | "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", 126 | "dependencies": { 127 | "base-x": "^3.0.2" 128 | } 129 | }, 130 | "node_modules/@types/connect": { 131 | "version": "3.4.38", 132 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", 133 | "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", 134 | "dependencies": { 135 | "@types/node": "*" 136 | } 137 | }, 138 | "node_modules/@types/node": { 139 | "version": "12.20.55", 140 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", 141 | "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" 142 | }, 143 | "node_modules/@types/ws": { 144 | "version": "7.4.7", 145 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", 146 | "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", 147 | "dependencies": { 148 | "@types/node": "*" 149 | } 150 | }, 151 | "node_modules/agentkeepalive": { 152 | "version": "4.5.0", 153 | "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", 154 | "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", 155 | "dependencies": { 156 | "humanize-ms": "^1.2.1" 157 | }, 158 | "engines": { 159 | "node": ">= 8.0.0" 160 | } 161 | }, 162 | "node_modules/ansi-regex": { 163 | "version": "6.0.1", 164 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", 165 | "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", 166 | "dev": true, 167 | "engines": { 168 | "node": ">=12" 169 | }, 170 | "funding": { 171 | "url": "https://github.com/chalk/ansi-regex?sponsor=1" 172 | } 173 | }, 174 | "node_modules/ansi-styles": { 175 | "version": "6.2.1", 176 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", 177 | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", 178 | "dev": true, 179 | "engines": { 180 | "node": ">=12" 181 | }, 182 | "funding": { 183 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 184 | } 185 | }, 186 | "node_modules/asynckit": { 187 | "version": "0.4.0", 188 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 189 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 190 | }, 191 | "node_modules/axios": { 192 | "version": "1.6.8", 193 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", 194 | "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", 195 | "dependencies": { 196 | "follow-redirects": "^1.15.6", 197 | "form-data": "^4.0.0", 198 | "proxy-from-env": "^1.1.0" 199 | } 200 | }, 201 | "node_modules/balanced-match": { 202 | "version": "1.0.2", 203 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 204 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 205 | "dev": true 206 | }, 207 | "node_modules/base-x": { 208 | "version": "4.0.0", 209 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", 210 | "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" 211 | }, 212 | "node_modules/base64-js": { 213 | "version": "1.5.1", 214 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 215 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 216 | "funding": [ 217 | { 218 | "type": "github", 219 | "url": "https://github.com/sponsors/feross" 220 | }, 221 | { 222 | "type": "patreon", 223 | "url": "https://www.patreon.com/feross" 224 | }, 225 | { 226 | "type": "consulting", 227 | "url": "https://feross.org/support" 228 | } 229 | ] 230 | }, 231 | "node_modules/bigint-buffer": { 232 | "version": "1.1.5", 233 | "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", 234 | "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", 235 | "hasInstallScript": true, 236 | "dependencies": { 237 | "bindings": "^1.3.0" 238 | }, 239 | "engines": { 240 | "node": ">= 10.0.0" 241 | } 242 | }, 243 | "node_modules/bindings": { 244 | "version": "1.5.0", 245 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 246 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 247 | "dependencies": { 248 | "file-uri-to-path": "1.0.0" 249 | } 250 | }, 251 | "node_modules/bn.js": { 252 | "version": "5.2.1", 253 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", 254 | "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" 255 | }, 256 | "node_modules/borsh": { 257 | "version": "0.7.0", 258 | "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", 259 | "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", 260 | "dependencies": { 261 | "bn.js": "^5.2.0", 262 | "bs58": "^4.0.0", 263 | "text-encoding-utf-8": "^1.0.2" 264 | } 265 | }, 266 | "node_modules/borsh/node_modules/base-x": { 267 | "version": "3.0.9", 268 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", 269 | "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", 270 | "dependencies": { 271 | "safe-buffer": "^5.0.1" 272 | } 273 | }, 274 | "node_modules/borsh/node_modules/bs58": { 275 | "version": "4.0.1", 276 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 277 | "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", 278 | "dependencies": { 279 | "base-x": "^3.0.2" 280 | } 281 | }, 282 | "node_modules/brace-expansion": { 283 | "version": "2.0.1", 284 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 285 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 286 | "dev": true, 287 | "dependencies": { 288 | "balanced-match": "^1.0.0" 289 | } 290 | }, 291 | "node_modules/bs58": { 292 | "version": "5.0.0", 293 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", 294 | "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", 295 | "dependencies": { 296 | "base-x": "^4.0.0" 297 | } 298 | }, 299 | "node_modules/buffer": { 300 | "version": "6.0.3", 301 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", 302 | "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", 303 | "funding": [ 304 | { 305 | "type": "github", 306 | "url": "https://github.com/sponsors/feross" 307 | }, 308 | { 309 | "type": "patreon", 310 | "url": "https://www.patreon.com/feross" 311 | }, 312 | { 313 | "type": "consulting", 314 | "url": "https://feross.org/support" 315 | } 316 | ], 317 | "dependencies": { 318 | "base64-js": "^1.3.1", 319 | "ieee754": "^1.2.1" 320 | } 321 | }, 322 | "node_modules/bufferutil": { 323 | "version": "4.0.8", 324 | "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", 325 | "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", 326 | "hasInstallScript": true, 327 | "optional": true, 328 | "dependencies": { 329 | "node-gyp-build": "^4.3.0" 330 | }, 331 | "engines": { 332 | "node": ">=6.14.2" 333 | } 334 | }, 335 | "node_modules/color-convert": { 336 | "version": "2.0.1", 337 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 338 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 339 | "dev": true, 340 | "dependencies": { 341 | "color-name": "~1.1.4" 342 | }, 343 | "engines": { 344 | "node": ">=7.0.0" 345 | } 346 | }, 347 | "node_modules/color-name": { 348 | "version": "1.1.4", 349 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 350 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 351 | "dev": true 352 | }, 353 | "node_modules/combined-stream": { 354 | "version": "1.0.8", 355 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 356 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 357 | "dependencies": { 358 | "delayed-stream": "~1.0.0" 359 | }, 360 | "engines": { 361 | "node": ">= 0.8" 362 | } 363 | }, 364 | "node_modules/commander": { 365 | "version": "2.20.3", 366 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 367 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" 368 | }, 369 | "node_modules/cross-spawn": { 370 | "version": "7.0.3", 371 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 372 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 373 | "dev": true, 374 | "dependencies": { 375 | "path-key": "^3.1.0", 376 | "shebang-command": "^2.0.0", 377 | "which": "^2.0.1" 378 | }, 379 | "engines": { 380 | "node": ">= 8" 381 | } 382 | }, 383 | "node_modules/delay": { 384 | "version": "5.0.0", 385 | "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", 386 | "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", 387 | "engines": { 388 | "node": ">=10" 389 | }, 390 | "funding": { 391 | "url": "https://github.com/sponsors/sindresorhus" 392 | } 393 | }, 394 | "node_modules/delayed-stream": { 395 | "version": "1.0.0", 396 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 397 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 398 | "engines": { 399 | "node": ">=0.4.0" 400 | } 401 | }, 402 | "node_modules/eastasianwidth": { 403 | "version": "0.2.0", 404 | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", 405 | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", 406 | "dev": true 407 | }, 408 | "node_modules/emoji-regex": { 409 | "version": "9.2.2", 410 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", 411 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", 412 | "dev": true 413 | }, 414 | "node_modules/err-code": { 415 | "version": "2.0.3", 416 | "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", 417 | "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" 418 | }, 419 | "node_modules/es6-promise": { 420 | "version": "4.2.8", 421 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", 422 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" 423 | }, 424 | "node_modules/es6-promisify": { 425 | "version": "5.0.0", 426 | "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", 427 | "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", 428 | "dependencies": { 429 | "es6-promise": "^4.0.3" 430 | } 431 | }, 432 | "node_modules/eventemitter3": { 433 | "version": "4.0.7", 434 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", 435 | "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" 436 | }, 437 | "node_modules/eyes": { 438 | "version": "0.1.8", 439 | "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", 440 | "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", 441 | "engines": { 442 | "node": "> 0.1.90" 443 | } 444 | }, 445 | "node_modules/fast-stable-stringify": { 446 | "version": "1.0.0", 447 | "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", 448 | "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==" 449 | }, 450 | "node_modules/file-uri-to-path": { 451 | "version": "1.0.0", 452 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 453 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" 454 | }, 455 | "node_modules/follow-redirects": { 456 | "version": "1.15.6", 457 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", 458 | "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", 459 | "funding": [ 460 | { 461 | "type": "individual", 462 | "url": "https://github.com/sponsors/RubenVerborgh" 463 | } 464 | ], 465 | "engines": { 466 | "node": ">=4.0" 467 | }, 468 | "peerDependenciesMeta": { 469 | "debug": { 470 | "optional": true 471 | } 472 | } 473 | }, 474 | "node_modules/foreground-child": { 475 | "version": "3.1.1", 476 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", 477 | "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", 478 | "dev": true, 479 | "dependencies": { 480 | "cross-spawn": "^7.0.0", 481 | "signal-exit": "^4.0.1" 482 | }, 483 | "engines": { 484 | "node": ">=14" 485 | }, 486 | "funding": { 487 | "url": "https://github.com/sponsors/isaacs" 488 | } 489 | }, 490 | "node_modules/form-data": { 491 | "version": "4.0.0", 492 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 493 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 494 | "dependencies": { 495 | "asynckit": "^0.4.0", 496 | "combined-stream": "^1.0.8", 497 | "mime-types": "^2.1.12" 498 | }, 499 | "engines": { 500 | "node": ">= 6" 501 | } 502 | }, 503 | "node_modules/glob": { 504 | "version": "10.4.1", 505 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", 506 | "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", 507 | "dev": true, 508 | "dependencies": { 509 | "foreground-child": "^3.1.0", 510 | "jackspeak": "^3.1.2", 511 | "minimatch": "^9.0.4", 512 | "minipass": "^7.1.2", 513 | "path-scurry": "^1.11.1" 514 | }, 515 | "bin": { 516 | "glob": "dist/esm/bin.mjs" 517 | }, 518 | "engines": { 519 | "node": ">=16 || 14 >=14.18" 520 | }, 521 | "funding": { 522 | "url": "https://github.com/sponsors/isaacs" 523 | } 524 | }, 525 | "node_modules/humanize-ms": { 526 | "version": "1.2.1", 527 | "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", 528 | "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", 529 | "dependencies": { 530 | "ms": "^2.0.0" 531 | } 532 | }, 533 | "node_modules/ieee754": { 534 | "version": "1.2.1", 535 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 536 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 537 | "funding": [ 538 | { 539 | "type": "github", 540 | "url": "https://github.com/sponsors/feross" 541 | }, 542 | { 543 | "type": "patreon", 544 | "url": "https://www.patreon.com/feross" 545 | }, 546 | { 547 | "type": "consulting", 548 | "url": "https://feross.org/support" 549 | } 550 | ] 551 | }, 552 | "node_modules/is-fullwidth-code-point": { 553 | "version": "3.0.0", 554 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 555 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 556 | "dev": true, 557 | "engines": { 558 | "node": ">=8" 559 | } 560 | }, 561 | "node_modules/isexe": { 562 | "version": "2.0.0", 563 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 564 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 565 | "dev": true 566 | }, 567 | "node_modules/isomorphic-ws": { 568 | "version": "4.0.1", 569 | "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", 570 | "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", 571 | "peerDependencies": { 572 | "ws": "*" 573 | } 574 | }, 575 | "node_modules/jackspeak": { 576 | "version": "3.1.2", 577 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", 578 | "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", 579 | "dev": true, 580 | "dependencies": { 581 | "@isaacs/cliui": "^8.0.2" 582 | }, 583 | "engines": { 584 | "node": ">=14" 585 | }, 586 | "funding": { 587 | "url": "https://github.com/sponsors/isaacs" 588 | }, 589 | "optionalDependencies": { 590 | "@pkgjs/parseargs": "^0.11.0" 591 | } 592 | }, 593 | "node_modules/jayson": { 594 | "version": "4.1.0", 595 | "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.1.0.tgz", 596 | "integrity": "sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==", 597 | "dependencies": { 598 | "@types/connect": "^3.4.33", 599 | "@types/node": "^12.12.54", 600 | "@types/ws": "^7.4.4", 601 | "commander": "^2.20.3", 602 | "delay": "^5.0.0", 603 | "es6-promisify": "^5.0.0", 604 | "eyes": "^0.1.8", 605 | "isomorphic-ws": "^4.0.1", 606 | "json-stringify-safe": "^5.0.1", 607 | "JSONStream": "^1.3.5", 608 | "uuid": "^8.3.2", 609 | "ws": "^7.4.5" 610 | }, 611 | "bin": { 612 | "jayson": "bin/jayson.js" 613 | }, 614 | "engines": { 615 | "node": ">=8" 616 | } 617 | }, 618 | "node_modules/json-stringify-safe": { 619 | "version": "5.0.1", 620 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 621 | "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" 622 | }, 623 | "node_modules/jsonparse": { 624 | "version": "1.3.1", 625 | "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", 626 | "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", 627 | "engines": [ 628 | "node >= 0.2.0" 629 | ] 630 | }, 631 | "node_modules/JSONStream": { 632 | "version": "1.3.5", 633 | "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", 634 | "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", 635 | "dependencies": { 636 | "jsonparse": "^1.2.0", 637 | "through": ">=2.2.7 <3" 638 | }, 639 | "bin": { 640 | "JSONStream": "bin.js" 641 | }, 642 | "engines": { 643 | "node": "*" 644 | } 645 | }, 646 | "node_modules/lru-cache": { 647 | "version": "10.2.2", 648 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", 649 | "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", 650 | "dev": true, 651 | "engines": { 652 | "node": "14 || >=16.14" 653 | } 654 | }, 655 | "node_modules/mime-db": { 656 | "version": "1.52.0", 657 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 658 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 659 | "engines": { 660 | "node": ">= 0.6" 661 | } 662 | }, 663 | "node_modules/mime-types": { 664 | "version": "2.1.35", 665 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 666 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 667 | "dependencies": { 668 | "mime-db": "1.52.0" 669 | }, 670 | "engines": { 671 | "node": ">= 0.6" 672 | } 673 | }, 674 | "node_modules/minimatch": { 675 | "version": "9.0.4", 676 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", 677 | "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", 678 | "dev": true, 679 | "dependencies": { 680 | "brace-expansion": "^2.0.1" 681 | }, 682 | "engines": { 683 | "node": ">=16 || 14 >=14.17" 684 | }, 685 | "funding": { 686 | "url": "https://github.com/sponsors/isaacs" 687 | } 688 | }, 689 | "node_modules/minipass": { 690 | "version": "7.1.2", 691 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", 692 | "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", 693 | "dev": true, 694 | "engines": { 695 | "node": ">=16 || 14 >=14.17" 696 | } 697 | }, 698 | "node_modules/ms": { 699 | "version": "2.1.3", 700 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 701 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 702 | }, 703 | "node_modules/node-fetch": { 704 | "version": "2.7.0", 705 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", 706 | "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", 707 | "dependencies": { 708 | "whatwg-url": "^5.0.0" 709 | }, 710 | "engines": { 711 | "node": "4.x || >=6.0.0" 712 | }, 713 | "peerDependencies": { 714 | "encoding": "^0.1.0" 715 | }, 716 | "peerDependenciesMeta": { 717 | "encoding": { 718 | "optional": true 719 | } 720 | } 721 | }, 722 | "node_modules/node-gyp-build": { 723 | "version": "4.8.0", 724 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", 725 | "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", 726 | "optional": true, 727 | "bin": { 728 | "node-gyp-build": "bin.js", 729 | "node-gyp-build-optional": "optional.js", 730 | "node-gyp-build-test": "build-test.js" 731 | } 732 | }, 733 | "node_modules/path-key": { 734 | "version": "3.1.1", 735 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 736 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 737 | "dev": true, 738 | "engines": { 739 | "node": ">=8" 740 | } 741 | }, 742 | "node_modules/path-scurry": { 743 | "version": "1.11.1", 744 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", 745 | "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", 746 | "dev": true, 747 | "dependencies": { 748 | "lru-cache": "^10.2.0", 749 | "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" 750 | }, 751 | "engines": { 752 | "node": ">=16 || 14 >=14.18" 753 | }, 754 | "funding": { 755 | "url": "https://github.com/sponsors/isaacs" 756 | } 757 | }, 758 | "node_modules/promise-retry": { 759 | "version": "2.0.1", 760 | "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", 761 | "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", 762 | "dependencies": { 763 | "err-code": "^2.0.2", 764 | "retry": "^0.12.0" 765 | }, 766 | "engines": { 767 | "node": ">=10" 768 | } 769 | }, 770 | "node_modules/proxy-from-env": { 771 | "version": "1.1.0", 772 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 773 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 774 | }, 775 | "node_modules/regenerator-runtime": { 776 | "version": "0.14.1", 777 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", 778 | "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" 779 | }, 780 | "node_modules/retry": { 781 | "version": "0.12.0", 782 | "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", 783 | "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", 784 | "engines": { 785 | "node": ">= 4" 786 | } 787 | }, 788 | "node_modules/rimraf": { 789 | "version": "5.0.7", 790 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", 791 | "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", 792 | "dev": true, 793 | "dependencies": { 794 | "glob": "^10.3.7" 795 | }, 796 | "bin": { 797 | "rimraf": "dist/esm/bin.mjs" 798 | }, 799 | "engines": { 800 | "node": ">=14.18" 801 | }, 802 | "funding": { 803 | "url": "https://github.com/sponsors/isaacs" 804 | } 805 | }, 806 | "node_modules/rpc-websockets": { 807 | "version": "7.10.0", 808 | "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.10.0.tgz", 809 | "integrity": "sha512-cemZ6RiDtYZpPiBzYijdOrkQQzmBCmug0E9SdRH2gIUNT15ql4mwCYWIp0VnSZq6Qrw/JkGUygp4PrK1y9KfwQ==", 810 | "dependencies": { 811 | "@babel/runtime": "^7.17.2", 812 | "eventemitter3": "^4.0.7", 813 | "uuid": "^8.3.2", 814 | "ws": "^8.5.0" 815 | }, 816 | "funding": { 817 | "type": "paypal", 818 | "url": "https://paypal.me/kozjak" 819 | }, 820 | "optionalDependencies": { 821 | "bufferutil": "^4.0.1", 822 | "utf-8-validate": "^5.0.2" 823 | } 824 | }, 825 | "node_modules/rpc-websockets/node_modules/ws": { 826 | "version": "8.16.0", 827 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", 828 | "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", 829 | "engines": { 830 | "node": ">=10.0.0" 831 | }, 832 | "peerDependencies": { 833 | "bufferutil": "^4.0.1", 834 | "utf-8-validate": ">=5.0.2" 835 | }, 836 | "peerDependenciesMeta": { 837 | "bufferutil": { 838 | "optional": true 839 | }, 840 | "utf-8-validate": { 841 | "optional": true 842 | } 843 | } 844 | }, 845 | "node_modules/safe-buffer": { 846 | "version": "5.2.1", 847 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 848 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 849 | "funding": [ 850 | { 851 | "type": "github", 852 | "url": "https://github.com/sponsors/feross" 853 | }, 854 | { 855 | "type": "patreon", 856 | "url": "https://www.patreon.com/feross" 857 | }, 858 | { 859 | "type": "consulting", 860 | "url": "https://feross.org/support" 861 | } 862 | ] 863 | }, 864 | "node_modules/shebang-command": { 865 | "version": "2.0.0", 866 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 867 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 868 | "dev": true, 869 | "dependencies": { 870 | "shebang-regex": "^3.0.0" 871 | }, 872 | "engines": { 873 | "node": ">=8" 874 | } 875 | }, 876 | "node_modules/shebang-regex": { 877 | "version": "3.0.0", 878 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 879 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 880 | "dev": true, 881 | "engines": { 882 | "node": ">=8" 883 | } 884 | }, 885 | "node_modules/signal-exit": { 886 | "version": "4.1.0", 887 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 888 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 889 | "dev": true, 890 | "engines": { 891 | "node": ">=14" 892 | }, 893 | "funding": { 894 | "url": "https://github.com/sponsors/isaacs" 895 | } 896 | }, 897 | "node_modules/string-width": { 898 | "version": "5.1.2", 899 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", 900 | "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", 901 | "dev": true, 902 | "dependencies": { 903 | "eastasianwidth": "^0.2.0", 904 | "emoji-regex": "^9.2.2", 905 | "strip-ansi": "^7.0.1" 906 | }, 907 | "engines": { 908 | "node": ">=12" 909 | }, 910 | "funding": { 911 | "url": "https://github.com/sponsors/sindresorhus" 912 | } 913 | }, 914 | "node_modules/string-width-cjs": { 915 | "name": "string-width", 916 | "version": "4.2.3", 917 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 918 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 919 | "dev": true, 920 | "dependencies": { 921 | "emoji-regex": "^8.0.0", 922 | "is-fullwidth-code-point": "^3.0.0", 923 | "strip-ansi": "^6.0.1" 924 | }, 925 | "engines": { 926 | "node": ">=8" 927 | } 928 | }, 929 | "node_modules/string-width-cjs/node_modules/ansi-regex": { 930 | "version": "5.0.1", 931 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 932 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 933 | "dev": true, 934 | "engines": { 935 | "node": ">=8" 936 | } 937 | }, 938 | "node_modules/string-width-cjs/node_modules/emoji-regex": { 939 | "version": "8.0.0", 940 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 941 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 942 | "dev": true 943 | }, 944 | "node_modules/string-width-cjs/node_modules/strip-ansi": { 945 | "version": "6.0.1", 946 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 947 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 948 | "dev": true, 949 | "dependencies": { 950 | "ansi-regex": "^5.0.1" 951 | }, 952 | "engines": { 953 | "node": ">=8" 954 | } 955 | }, 956 | "node_modules/strip-ansi": { 957 | "version": "7.1.0", 958 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", 959 | "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", 960 | "dev": true, 961 | "dependencies": { 962 | "ansi-regex": "^6.0.1" 963 | }, 964 | "engines": { 965 | "node": ">=12" 966 | }, 967 | "funding": { 968 | "url": "https://github.com/chalk/strip-ansi?sponsor=1" 969 | } 970 | }, 971 | "node_modules/strip-ansi-cjs": { 972 | "name": "strip-ansi", 973 | "version": "6.0.1", 974 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 975 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 976 | "dev": true, 977 | "dependencies": { 978 | "ansi-regex": "^5.0.1" 979 | }, 980 | "engines": { 981 | "node": ">=8" 982 | } 983 | }, 984 | "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { 985 | "version": "5.0.1", 986 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 987 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 988 | "dev": true, 989 | "engines": { 990 | "node": ">=8" 991 | } 992 | }, 993 | "node_modules/superstruct": { 994 | "version": "0.14.2", 995 | "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz", 996 | "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==" 997 | }, 998 | "node_modules/text-encoding-utf-8": { 999 | "version": "1.0.2", 1000 | "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", 1001 | "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" 1002 | }, 1003 | "node_modules/through": { 1004 | "version": "2.3.8", 1005 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1006 | "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" 1007 | }, 1008 | "node_modules/tr46": { 1009 | "version": "0.0.3", 1010 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 1011 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 1012 | }, 1013 | "node_modules/utf-8-validate": { 1014 | "version": "5.0.10", 1015 | "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", 1016 | "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", 1017 | "hasInstallScript": true, 1018 | "optional": true, 1019 | "dependencies": { 1020 | "node-gyp-build": "^4.3.0" 1021 | }, 1022 | "engines": { 1023 | "node": ">=6.14.2" 1024 | } 1025 | }, 1026 | "node_modules/uuid": { 1027 | "version": "8.3.2", 1028 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 1029 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", 1030 | "bin": { 1031 | "uuid": "dist/bin/uuid" 1032 | } 1033 | }, 1034 | "node_modules/webidl-conversions": { 1035 | "version": "3.0.1", 1036 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 1037 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 1038 | }, 1039 | "node_modules/whatwg-url": { 1040 | "version": "5.0.0", 1041 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 1042 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 1043 | "dependencies": { 1044 | "tr46": "~0.0.3", 1045 | "webidl-conversions": "^3.0.0" 1046 | } 1047 | }, 1048 | "node_modules/which": { 1049 | "version": "2.0.2", 1050 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1051 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1052 | "dev": true, 1053 | "dependencies": { 1054 | "isexe": "^2.0.0" 1055 | }, 1056 | "bin": { 1057 | "node-which": "bin/node-which" 1058 | }, 1059 | "engines": { 1060 | "node": ">= 8" 1061 | } 1062 | }, 1063 | "node_modules/wrap-ansi": { 1064 | "version": "8.1.0", 1065 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", 1066 | "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", 1067 | "dev": true, 1068 | "dependencies": { 1069 | "ansi-styles": "^6.1.0", 1070 | "string-width": "^5.0.1", 1071 | "strip-ansi": "^7.0.1" 1072 | }, 1073 | "engines": { 1074 | "node": ">=12" 1075 | }, 1076 | "funding": { 1077 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1078 | } 1079 | }, 1080 | "node_modules/wrap-ansi-cjs": { 1081 | "name": "wrap-ansi", 1082 | "version": "7.0.0", 1083 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1084 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1085 | "dev": true, 1086 | "dependencies": { 1087 | "ansi-styles": "^4.0.0", 1088 | "string-width": "^4.1.0", 1089 | "strip-ansi": "^6.0.0" 1090 | }, 1091 | "engines": { 1092 | "node": ">=10" 1093 | }, 1094 | "funding": { 1095 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1096 | } 1097 | }, 1098 | "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { 1099 | "version": "5.0.1", 1100 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1101 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1102 | "dev": true, 1103 | "engines": { 1104 | "node": ">=8" 1105 | } 1106 | }, 1107 | "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { 1108 | "version": "4.3.0", 1109 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1110 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1111 | "dev": true, 1112 | "dependencies": { 1113 | "color-convert": "^2.0.1" 1114 | }, 1115 | "engines": { 1116 | "node": ">=8" 1117 | }, 1118 | "funding": { 1119 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1120 | } 1121 | }, 1122 | "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { 1123 | "version": "8.0.0", 1124 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 1125 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 1126 | "dev": true 1127 | }, 1128 | "node_modules/wrap-ansi-cjs/node_modules/string-width": { 1129 | "version": "4.2.3", 1130 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1131 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1132 | "dev": true, 1133 | "dependencies": { 1134 | "emoji-regex": "^8.0.0", 1135 | "is-fullwidth-code-point": "^3.0.0", 1136 | "strip-ansi": "^6.0.1" 1137 | }, 1138 | "engines": { 1139 | "node": ">=8" 1140 | } 1141 | }, 1142 | "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { 1143 | "version": "6.0.1", 1144 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1145 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1146 | "dev": true, 1147 | "dependencies": { 1148 | "ansi-regex": "^5.0.1" 1149 | }, 1150 | "engines": { 1151 | "node": ">=8" 1152 | } 1153 | }, 1154 | "node_modules/ws": { 1155 | "version": "7.5.9", 1156 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", 1157 | "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", 1158 | "engines": { 1159 | "node": ">=8.3.0" 1160 | }, 1161 | "peerDependencies": { 1162 | "bufferutil": "^4.0.1", 1163 | "utf-8-validate": "^5.0.2" 1164 | }, 1165 | "peerDependenciesMeta": { 1166 | "bufferutil": { 1167 | "optional": true 1168 | }, 1169 | "utf-8-validate": { 1170 | "optional": true 1171 | } 1172 | } 1173 | } 1174 | } 1175 | } 1176 | -------------------------------------------------------------------------------- /package.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./index.js" 3 | } -------------------------------------------------------------------------------- /package.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "main": "./index.js" 4 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solana-swap", 3 | "version": "1.1.6", 4 | "description": "Solana Swap Library for Solana Tracker Swap API", 5 | "main": "dist/cjs/index.js", 6 | "module": "dist/esm/index.js", 7 | "umd:main": "dist/umd/index.js", 8 | "types": "dist/types/index.d.ts", 9 | "browser": "dist/umd/index.js", 10 | "exports": { 11 | ".": { 12 | "import": "./dist/esm/index.js", 13 | "require": "./dist/cjs/index.js" 14 | } 15 | }, 16 | "scripts": { 17 | "clean": "rimraf dist", 18 | "build:cjs": "tsc --module commonjs --outDir dist/cjs && cp package.cjs.json dist/cjs/package.json", 19 | "build:esm": "tsc --module es2015 --outDir dist/esm && cp package.esm.json dist/esm/package.json", 20 | "build:umd": "tsc --module umd --outDir dist/umd", 21 | "build:types": "tsc --declaration --emitDeclarationOnly --outDir dist/types", 22 | "build": "npm run clean && npm run build:cjs && npm run build:esm && npm run build:umd && npm run build:types", 23 | "watch:build": "tsc --watch", 24 | "watch:server": "nodemon './dist/cjs/index.js' --watch './dist/cjs'", 25 | "start": "npm-run-all build --parallel watch:build watch:server --print-label" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/YZYLAB/solana-swap.git" 30 | }, 31 | "keywords": [ 32 | "solana", 33 | "swap", 34 | "raydium", 35 | "jupiter" 36 | ], 37 | "author": "Solana Tracker", 38 | "license": "ISC", 39 | "bugs": { 40 | "url": "https://github.com/YZYLAB/solana-swap/issues" 41 | }, 42 | "homepage": "https://github.com/YZYLAB/solana-swap#readme", 43 | "dependencies": { 44 | "@solana/web3.js": "^1.91.6", 45 | "axios": "^1.6.8", 46 | "bs58": "^5.0.0", 47 | "promise-retry": "^2.0.1" 48 | }, 49 | "devDependencies": { 50 | "rimraf": "^5.0.7" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import bs58 from "bs58"; 3 | import { 4 | Connection, 5 | Keypair, 6 | Transaction, 7 | VersionedTransaction, 8 | BlockhashWithExpiryBlockHeight, 9 | } from "@solana/web3.js"; 10 | import { transactionSenderAndConfirmationWaiter, TransactionSenderAndConfirmationWaiterOptions } from "./lib/sender"; 11 | import { RateResponse, SwapResponse } from "./types"; 12 | import { sendBundle, createTipTransaction, checkBundleStatus } from "./lib/jito"; 13 | 14 | export class SolanaTracker { 15 | private baseUrl = "https://swap-v2.solanatracker.io"; 16 | private readonly connection: Connection; 17 | private readonly keypair: Keypair; 18 | private readonly apiKey: string; 19 | 20 | constructor(keypair: Keypair, rpc: string, apiKey?: string) { 21 | this.connection = new Connection(rpc); 22 | this.keypair = keypair; 23 | this.apiKey = apiKey || ""; 24 | } 25 | 26 | async setBaseUrl(url: string) { 27 | this.baseUrl = url; 28 | } 29 | 30 | async getRate( 31 | from: string, 32 | to: string, 33 | amount: number, 34 | slippage: number 35 | ): Promise { 36 | const params = new URLSearchParams({ 37 | from, 38 | to, 39 | amount: amount.toString(), 40 | slippage: slippage.toString(), 41 | }); 42 | const url = `${this.baseUrl}/rate?${params}`; 43 | try { 44 | const response = await axios.get(url); 45 | return response.data as RateResponse; 46 | } catch (error) { 47 | throw error; 48 | } 49 | } 50 | 51 | async getSwapInstructions( 52 | from: string, 53 | to: string, 54 | fromAmount: number | string, 55 | slippage: number, 56 | payer: string, 57 | priorityFee?: number, 58 | forceLegacy?: boolean 59 | ): Promise { 60 | const params = new URLSearchParams({ 61 | from, 62 | to, 63 | fromAmount: fromAmount.toString(), 64 | slippage: slippage.toString(), 65 | payer, 66 | forceLegacy: forceLegacy ? "true" : "false", 67 | }); 68 | if (priorityFee) { 69 | params.append("priorityFee", priorityFee.toString()); 70 | } 71 | const url = `${this.baseUrl}/swap?${params}`; 72 | try { 73 | const response = await axios.get(url, { 74 | headers: { 75 | "x-api-key": this.apiKey, 76 | }, 77 | }); 78 | return response.data as SwapResponse; 79 | } catch (error) { 80 | throw error; 81 | } 82 | } 83 | 84 | async performSwap( 85 | swapResponse: SwapResponse, 86 | options: TransactionSenderAndConfirmationWaiterOptions = { 87 | sendOptions: { skipPreflight: true }, 88 | confirmationRetries: 30, 89 | confirmationRetryTimeout: 1000, 90 | lastValidBlockHeightBuffer: 150, 91 | commitment: "processed", 92 | resendInterval: 1000, 93 | confirmationCheckInterval: 1000, 94 | skipConfirmationCheck: false, 95 | jito: { 96 | enabled: false, 97 | tip: 0 98 | } 99 | } 100 | ): Promise { 101 | let serializedTransactionBuffer: Buffer | Uint8Array; 102 | 103 | try { 104 | serializedTransactionBuffer = Buffer.from(swapResponse.txn, "base64"); 105 | } catch (error) { 106 | const base64Str = swapResponse.txn; 107 | const binaryStr = atob(base64Str); 108 | const buffer = new Uint8Array(binaryStr.length); 109 | for (let i = 0; i < binaryStr.length; i++) { 110 | buffer[i] = binaryStr.charCodeAt(i); 111 | } 112 | serializedTransactionBuffer = buffer; 113 | } 114 | let txn: VersionedTransaction | Transaction; 115 | 116 | const blockhash = await this.connection.getLatestBlockhash(); 117 | const blockhashWithExpiryBlockHeight: BlockhashWithExpiryBlockHeight = { 118 | blockhash: blockhash.blockhash, 119 | lastValidBlockHeight: blockhash.lastValidBlockHeight, 120 | }; 121 | 122 | if (swapResponse.txVersion === 'v0') { 123 | txn = VersionedTransaction.deserialize(serializedTransactionBuffer); 124 | txn.sign([this.keypair]); 125 | } else { 126 | txn = Transaction.from(serializedTransactionBuffer); 127 | txn.sign(this.keypair); 128 | } 129 | 130 | if (options.jito?.enabled) { 131 | // Create a tip transaction for the Jito block engine 132 | const tipTxn = await createTipTransaction(this.keypair.publicKey.toBase58(), options.jito.tip); 133 | tipTxn.recentBlockhash = blockhash.blockhash; 134 | tipTxn.sign(this.keypair); 135 | 136 | const response = await sendBundle([bs58.encode(txn.serialize()), bs58.encode(tipTxn.serialize())]); 137 | if (response.result) { 138 | const txid = await checkBundleStatus(response.result, options.confirmationRetries, options.commitment, options.confirmationCheckInterval); 139 | return txid; 140 | } 141 | } 142 | 143 | const txid = await transactionSenderAndConfirmationWaiter({ 144 | connection: this.connection, 145 | serializedTransaction: txn.serialize() as Buffer, 146 | blockhashWithExpiryBlockHeight, 147 | options: options, 148 | }); 149 | return txid.toString(); 150 | } 151 | } -------------------------------------------------------------------------------- /src/lib/jito.ts: -------------------------------------------------------------------------------- 1 | import { Transaction, SystemProgram, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; 2 | import axios from "axios"; 3 | 4 | // Jito Tip Accounts: https://jito-labs.gitbook.io/mev/searcher-resources/json-rpc-api-reference/bundles/gettipaccounts 5 | const tipAccounts = [ 6 | "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5", 7 | "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe", 8 | "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY", 9 | "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49", 10 | "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh", 11 | "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt", 12 | "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL", 13 | "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT" 14 | ]; 15 | 16 | export async function sendBundle(transactions: Array) { 17 | const bundleData = { 18 | jsonrpc: "2.0", 19 | id: 1, 20 | method: "sendBundle", 21 | params: [transactions], 22 | }; 23 | try { 24 | const response = await axios.post( 25 | `https://mainnet.block-engine.jito.wtf/api/v1/bundles`, 26 | bundleData, 27 | { 28 | headers: { 29 | "Content-Type": "application/json", 30 | }, 31 | } 32 | ) 33 | return response.data; 34 | } catch (error: any) { 35 | if (error?.response.data.error) { 36 | throw new Error(JSON.stringify(error?.response.data.error)); 37 | } 38 | 39 | throw new Error("Failed to send bundle."); 40 | } 41 | } 42 | 43 | export const createTipTransaction = async (wallet: string, tip: number) => { 44 | return new Transaction().add( 45 | SystemProgram.transfer({ 46 | fromPubkey: new PublicKey(wallet), 47 | toPubkey: new PublicKey( 48 | tipAccounts[Math.floor(Math.random() * tipAccounts.length)] 49 | ), 50 | lamports: tip * LAMPORTS_PER_SOL, 51 | }) 52 | ) 53 | } 54 | 55 | export async function getBundleStatuses(bundleIds: string[]) { 56 | const bundleData = { 57 | jsonrpc: "2.0", 58 | id: 1, 59 | method: "getBundleStatuses", 60 | params: [bundleIds], 61 | }; 62 | try { 63 | const response = await axios.post( 64 | `https://mainnet.block-engine.jito.wtf/api/v1/bundles`, 65 | bundleData, 66 | { 67 | headers: { 68 | "Content-Type": "application/json", 69 | }, 70 | } 71 | ); 72 | return response.data; 73 | } catch (error: any) { 74 | if (error?.response?.data?.error) { 75 | throw new Error(JSON.stringify(error.response.data.error)); 76 | } 77 | throw new Error("Failed to get bundle statuses."); 78 | } 79 | } 80 | 81 | export async function checkBundleStatus( 82 | bundleId: string, 83 | maxRetries: number = 10, 84 | commitmentLevel: 'processed' | 'confirmed' | 'finalized' = 'confirmed', 85 | retryInterval: number = 1000 86 | ): Promise<'success' | 'not_included' | 'max_retries_reached' | 'error'> { 87 | let retries = 0; 88 | 89 | while (retries < maxRetries) { 90 | try { 91 | const response = await getBundleStatuses([bundleId]); 92 | const bundleInfo = response.result.value.find( 93 | (bundle: any) => bundle.bundle_id === bundleId 94 | ); 95 | 96 | if (!bundleInfo) { 97 | await new Promise(resolve => setTimeout(resolve, retryInterval)); 98 | } 99 | 100 | const status = bundleInfo.confirmation_status; 101 | 102 | const isStatusSufficient = 103 | (commitmentLevel === 'processed' && ['processed', 'confirmed', 'finalized'].includes(status)) || 104 | (commitmentLevel === 'confirmed' && ['confirmed', 'finalized'].includes(status)) || 105 | (commitmentLevel === 'finalized' && status === 'finalized'); 106 | 107 | if (isStatusSufficient) { 108 | if (bundleInfo.err.Ok === null) { 109 | return bundleInfo.transactions[0] 110 | } else { 111 | throw new Error('Jito Bundle Error:' + JSON.stringify(bundleInfo.err)); 112 | } 113 | } 114 | 115 | await new Promise(resolve => setTimeout(resolve, retryInterval)); 116 | retries++; 117 | } catch (error) { 118 | await new Promise(resolve => setTimeout(resolve, retryInterval)); 119 | retries++; 120 | } 121 | } 122 | 123 | throw new Error('Max retries reached while checking bundle status.'); 124 | } -------------------------------------------------------------------------------- /src/lib/sender.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | SendOptions, 4 | TransactionSignature, 5 | Commitment, 6 | } from "@solana/web3.js"; 7 | 8 | interface BlockhashWithExpiryBlockHeight { 9 | blockhash: string; 10 | lastValidBlockHeight: number; 11 | } 12 | 13 | class TransactionError extends Error { 14 | signature: string; 15 | 16 | constructor(message: string, signature: string) { 17 | super(message); 18 | this.name = 'TransactionError'; 19 | this.signature = signature; 20 | } 21 | } 22 | 23 | export const COMMITMENT_LEVELS: Record = { 24 | processed: 0, 25 | confirmed: 1, 26 | finalized: 2, 27 | recent: 0, // Equivalent to 'processed' 28 | single: 1, // Equivalent to 'confirmed' 29 | singleGossip: 1, // Equivalent to 'confirmed' 30 | root: 2, // Equivalent to 'finalized' 31 | max: 2, // Equivalent to 'finalized' 32 | }; 33 | 34 | export type SupportedCommitment = 'processed' | 'confirmed' | 'finalized'; 35 | 36 | export interface TransactionSenderAndConfirmationWaiterOptions { 37 | sendOptions?: SendOptions; 38 | confirmationRetries?: number; 39 | confirmationRetryTimeout?: number; 40 | lastValidBlockHeightBuffer?: number; 41 | resendInterval?: number; 42 | confirmationCheckInterval?: number; 43 | skipConfirmationCheck?: boolean; 44 | commitment?: SupportedCommitment; 45 | jito?: { 46 | enabled: boolean; 47 | tip: number; 48 | }; 49 | } 50 | 51 | const DEFAULT_OPTIONS: TransactionSenderAndConfirmationWaiterOptions = { 52 | sendOptions: { skipPreflight: true }, 53 | confirmationRetries: 30, 54 | confirmationRetryTimeout: 1000, 55 | lastValidBlockHeightBuffer: 150, 56 | resendInterval: 1000, 57 | confirmationCheckInterval: 1000, 58 | skipConfirmationCheck: false, 59 | commitment: "processed", 60 | jito: { 61 | enabled: false, 62 | tip: 0, 63 | } 64 | }; 65 | 66 | async function transactionSenderAndConfirmationWaiter({ 67 | connection, 68 | serializedTransaction, 69 | blockhashWithExpiryBlockHeight, 70 | options = DEFAULT_OPTIONS, 71 | }: { 72 | connection: Connection; 73 | serializedTransaction: Buffer; 74 | blockhashWithExpiryBlockHeight: BlockhashWithExpiryBlockHeight; 75 | options?: Partial; 76 | }): Promise { 77 | const { 78 | sendOptions, 79 | confirmationRetries, 80 | confirmationRetryTimeout, 81 | lastValidBlockHeightBuffer, 82 | resendInterval, 83 | confirmationCheckInterval, 84 | skipConfirmationCheck, 85 | commitment 86 | } = { ...DEFAULT_OPTIONS, ...options }; 87 | 88 | const lastValidBlockHeight = 89 | blockhashWithExpiryBlockHeight.lastValidBlockHeight + 90 | (lastValidBlockHeightBuffer || 150); 91 | 92 | // Send the transaction initially 93 | let signature: TransactionSignature; 94 | try { 95 | signature = await connection.sendRawTransaction( 96 | serializedTransaction, 97 | sendOptions 98 | ); 99 | } catch (error: any) { 100 | throw new TransactionError(`Failed to send transaction: ${error.message}`, ''); 101 | } 102 | 103 | if (skipConfirmationCheck) { 104 | return signature; 105 | } 106 | 107 | // Set up transaction resend interval 108 | const resendIntervalId = resendInterval ? setInterval(async () => { 109 | try { 110 | await connection.sendRawTransaction( 111 | serializedTransaction, 112 | sendOptions 113 | ); 114 | } catch (error) {} 115 | }, resendInterval < 1000 ? 1000 : resendInterval) : null; 116 | 117 | // Loop for confirmation check 118 | let retryCount = 0; 119 | while (retryCount <= (confirmationRetries || 30)) { 120 | try { 121 | const status = await connection.getSignatureStatus(signature); 122 | 123 | if (status.value && status.value.confirmationStatus) { 124 | if (resendIntervalId) { 125 | clearInterval(resendIntervalId); 126 | } 127 | } 128 | if (status.value && status.value.confirmationStatus && 129 | COMMITMENT_LEVELS[status.value.confirmationStatus] >= COMMITMENT_LEVELS[commitment as SupportedCommitment]) { 130 | if (resendIntervalId) { 131 | clearInterval(resendIntervalId); 132 | } 133 | return signature; 134 | } 135 | 136 | if (status.value && status.value.err) { 137 | if (resendIntervalId) { 138 | clearInterval(resendIntervalId); 139 | } 140 | throw new TransactionError(`Transaction failed: ${status.value.err}`, signature); 141 | } 142 | 143 | const blockHeight = await connection.getBlockHeight(); 144 | if (blockHeight > lastValidBlockHeight) { 145 | if (resendIntervalId) { 146 | clearInterval(resendIntervalId); 147 | } 148 | throw new TransactionError("Transaction expired", signature); 149 | } 150 | 151 | await new Promise((resolve) => 152 | setTimeout(resolve, confirmationCheckInterval) 153 | ); 154 | 155 | retryCount++; 156 | } catch (error: any) { 157 | if (resendIntervalId) { 158 | clearInterval(resendIntervalId); 159 | } 160 | if (error instanceof TransactionError) { 161 | throw error; 162 | } 163 | throw new TransactionError(`Confirmation check failed: ${error.message}`, signature); 164 | } 165 | } 166 | 167 | if (resendIntervalId) { 168 | clearInterval(resendIntervalId); 169 | } 170 | throw new TransactionError("Transaction failed after maximum retries", signature); 171 | } 172 | 173 | export { transactionSenderAndConfirmationWaiter }; -------------------------------------------------------------------------------- /src/lib/signature.ts: -------------------------------------------------------------------------------- 1 | import bs58 from "bs58"; 2 | import { Transaction, VersionedTransaction } from "@solana/web3.js"; 3 | 4 | export function getSignature( 5 | transaction: Transaction | VersionedTransaction 6 | ): string { 7 | const signature = 8 | "signature" in transaction 9 | ? transaction.signature 10 | : transaction.signatures[0]; 11 | if (!signature) { 12 | throw new Error( 13 | "Missing transaction signature, the transaction was not signed by the fee payer" 14 | ); 15 | } 16 | return bs58.encode(signature); 17 | } -------------------------------------------------------------------------------- /src/lib/wait.ts: -------------------------------------------------------------------------------- 1 | export const wait = (time: number) => 2 | new Promise((resolve) => setTimeout(resolve, time)); -------------------------------------------------------------------------------- /src/tests/example.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from "@solana/web3.js"; 2 | import bs58 from "bs58"; 3 | import { SolanaTracker } from "../"; 4 | 5 | async function swap() { 6 | const keypair = Keypair.fromSecretKey( 7 | bs58.decode( 8 | "YOUR_SECRET_KEY" 9 | ) 10 | ); 11 | const solanaTracker = new SolanaTracker( 12 | keypair, 13 | "https://rpc-mainnet.solanatracker.io/?api_key=YOUR_API_KEY" // Staked RPC: https://www.solanatracker.io/solana-rpc 14 | ); 15 | 16 | const swapResponse = await solanaTracker.getSwapInstructions( 17 | "So11111111111111111111111111111111111111112", // From Token 18 | "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R", // To Token 19 | 0.0001, // Amount to swap 20 | 30, // Slippage 21 | keypair.publicKey.toBase58(), // Payer public key 22 | 0.0005, // Priority fee (Recommended while network is congested) 23 | ); 24 | 25 | // Regular transaction 26 | try { 27 | const txid = await solanaTracker.performSwap(swapResponse, { 28 | sendOptions: { skipPreflight: true }, 29 | confirmationRetries: 30, 30 | confirmationRetryTimeout: 500, 31 | lastValidBlockHeightBuffer: 150, 32 | resendInterval: 1000, 33 | confirmationCheckInterval: 1000, 34 | commitment: "processed", 35 | skipConfirmationCheck: false // Set to true if you want to skip confirmation checks and return txid immediately 36 | }); 37 | // Returns txid when the swap is successful or throws an error if the swap fails 38 | console.log("Transaction ID:", txid); 39 | console.log("Transaction URL:", `https://solscan.io/tx/${txid}`); 40 | } catch (error: any) { 41 | const {signature, message} = error; 42 | console.error("Error performing swap:", message, signature); 43 | } 44 | 45 | 46 | // Jito transaction 47 | try { 48 | const txid = await solanaTracker.performSwap(swapResponse, { 49 | sendOptions: { skipPreflight: true }, 50 | confirmationRetries: 30, 51 | confirmationCheckInterval: 500, 52 | commitment: "processed", 53 | jito: { 54 | enabled: true, 55 | tip: 0.0001, 56 | }, 57 | }); 58 | // Returns txid when the swap is successful or throws an error if the swap fails 59 | console.log("Transaction ID:", txid); 60 | console.log("Transaction URL:", `https://solscan.io/tx/${txid}`); 61 | } catch (error: any) { 62 | const {signature, message} = error; 63 | console.error("Error performing swap:", message, signature); 64 | } 65 | } 66 | 67 | swap(); 68 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export interface RateResponse { 2 | amountIn: number; 3 | amountOut: number; 4 | minAmountOut: number; 5 | currentPrice: number; 6 | executionPrice: number; 7 | priceImpact: number; 8 | fee: number; 9 | baseCurrency: { 10 | decimals: number; 11 | mint: string; 12 | }; 13 | quoteCurrency: { 14 | decimals: number; 15 | mint: string; 16 | }; 17 | platformFee: number; 18 | platformFeeUI: number; 19 | rawQuoteResponse: any; 20 | } 21 | 22 | export interface SwapResponse { 23 | txn: string; 24 | txVersion: string; 25 | rate: RateResponse; 26 | forceLegacy?: boolean; 27 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "moduleResolution": "node", 5 | "declaration": true, 6 | "outDir": "./dist", 7 | "strict": true, 8 | "esModuleInterop": true 9 | }, 10 | "include": [ 11 | "src/**/*" 12 | ], 13 | "exclude": [ 14 | "node_modules", 15 | "dist" 16 | ] 17 | } --------------------------------------------------------------------------------