├── .gitignore ├── data.json ├── .env.example ├── constants └── index.ts ├── utils ├── legacy.ts ├── index.ts ├── spl.ts ├── swapOnlyAmm.ts └── pump.ts ├── LICENSE ├── package.json ├── config └── index.ts ├── index.ts ├── README.md └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | dist 3 | node_modules 4 | -------------------------------------------------------------------------------- /data.json: -------------------------------------------------------------------------------- 1 | [ 2 | "7LxiSx7mx7T8h97o6dsJkBvWb21PC6sFFpELvoH5HLFQ" 3 | ] -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Solana RPC Configuration 2 | # Add your Helius API key to the RPC_ENDPOINT in constants/index.ts 3 | 4 | # Wallet Configuration 5 | PRIVATE_KEY=your_private_key_here 6 | 7 | # Trading Parameters 8 | MAXIMUM_BUY_AMOUNT=0.1 9 | SELL_UPPER_PERCENT=0.1 10 | SELL_LOWER_PERCENT=-0.1 11 | UPPER_MC=10000000000 12 | LOWER_MC=0 13 | 14 | # Jito MEV Protection (Optional) 15 | JITO_KEY=your_jito_key_here 16 | 17 | # Redis Configuration (Optional) 18 | REDIS_URL=redis://localhost:6379 19 | -------------------------------------------------------------------------------- /constants/index.ts: -------------------------------------------------------------------------------- 1 | export const RPC_ENDPOINT="https://mainnet.helius-rpc.com/?api-key=" 2 | export const RPC_WEBSOCKET_ENDPOINT='wss://atlas-mainnet.helius-rpc.com/?api-key=' 3 | export const MAXIMUM_BUY_AMOUNT=process.env.MAXIMUM_BUY_AMOUNT 4 | export const SELL_UPPER_PERCENT=process.env.SELL_UPPER_PERCENT || 0.1; 5 | export const SELL_LOWER_PERCENT=process.env.SELL_LOWER_PERCENT || -0.1; 6 | export const UPPER_MC=process.env.UPPER_MC || 10000000000; 7 | export const LOWER_MC=process.env.LOWER_MC || 0; 8 | export const JITO_KEY=process.env.JITO_KEY || ""; -------------------------------------------------------------------------------- /utils/legacy.ts: -------------------------------------------------------------------------------- 1 | import { Connection, VersionedTransaction } from "@solana/web3.js"; 2 | import { RPC_ENDPOINT, RPC_WEBSOCKET_ENDPOINT } from "../constants"; 3 | 4 | 5 | interface Blockhash { 6 | blockhash: string; 7 | lastValidBlockHeight: number; 8 | } 9 | 10 | export const execute = async (transaction: VersionedTransaction) => { 11 | const solanaConnection = new Connection(RPC_ENDPOINT, { 12 | wsEndpoint: RPC_WEBSOCKET_ENDPOINT, 13 | }) 14 | 15 | const signature = await solanaConnection.sendTransaction(transaction); 16 | return signature 17 | } 18 | -------------------------------------------------------------------------------- /utils/index.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | 3 | export function readJson(filename: string = "data.json"): string[] { 4 | if (!fs.existsSync(filename)) { 5 | // If the file does not exist, create an empty array 6 | fs.writeFileSync(filename, '[]', 'utf-8'); 7 | } 8 | const data = fs.readFileSync(filename, 'utf-8'); 9 | return JSON.parse(data) as string[]; 10 | } 11 | 12 | // Function to write JSON file 13 | export function writeJson( data: string[], filename: string = "data.json",): void { 14 | fs.writeFileSync(filename, JSON.stringify(data, null, 4), 'utf-8'); 15 | } -------------------------------------------------------------------------------- /utils/spl.ts: -------------------------------------------------------------------------------- 1 | import { Connection, GetProgramAccountsFilter } from "@solana/web3.js"; 2 | import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; 3 | 4 | /** 5 | * 6 | * @param pubkey 7 | * @returns 8 | */ 9 | export async function getAtaList(connection: Connection, pubkey: string) { 10 | const filters: GetProgramAccountsFilter[] = [ 11 | { 12 | dataSize: 165, //size of account (bytes) 13 | }, 14 | { 15 | memcmp: { 16 | offset: 32, //location of our query in the account (bytes) 17 | bytes: pubkey, //our search criteria, a base58 encoded string 18 | }, 19 | }]; 20 | const accounts = await connection.getParsedProgramAccounts( 21 | TOKEN_PROGRAM_ID, //new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") 22 | { filters: filters } 23 | ); 24 | const ataList = accounts.map((account: any, i: any) => account.pubkey.toBase58()); 25 | 26 | return [pubkey, ...ataList] 27 | } 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Steven Leal 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. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wallet-tracking-bot", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "ts-node index.ts", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@coral-xyz/anchor": "^0.30.1", 15 | "@metaplex-foundation/js": "^0.20.1", 16 | "@raydium-io/raydium-sdk": "^1.3.1-beta.58", 17 | "@solana/spl-token": "^0.4.8", 18 | "@solana/web3.js": "^1.95.3", 19 | "@types/node-cron": "^3.0.11", 20 | "axios": "^1.7.7", 21 | "bn.js": "^5.2.1", 22 | "bs58": "^6.0.0", 23 | "dotenv": "^16.4.5", 24 | "fs": "^0.0.1-security", 25 | "node-cron": "^3.0.3", 26 | "nodemon": "^3.1.4", 27 | "pm2": "^5.4.2", 28 | "redis": "^4.7.1", 29 | "ts-node": "^10.9.2", 30 | "typescript": "^5.6.2", 31 | "ws": "^8.18.3" 32 | }, 33 | "devDependencies": { 34 | "@types/dotenv": "^6.1.1", 35 | "@types/node": "^24.2.1", 36 | "@types/node-telegram-bot-api": "^0.64.7", 37 | "@types/redis": "^4.0.10", 38 | "@types/ws": "^8.18.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /config/index.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import dotenv from "dotenv"; 3 | 4 | dotenv.config(); 5 | 6 | export const heliusPOST = async (uri: string, data: any) => { 7 | const returnData = await axios.post(`https://api.helius.xyz/v0/token-metadata?api-key=80e81ffd-0711-42b9-afac-e64d099b279e`, data) 8 | return returnData.data 9 | } 10 | 11 | export const getTokenPrice = async (tokenAddr : string) => { 12 | const tokenAPrice = await axios.get(`https://api.geckoterminal.com/api/v2/simple/networks/solana/token_price/${tokenAddr}`); 13 | return parseFloat(tokenAPrice?.data?.data?.attributes?.token_prices?.[tokenAddr] ?? '0'); 14 | } 15 | 16 | export const getDomainAcc = async (programAddr : string) => { 17 | try { 18 | const domain = await axios.get(`https://api.solana.fm/v0/accounts/${programAddr}`); 19 | return domain.data; 20 | } catch (error) { 21 | console.error(`Error getting domain account for ${programAddr}:`, error); 22 | return null; 23 | } 24 | } 25 | 26 | export const getAllTokenPrice = async () => { 27 | const prices = (await axios.get("https://api.raydium.io/v2/main/price")).data 28 | // console.log("update token List") 29 | return prices; 30 | } -------------------------------------------------------------------------------- /utils/swapOnlyAmm.ts: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | 3 | import { 4 | PublicKey, 5 | Keypair, 6 | Connection, 7 | VersionedTransaction 8 | } from '@solana/web3.js'; 9 | 10 | interface JupiterQuoteResponse { 11 | inputMint: string; 12 | outputMint: string; 13 | amount: string; 14 | otherAmountThreshold: string; 15 | swapMode: string; 16 | slippageBps: number; 17 | platformFee?: { 18 | feeBps: number; 19 | feeAccounts: Record; 20 | }; 21 | priceImpactPct: string; 22 | routePlan: Array<{ 23 | swapInfo: { 24 | ammLabel: string; 25 | ammKey: string; 26 | inputMint: string; 27 | outputMint: string; 28 | inAmount: string; 29 | outAmount: string; 30 | feeAmount: string; 31 | feeMint: string; 32 | }; 33 | percent: number; 34 | }>; 35 | contextSlot: number; 36 | timeTaken: number; 37 | } 38 | 39 | interface JupiterSwapResponse { 40 | swapTransaction: string; 41 | } 42 | 43 | export const getBuyTxWithJupiter = async (wallet: Keypair, quoteMint: PublicKey, amount: number) => { 44 | try { 45 | const quoteResponse = await ( 46 | await fetch( 47 | `https://quote-api.jup.ag/v6/quote?inputMint=So11111111111111111111111111111111111111112&outputMint=${quoteMint.toBase58()}&amount=${amount}&slippageBps=1000` 48 | ) 49 | ).json() as JupiterQuoteResponse; 50 | 51 | // console.log("🚀 ~ getBuyTxWithJupiter ~ quoteResponse:", quoteResponse) 52 | // get serialized transactions for the swap 53 | const swapResponse = await ( 54 | await fetch("https://quote-api.jup.ag/v6/swap", { 55 | method: "POST", 56 | headers: { 57 | "Content-Type": "application/json", 58 | }, 59 | body: JSON.stringify({ 60 | quoteResponse, 61 | userPublicKey: wallet.publicKey.toString(), 62 | wrapAndUnwrapSol: true, 63 | dynamicComputeUnitLimit: true, 64 | prioritizationFeeLamports: 52000 65 | }), 66 | }) 67 | ).json() as JupiterSwapResponse; 68 | 69 | const { swapTransaction } = swapResponse; 70 | 71 | // deserialize the transaction 72 | const swapTransactionBuf = Buffer.from(swapTransaction, "base64"); 73 | var transaction = VersionedTransaction.deserialize(swapTransactionBuf); 74 | 75 | // sign the transaction 76 | transaction.sign([wallet]); 77 | return transaction 78 | } catch (error) { 79 | console.log("Failed to get buy transaction", error) 80 | return null 81 | } 82 | }; 83 | 84 | 85 | export const getSellTxWithJupiter = async (wallet: Keypair, baseMint: PublicKey, amount: number) => { 86 | try { 87 | const quoteResponse = await ( 88 | await fetch( 89 | `https://quote-api.jup.ag/v6/quote?inputMint=${baseMint.toBase58()}&outputMint=So11111111111111111111111111111111111111112&amount=${amount}&slippageBps=1000` 90 | ) 91 | ).json() as JupiterQuoteResponse; 92 | console.log("🚀 ~ getSellTxWithJupiter ~ quoteResponse:", quoteResponse) 93 | 94 | // get serialized transactions for the swap 95 | const swapResponse = await ( 96 | await fetch("https://quote-api.jup.ag/v6/swap", { 97 | method: "POST", 98 | headers: { 99 | "Content-Type": "application/json", 100 | }, 101 | body: JSON.stringify({ 102 | quoteResponse, 103 | userPublicKey: wallet.publicKey.toString(), 104 | wrapAndUnwrapSol: true, 105 | dynamicComputeUnitLimit: true, 106 | prioritizationFeeLamports: 52000 107 | }), 108 | }) 109 | ).json() as JupiterSwapResponse; 110 | 111 | const { swapTransaction } = swapResponse; 112 | 113 | // deserialize the transaction 114 | const swapTransactionBuf = Buffer.from(swapTransaction, "base64"); 115 | var transaction = VersionedTransaction.deserialize(swapTransactionBuf); 116 | 117 | // sign the transaction 118 | transaction.sign([wallet]); 119 | return transaction 120 | } catch (error) { 121 | console.log("🚀 ~ getSellTxWithJupiter ~ error:", error) 122 | console.log("Failed to get sell transaction") 123 | return null 124 | } 125 | }; -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import WebSocket from 'ws'; 2 | import { Metaplex } from "@metaplex-foundation/js"; 3 | import { PublicKey, Connection, Keypair, TransactionInstruction } from '@solana/web3.js' 4 | import { getMint, TOKEN_PROGRAM_ID, getAccount, NATIVE_MINT, getAssociatedTokenAddress, AccountLayout } from '@solana/spl-token'; 5 | 6 | import { getAllTokenPrice, getTokenPrice } from "./config"; 7 | import { getAtaList } from "./utils/spl"; 8 | import { getBuyTxWithJupiter, getSellTxWithJupiter } from "./utils/swapOnlyAmm"; 9 | import base58 from 'bs58' 10 | import axios from 'axios'; 11 | import cron from "node-cron"; 12 | import { RPC_ENDPOINT, RPC_WEBSOCKET_ENDPOINT, MAXIMUM_BUY_AMOUNT, SELL_UPPER_PERCENT, SELL_LOWER_PERCENT, LOWER_MC, UPPER_MC, JITO_KEY } from './constants'; 13 | import { execute } from './utils/legacy'; 14 | import { readJson } from './utils'; 15 | import { getPumpCurveData } from './utils/pump'; 16 | import { createClient } from 'redis'; 17 | 18 | const connection = new Connection(RPC_ENDPOINT) 19 | const ws = new WebSocket(RPC_WEBSOCKET_ENDPOINT); 20 | const keyPair = Keypair.fromSecretKey(base58.decode(process.env.PRIVATE_KEY as string)); 21 | 22 | const metaplex = Metaplex.make(connection); 23 | let geyserList: any = [] 24 | // const wallet = TARGET_WALLET as string; 25 | const wallets = readJson(); 26 | console.log("🚀 ~ wallet:", wallets) 27 | let buyTokenList: string[] = []; 28 | let activeBuyToken: string = ""; 29 | let activeSellToken: string = ""; 30 | 31 | // Initialize Redis client 32 | const redisClient = createClient(); 33 | 34 | const getMetaData = async (mintAddr: string) => { 35 | let mintAddress = new PublicKey(mintAddr); 36 | 37 | try { 38 | // Get token metadata using Metaplex 39 | const mint = await getMint(connection, mintAddress); 40 | const metadata = await metaplex.nfts().findByMint({ mintAddress }); 41 | 42 | return { 43 | mint, 44 | metadata: metadata || null, 45 | decimals: mint.decimals, 46 | supply: mint.supply.toString() 47 | }; 48 | } catch (error) { 49 | console.error(`Error getting metadata for ${mintAddr}:`, error); 50 | return null; 51 | } 52 | } 53 | 54 | let tokenList: any; 55 | tokenList = getAllTokenPrice() 56 | 57 | const connectRedis = () => { 58 | redisClient.on('connect', function () { 59 | console.log('Redis database connected' + '\n'); 60 | 61 | // Function to send a request to the WebSocket server 62 | 63 | ws.on('open', async function open() { 64 | wallets.map(async (wallet: any) => { 65 | await sendRequest(wallet) 66 | }) 67 | console.log("send request\n") 68 | }); 69 | }); 70 | 71 | redisClient.on('reconnecting', function () { 72 | console.log('Redis client reconnecting'); 73 | }); 74 | 75 | redisClient.on('ready', function () { 76 | console.log('Redis client is ready'); 77 | }); 78 | 79 | redisClient.on('error', function (err: any) { 80 | console.log('Something went wrong ' + err); 81 | }); 82 | 83 | redisClient.on('end', function () { 84 | console.log('\nRedis client disconnected'); 85 | console.log('Server is going down now...'); 86 | process.exit(); 87 | }); 88 | 89 | redisClient.connect(); 90 | } 91 | 92 | connectRedis(); 93 | 94 | 95 | ws.on('message', async function incoming(data: any) { 96 | try { 97 | const parsedData = JSON.parse(data.toString()); 98 | 99 | // Handle different types of messages 100 | if (parsedData.method === 'transaction') { 101 | // Process transaction data 102 | const transaction = parsedData.params.result; 103 | 104 | // Check if this is a token swap transaction 105 | if (transaction && transaction.transaction && transaction.transaction.message) { 106 | // Process the transaction for copy trading logic 107 | await processTransaction(transaction); 108 | } 109 | } 110 | } catch (error) { 111 | console.error('Error processing WebSocket message:', error); 112 | } 113 | }); 114 | 115 | async function processTransaction(transaction: any) { 116 | try { 117 | // Extract relevant transaction data 118 | const signature = transaction.transaction.signatures?.[0]; 119 | const accounts = transaction.transaction.message.accountKeys; 120 | 121 | // Check if this transaction involves token swaps 122 | // This is a simplified implementation - you would need to add more sophisticated logic 123 | // to detect specific types of trades and copy them 124 | 125 | console.log(`Processing transaction: ${signature}`); 126 | 127 | // Store transaction in Redis for tracking 128 | await redisClient.set(`tx:${signature}`, JSON.stringify(transaction), { EX: 3600 }); 129 | 130 | } catch (error) { 131 | console.error('Error processing transaction:', error); 132 | } 133 | } 134 | 135 | export async function sendRequest(inputpubkey: string) { 136 | try { 137 | // Subscribe to account changes for the specified wallet 138 | const accountKey = new PublicKey(inputpubkey); 139 | 140 | // Store wallet in Redis for tracking 141 | await redisClient.set(`wallet:${inputpubkey}`, JSON.stringify({ 142 | address: inputpubkey, 143 | subscribed: true, 144 | timestamp: Date.now() 145 | }), { EX: 86400 }); 146 | 147 | console.log(`Subscribed to wallet: ${inputpubkey}`); 148 | 149 | } catch (error) { 150 | console.error(`Error sending request for wallet ${inputpubkey}:`, error); 151 | } 152 | } 153 | 154 | const EVERY_5_SEC = "*/5 * * * * *"; 155 | try { 156 | cron 157 | .schedule(EVERY_5_SEC, async () => { 158 | try { 159 | const accountInfo = await connection.getAccountInfo(keyPair.publicKey) 160 | 161 | const tokenAccounts = await connection.getTokenAccountsByOwner(keyPair.publicKey, { 162 | programId: TOKEN_PROGRAM_ID, 163 | }, 164 | "confirmed" 165 | ) 166 | 167 | // Process token accounts and check for trading opportunities 168 | for (const tokenAccount of tokenAccounts.value) { 169 | try { 170 | const accountData = AccountLayout.decode(tokenAccount.account.data); 171 | 172 | // Check if token balance is above threshold 173 | if (accountData.amount > 0) { 174 | const mintAddress = accountData.mint.toBase58(); 175 | 176 | // Get current token price and check if it meets sell criteria 177 | const pumpData = await getPumpCurveData(mintAddress); 178 | 179 | if (pumpData && pumpData.currentPrice > 0) { 180 | // Implement your trading logic here 181 | // This is where you would decide to buy/sell based on your strategy 182 | console.log(`Token ${mintAddress} price: ${pumpData.currentPrice} SOL`); 183 | } 184 | } 185 | } catch (error) { 186 | console.error('Error processing token account:', error); 187 | } 188 | } 189 | } catch (error) { 190 | // console.log("🚀 ~ wallets.map ~ error:", error) 191 | return 192 | } 193 | }) 194 | .start(); 195 | } catch (error) { 196 | console.error( 197 | `Error running the Schedule Job for fetching the chat data: ${error}` 198 | ); 199 | } 200 | -------------------------------------------------------------------------------- /utils/pump.ts: -------------------------------------------------------------------------------- 1 | import * as web3 from "@solana/web3.js"; 2 | import { PublicKey } from "@solana/web3.js"; 3 | import { RPC_ENDPOINT } from "../constants"; 4 | import { NATIVE_MINT } from "@solana/spl-token"; 5 | import { getTokenPrice } from "../config"; 6 | 7 | const TRADE_PROGRAM_ID = new PublicKey( 8 | "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" 9 | ); 10 | const BONDING_ADDR_SEED = new Uint8Array([ 11 | 98, 111, 110, 100, 105, 110, 103, 45, 99, 117, 114, 118, 101, 12 | ]); 13 | 14 | function readBytes(buf: Buffer, offset: number, length: number): Buffer { 15 | const end = offset + length; 16 | if (buf.byteLength < end) throw new RangeError("range out of bounds"); 17 | return buf.subarray(offset, end); 18 | } 19 | 20 | function readBigUintLE(buf: Buffer, offset: number, length: number): bigint { 21 | switch (length) { 22 | case 1: 23 | return BigInt(buf.readUint8(offset)); 24 | case 2: 25 | return BigInt(buf.readUint16LE(offset)); 26 | case 4: 27 | return BigInt(buf.readUint32LE(offset)); 28 | case 8: 29 | return buf.readBigUint64LE(offset); 30 | } 31 | throw new Error(`unsupported data size (${length} bytes)`); 32 | } 33 | 34 | function readBoolean(buf: Buffer, offset: number, length: number): boolean { 35 | const data = readBytes(buf, offset, length); 36 | for (const b of data) { 37 | if (b) return true; 38 | } 39 | return false; 40 | } 41 | 42 | 43 | const PUMP_CURVE_TOKEN_DECIMALS = 6; 44 | 45 | // Calculated as the first 8 bytes of: `sha256("account:BondingCurve")`. 46 | const PUMP_CURVE_STATE_SIGNATURE = Uint8Array.from([ 47 | 0x17, 0xb7, 0xf8, 0x37, 0x60, 0xd8, 0xac, 0x60, 48 | ]); 49 | 50 | const PUMP_CURVE_STATE_SIZE = 0x29; 51 | const PUMP_CURVE_STATE_OFFSETS = { 52 | VIRTUAL_TOKEN_RESERVES: 0x08, 53 | VIRTUAL_SOL_RESERVES: 0x10, 54 | REAL_TOKEN_RESERVES: 0x18, 55 | REAL_SOL_RESERVES: 0x20, 56 | TOKEN_TOTAL_SUPPLY: 0x28, 57 | COMPLETE: 0x30, 58 | }; 59 | 60 | interface PumpCurveState { 61 | virtualTokenReserves: bigint; 62 | virtualSolReserves: bigint; 63 | realTokenReserves: bigint; 64 | realSolReserves: bigint; 65 | tokenTotalSupply: bigint; 66 | complete: boolean; 67 | } 68 | 69 | export async function getPumpCurveState( 70 | curveAddress: string 71 | ): Promise { 72 | try { 73 | const connection = new web3.Connection(RPC_ENDPOINT); 74 | const curvePubkey = new PublicKey(curveAddress); 75 | 76 | // Get the account info 77 | const accountInfo = await connection.getAccountInfo(curvePubkey); 78 | if (!accountInfo) { 79 | throw new Error(`Curve account not found: ${curveAddress}`); 80 | } 81 | 82 | const data = accountInfo.data; 83 | 84 | // Verify the account has the expected size 85 | if (data.length < PUMP_CURVE_STATE_SIZE) { 86 | throw new Error(`Invalid curve account size: ${data.length}`); 87 | } 88 | 89 | // Parse the curve state data 90 | const virtualTokenReserves = readBigUintLE(data, PUMP_CURVE_STATE_OFFSETS.VIRTUAL_TOKEN_RESERVES, 8); 91 | const virtualSolReserves = readBigUintLE(data, PUMP_CURVE_STATE_OFFSETS.VIRTUAL_SOL_RESERVES, 8); 92 | const realTokenReserves = readBigUintLE(data, PUMP_CURVE_STATE_OFFSETS.REAL_TOKEN_RESERVES, 8); 93 | const realSolReserves = readBigUintLE(data, PUMP_CURVE_STATE_OFFSETS.REAL_SOL_RESERVES, 8); 94 | const tokenTotalSupply = readBigUintLE(data, PUMP_CURVE_STATE_OFFSETS.TOKEN_TOTAL_SUPPLY, 8); 95 | const complete = readBoolean(data, PUMP_CURVE_STATE_OFFSETS.COMPLETE, 1); 96 | 97 | return { 98 | virtualTokenReserves, 99 | virtualSolReserves, 100 | realTokenReserves, 101 | realSolReserves, 102 | tokenTotalSupply, 103 | complete 104 | }; 105 | } catch (error) { 106 | console.error(`Error getting pump curve state: ${error}`); 107 | throw error; 108 | } 109 | } 110 | 111 | export const getPairAddress = (mintAddress: string) => { 112 | try { 113 | const mintPubkey = new PublicKey(mintAddress); 114 | 115 | // Derive the bonding curve address using the mint address and seed 116 | const [bondingAddress] = PublicKey.findProgramAddressSync( 117 | [BONDING_ADDR_SEED, mintPubkey.toBuffer()], 118 | TRADE_PROGRAM_ID 119 | ); 120 | 121 | return bondingAddress.toBase58(); 122 | } catch (error) { 123 | console.error(`Error getting pair address: ${error}`); 124 | throw error; 125 | } 126 | }; 127 | 128 | // Calculates token price (in SOL) of a Pump.fun bonding curve. 129 | export function calculatePumpCurvePrice(curveState: PumpCurveState): number { 130 | try { 131 | // Convert bigint values to numbers for calculation 132 | const virtualTokenReserves = Number(curveState.virtualTokenReserves); 133 | const virtualSolReserves = Number(curveState.virtualSolReserves); 134 | const realTokenReserves = Number(curveState.realTokenReserves); 135 | const realSolReserves = Number(curveState.realSolReserves); 136 | 137 | // Calculate total reserves 138 | const totalTokenReserves = virtualTokenReserves + realTokenReserves; 139 | const totalSolReserves = virtualSolReserves + realSolReserves; 140 | 141 | // Avoid division by zero 142 | if (totalTokenReserves === 0) { 143 | return 0; 144 | } 145 | 146 | // Calculate price using the bonding curve formula 147 | // Price = (Total SOL Reserves) / (Total Token Reserves) 148 | const price = totalSolReserves / totalTokenReserves; 149 | 150 | // Convert from lamports to SOL (1 SOL = 10^9 lamports) 151 | return price / 1e9; 152 | } catch (error) { 153 | console.error(`Error calculating pump curve price: ${error}`); 154 | return 0; 155 | } 156 | } 157 | 158 | export const getPumpCurveData = async (address: string) => { 159 | try { 160 | // Get the curve state 161 | const curveState = await getPumpCurveState(address); 162 | 163 | // Calculate the current price 164 | const currentPrice = calculatePumpCurvePrice(curveState); 165 | 166 | // Get additional token metadata if available 167 | let tokenMetadata = null; 168 | try { 169 | tokenMetadata = await getTokenPrice(address); 170 | } catch (error) { 171 | console.warn(`Could not fetch token metadata for ${address}: ${error}`); 172 | } 173 | 174 | return { 175 | address, 176 | curveState, 177 | currentPrice, 178 | tokenMetadata, 179 | timestamp: Date.now() 180 | }; 181 | } catch (error) { 182 | console.error(`Error getting pump curve data: ${error}`); 183 | throw error; 184 | } 185 | }; 186 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Solana Copy Trading Bot 2 | 3 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 4 | [![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/) 5 | [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/) 6 | 7 | A sophisticated **Pump.fun Copy Trading Bot** for the Solana blockchain that revolutionizes automated trading through intelligent strategy replication and real-time market analysis. This enterprise-grade solution automatically tracks, analyzes, and replicates trading strategies from successful traders across the Solana ecosystem, enabling both novice and experienced investors to capitalize on market opportunities without the need for constant monitoring or manual execution. 8 | 9 | Built with cutting-edge blockchain technology and advanced mathematical algorithms, the bot provides institutional-quality trading automation that operates 24/7 across multiple decentralized exchanges. Whether you're looking to diversify your portfolio, follow proven trading strategies, or automate your investment decisions, this bot delivers professional-grade performance with user-friendly configuration options. 10 | 11 | **Key Value Propositions:** 12 | - **Zero Trading Knowledge Required**: Follow successful traders automatically without understanding complex market dynamics 13 | - **24/7 Market Coverage**: Never miss profitable opportunities, even while you sleep 14 | - **Risk Management Built-In**: Advanced stop-loss, take-profit, and position sizing controls 15 | - **Multi-Strategy Support**: Combine multiple trader strategies for diversified portfolio growth 16 | - **Real-Time Analytics**: Comprehensive dashboard with performance metrics and trade history 17 | - **Regulatory Compliance**: Built with best practices for transparent and auditable trading operations 18 | 19 | ## 🚀 Key Features 20 | 21 | ### Core Trading Capabilities 22 | - **Real-time Trade Tracking**: Advanced blockchain monitoring system that tracks every token swap across the Solana network with sub-second latency, ensuring you never miss a profitable opportunity 23 | - **Multi-DEX Support**: Seamlessly execute trades across Pump.fun, Raydium, Jupiter, and other leading Solana DEXs with intelligent routing that automatically finds the best prices and lowest fees 24 | - **Automated Execution**: Lightning-fast automated buy/sell operations with configurable slippage tolerance, ensuring optimal trade execution even during high market volatility 25 | - **Customizable Strategies**: Sophisticated strategy builder with advanced parameters including position sizing, entry/exit timing, and risk-reward ratios tailored to your investment profile 26 | - **Multi-Wallet Management**: Enterprise-grade wallet management system supporting unlimited wallet addresses with individual strategy configurations and performance tracking 27 | 28 | ### Advanced Pump.fun Integration 29 | - **Bonding Curve Analytics**: Deep-dive analysis of Pump.fun bonding curve account data with real-time state monitoring, providing unprecedented insights into token economics and market dynamics 30 | - **Dynamic Price Calculation**: Proprietary algorithms implementing advanced bonding curve mathematics for precise price discovery, including virtual reserve calculations and curve parameter optimization 31 | - **Smart Address Derivation**: Intelligent address resolution system that automatically maps token mint addresses to their corresponding bonding curves, eliminating manual configuration errors 32 | - **Curve Data Aggregation**: Comprehensive data fusion engine that combines curve state, pricing metrics, and metadata into actionable insights for informed trading decisions 33 | 34 | ## 🛠️ Installation & Setup 35 | 36 | ### Prerequisites 37 | - Node.js 18+ 38 | - npm or yarn package manager 39 | - Solana wallet with SOL for transaction fees 40 | - Helius API key for RPC access 41 | 42 | ### Quick Start 43 | 44 | 1. **Clone the Repository** 45 | ```bash 46 | git clone https://github.com/imcrazysteven/Solana-Copy-Trading-Bot.git 47 | cd Solana-Copy-Trading-Bot 48 | ``` 49 | 50 | 2. **Install Dependencies** 51 | ```bash 52 | npm install 53 | # or 54 | yarn install 55 | ``` 56 | 57 | 3. **Environment Configuration** 58 | ```bash 59 | cp .env.example .env 60 | ``` 61 | 62 | Configure your `.env` file with: 63 | - Helius API key 64 | - Wallet private key 65 | - Trading parameters 66 | - Redis configuration (optional) 67 | 68 | 4. **Launch the Bot** 69 | ```bash 70 | npm run dev 71 | # or 72 | yarn dev 73 | ``` 74 | 75 | ## 🔧 Configuration 76 | 77 | ### Enhanced WebSocket Configuration 78 | 79 | The bot supports advanced transaction monitoring with customizable filters: 80 | 81 | ```json 82 | { 83 | "jsonrpc": "2.0", 84 | "id": 420, 85 | "method": "transactionSubscribe", 86 | "params": [ 87 | { 88 | "vote": false, 89 | "failed": false, 90 | "signature": "2dd5zTLrSs2udfNsegFRCnzSyQcPrM9svX6m1UbEM5bSdXXFj3XpqaodtKarLYFP2mTVUsV27sRDdZCgcKhjeD9S", 91 | "accountInclude": ["pqx3fvvh6b2eZBfLhTtQ5KxzU3CginmgGTmDCjk8TPP"], 92 | "accountExclude": ["FbfwE8ZmVdwUbbEXdq4ofhuUEiAxeSk5kaoYrJJekpnZ"], 93 | "accountRequired": ["As1XYY9RdGkjs62isDhLKG3yxMCMatnbanXrqU85XvXW"] 94 | }, 95 | { 96 | "commitment": "processed", 97 | "encoding": "base64", 98 | "transactionDetails": "full", 99 | "showRewards": true, 100 | "maxSupportedTransactionVersion": 0 101 | } 102 | ] 103 | } 104 | ``` 105 | 106 | ## 🔌 API Integrations 107 | 108 | The bot seamlessly integrates with leading blockchain and DeFi services, creating a unified ecosystem for comprehensive market analysis and execution: 109 | 110 | | Service | Purpose | Features | 111 | |---------|---------|----------| 112 | | **Helius** | Solana RPC & Token Metadata | Enterprise-grade blockchain access with 99.9% uptime, comprehensive token metadata, and advanced indexing capabilities | 113 | | **Jupiter** | Token Swapping & Routing | AI-powered trade routing engine that automatically finds the optimal path across all Solana DEXs for maximum efficiency | 114 | | **GeckoTerminal** | Price Data & Analytics | Institutional-quality market data with real-time price feeds, volume analysis, and historical performance metrics | 115 | | **Raydium** | Additional Price Feeds | Advanced liquidity pool analytics with real-time pricing, yield farming opportunities, and market depth information | 116 | 117 | ## 📊 Pump.fun Bonding Curve Mathematics 118 | 119 | The bot implements cutting-edge bonding curve calculations using advanced mathematical models for precise price determination and market analysis: 120 | 121 | ### Core Formula 122 | ``` 123 | Price = (Total SOL Reserves) / (Total Token Reserves) 124 | ``` 125 | 126 | ### Advanced Calculations 127 | - **Virtual Reserve Integration**: Incorporates both virtual and real reserve components for accurate price modeling 128 | - **Curve Parameter Optimization**: Dynamic adjustment of curve parameters based on market conditions and liquidity depth 129 | - **Slippage Prediction**: Advanced algorithms that predict price impact before trade execution 130 | - **Arbitrage Detection**: Real-time identification of price discrepancies across different bonding curves 131 | 132 | ### Mathematical Features 133 | - **Real-time Calculus**: Continuous derivative calculations for optimal entry/exit timing 134 | - **Risk Assessment**: Probability-based risk modeling using Monte Carlo simulations 135 | - **Portfolio Optimization**: Markowitz-style portfolio theory applied to bonding curve assets 136 | 137 | Where reserves encompass both virtual and real components as defined by the Pump.fun protocol specifications, enhanced with proprietary mathematical models for superior accuracy. 138 | 139 | ## ❓ Frequently Asked Questions 140 | 141 | ### General Questions 142 | 143 | **Q: Is this bot safe to use?** 144 | A: The bot is open-source and auditable. However, always test with small amounts first and ensure your private keys are secure. 145 | 146 | **Q: What exchanges does the bot support?** 147 | A: The bot supports multiple DEXs including Pump.fun, Raydium, Jupiter, and other Solana-based exchanges. 148 | 149 | **Q: Can I customize the trading strategy?** 150 | A: Yes, the bot offers extensive customization options for risk management, trade timing, and portfolio allocation. 151 | 152 | ### Technical Questions 153 | 154 | **Q: What are the minimum system requirements?** 155 | A: Node.js 18+, stable internet connection, and sufficient SOL for transaction fees. 156 | 157 | **Q: How does the bot handle network congestion?** 158 | A: The bot includes retry mechanisms and transaction prioritization to handle high network load. 159 | 160 | **Q: Is Redis required for operation?** 161 | A: Redis is optional but recommended for improved performance and data persistence. 162 | 163 | ### Trading Questions 164 | 165 | **Q: What fees are involved?** 166 | A: Standard Solana network fees plus any DEX-specific trading fees. The bot optimizes for minimal fee impact. 167 | 168 | **Q: Can I set stop-loss orders?** 169 | A: Yes, the bot supports various risk management features including stop-loss and take-profit orders. 170 | 171 | **Q: How quickly does the bot execute trades?** 172 | A: Trade execution typically occurs within seconds of the target wallet's transaction confirmation. 173 | 174 | ## 🔑 Keywords 175 | 176 | **Blockchain & DeFi**: Solana, DeFi, Decentralized Exchange, Token Trading, Smart Contracts, Web3 177 | 178 | **Trading & Investment**: Copy Trading, Automated Trading, Algorithmic Trading, Portfolio Management, Risk Management, Yield Farming 179 | 180 | **Technical**: TypeScript, Node.js, WebSocket, API Integration, Real-time Data, Blockchain RPC, Cryptography 181 | 182 | **Platforms**: Pump.fun, Raydium, Jupiter, Helius, GeckoTerminal, Solana Ecosystem 183 | 184 | **Trading Strategies**: Bonding Curves, Liquidity Provision, Arbitrage, Market Making, Trend Following 185 | 186 | ## 📄 License 187 | 188 | This project is licensed under the [MIT License](./LICENSE) - see the LICENSE file for details. 189 | 190 | ## 🤝 Contributing 191 | 192 | We welcome contributions! Please feel free to submit issues, feature requests, or pull requests. 193 | 194 | ## 📞 Contact & Support 195 | 196 | - **Email**: [imcrazysteven143@gmail.com](mailto:imcrazysteven143@gmail.com) 197 | - **GitHub**: [Steven (@imcrazysteven)](https://github.com/imcrazysteven) 198 | - **Telegram**: [@imcrazysteven](https://t.me/imcrazysteven) 199 | - **Twitter**: [@imcrazysteven](https://x.com/imcrazysteven) 200 | - **Instagram**: [@imcrazysteven](https://www.instagram.com/imcrazysteven/) 201 | 202 | --- 203 | 204 | **⚠️ Disclaimer**: This project is for educational and research purposes. Cryptocurrency trading involves substantial risk. Always conduct thorough research and consider consulting with financial advisors before making investment decisions. If you want to have your own sophisticated copy trading bot, please contact me through contact information. 205 | 206 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | "lib": ["es2020"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | "types": ["node"], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ 43 | "resolveJsonModule": true, /* Enable importing .json files. */ 44 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 45 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 46 | 47 | /* JavaScript Support */ 48 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 49 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 50 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 51 | 52 | /* Emit */ 53 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files. */ 54 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 55 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 56 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 57 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 58 | // "noEmit": true, /* Disable emitting files from a compilation. */ 59 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 60 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 61 | // "removeComments": true, /* Disable emitting comments. */ 62 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source. */ 65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 68 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 74 | 75 | /* Interop Constraints */ 76 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 77 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 78 | // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ 79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 83 | 84 | /* Type Checking */ 85 | "strict": true, /* Enable all strict type-checking options. */ 86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 91 | // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ 92 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 93 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 94 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 95 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 96 | // "noUnusedParameters": true, /* Raise an error when a parameter isn't read. */ 97 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 98 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 99 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 100 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 101 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 102 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 103 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 104 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 105 | 106 | /* Completeness */ 107 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 108 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 109 | } 110 | } 111 | --------------------------------------------------------------------------------