├── src ├── createLUT.ts ├── keypairs │ └── keypair1.json ├── clients │ ├── LookupTableProvider.ts │ ├── jito.ts │ ├── config.ts │ └── poolKeysReassigned.ts ├── createKeys.ts ├── sellFunc.ts ├── keyInfo.json ├── jitoPool.ts ├── sellRay.ts └── senderUI.ts ├── img └── mylogo.jpg ├── blockengine.json ├── config.ts ├── package.json ├── main.ts ├── README.md ├── tsconfig.json └── pumpfun-IDL.json /src/createLUT.ts: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/mylogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2-rust/pump.fun-bundler/HEAD/img/mylogo.jpg -------------------------------------------------------------------------------- /blockengine.json: -------------------------------------------------------------------------------- 1 | [202,190,16,165,214,133,240,209,173,213,226,32,24,245,109,228,80,244,78,189,230,168,157,99,100,100,19,68,227,205,209,239,76,10,182,65,44,153,228,213,24,116,94,136,48,101,169,115,164,234,222,248,82,135,141,131,207,211,136,210,74,106,122,83] -------------------------------------------------------------------------------- /src/keypairs/keypair1.json: -------------------------------------------------------------------------------- 1 | [113,229,188,93,141,124,246,53,197,97,227,112,114,63,180,58,223,158,12,147,92,224,14,6,104,83,99,179,240,135,75,248,229,126,150,70,138,17,242,238,187,37,227,30,216,32,52,123,187,155,203,10,25,38,14,198,252,93,223,5,107,65,115,126] -------------------------------------------------------------------------------- /src/clients/LookupTableProvider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AccountInfo, 3 | AddressLookupTableAccount, 4 | AddressLookupTableProgram, 5 | PublicKey, 6 | } from '@solana/web3.js'; 7 | import { connection } from '../../config'; 8 | 9 | /** 10 | * this class solves 2 problems: 11 | * 1. cache and geyser subscribe to lookup tables for fast retreival 12 | * 2. compute the ideal lookup tables for a set of addresses 13 | * 14 | * the second problem/solution is needed because jito bundles can not include a a txn that uses a lookup table 15 | * that has been modified in the same bundle. so this class caches all lookups and then computes the ideal lookup tables 16 | * for a set of addresses used by the arb txn so that the arb txn size is reduced below the maximum. 17 | */ 18 | class LookupTableProvider { 19 | } 20 | 21 | const lookupTableProvider = new LookupTableProvider(); 22 | 23 | lookupTableProvider.getLookupTable( 24 | // custom lookup tables 25 | new PublicKey('Gr8rXuDwE2Vd2F5tifkPyMaUR67636YgrZEjkJf9RR9V'), 26 | ); 27 | 28 | export { lookupTableProvider }; 29 | -------------------------------------------------------------------------------- /config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | Keypair, 4 | PublicKey, 5 | } from "@solana/web3.js"; 6 | import bs58 from "bs58"; 7 | 8 | 9 | 10 | 11 | // PRIV KEY OF DEPLOYER 12 | export const wallet = Keypair.fromSecretKey( 13 | bs58.decode( 14 | "", 15 | ), 16 | ); 17 | 18 | 19 | // PRIV KEY OF FEEPAYER 20 | export const payer = Keypair.fromSecretKey( 21 | bs58.decode( 22 | "", 23 | ), 24 | ); 25 | 26 | 27 | // ENTER YOUR RPC 28 | export const rpc = 29 | ""; 30 | 31 | 32 | 33 | 34 | /* DONT TOUCH ANYTHING BELOW THIS */ 35 | 36 | export const connection = new Connection(rpc, "confirmed"); 37 | 38 | export const PUMP_PROGRAM = new PublicKey("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"); 39 | 40 | export const RayLiqPoolv4 = new PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'); 41 | 42 | export const global = new PublicKey("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"); 43 | 44 | export const mintAuthority = new PublicKey("TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"); 45 | 46 | export const MPL_TOKEN_METADATA_PROGRAM_ID = new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"); 47 | 48 | export const eventAuthority = new PublicKey("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"); 49 | 50 | export const feeRecipient = new PublicKey("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM"); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PumpFun-Bundler", 3 | "version": "1.0.0", 4 | "description": "https://solana-scripts.com", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "ts-node jitoPool.ts" 8 | }, 9 | "author": "https://solana-scripts.com", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@coral-xyz/anchor": "^0.29.0", 13 | "@octokit/rest": "^20.1.0", 14 | "@openbook-dex/openbook": "^0.0.9", 15 | "@project-serum/anchor": "^0.26.0", 16 | "@project-serum/serum": "^0.13.65", 17 | "@raydium-io/raydium-sdk": "^1.3.1-beta.47", 18 | "@solana/spl-token": "^0.3.9", 19 | "@solana/web3.js": "^1.87.6", 20 | "@types/node": "^20.10.5", 21 | "axios": "^1.6.8", 22 | "bn.js": "^5.2.1", 23 | "bs58": "^5.0.0", 24 | "convict": "^6.2.4", 25 | "dotenv": "^16.4.4", 26 | "fs": "^0.0.1-security", 27 | "http": "^0.0.1-security", 28 | "https": "^1.0.0", 29 | "jito-ts": "^3.0.1", 30 | "mime": "^4.0.1", 31 | "nft.storage": "^7.1.1", 32 | "node-fetch": "^3.3.2", 33 | "path": "^0.12.7", 34 | "prompt-sync": "^4.2.0", 35 | "protobufjs": "^7.2.6", 36 | "typescript": "^5.3.3" 37 | }, 38 | "devDependencies": { 39 | "@types/bn.js": "^5.1.5", 40 | "@types/convict": "^6.1.6", 41 | "@types/node-fetch": "^2.6.9", 42 | "@types/prompt-sync": "^4.2.3", 43 | "javascript-obfuscator": "^4.1.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/clients/jito.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from '@solana/web3.js'; 2 | import { config } from './config'; 3 | import { geyserClient as jitoGeyserClient } from 'jito-ts'; 4 | 5 | import { 6 | SearcherClient, 7 | searcherClient as jitoSearcherClient, 8 | } from 'jito-ts/dist/sdk/block-engine/searcher.js'; 9 | import * as fs from 'fs'; 10 | 11 | const BLOCK_ENGINE_URLS = config.get('block_engine_urls'); 12 | const AUTH_KEYPAIR_PATH = config.get('auth_keypair_path'); 13 | 14 | const GEYSER_URL = config.get('geyser_url'); 15 | const GEYSER_ACCESS_TOKEN = config.get('geyser_access_token'); 16 | 17 | const decodedKey = new Uint8Array( 18 | JSON.parse(fs.readFileSync(AUTH_KEYPAIR_PATH).toString()) as number[], 19 | ); 20 | const keypair = Keypair.fromSecretKey(decodedKey); 21 | 22 | export const privateKey = keypair 23 | 24 | const searcherClients: SearcherClient[] = []; 25 | 26 | for (const url of BLOCK_ENGINE_URLS) { 27 | const client = jitoSearcherClient(url, keypair, { 28 | 'grpc.keepalive_timeout_ms': 4000, 29 | }); 30 | searcherClients.push(client); 31 | } 32 | 33 | const geyserClient = jitoGeyserClient(GEYSER_URL, GEYSER_ACCESS_TOKEN, { 34 | 'grpc.keepalive_timeout_ms': 4000, 35 | }); 36 | 37 | // all bundles sent get automatically forwarded to the other regions. 38 | // assuming the first block engine in the array is the closest one 39 | const searcherClient = searcherClients[0]; 40 | 41 | export { searcherClient, searcherClients, geyserClient }; -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | import { createKeypairs } from "./src/createKeys"; 2 | import { buyBundle } from "./src/jitoPool"; 3 | import { sender } from "./src/senderUI"; 4 | import { sellXPercentagePF } from "./src/sellFunc"; 5 | import promptSync from "prompt-sync"; 6 | import { sellXPercentageRAY } from "./src/sellRay"; 7 | 8 | const prompt = promptSync(); 9 | 10 | async function main() { 11 | let running = true; 12 | 13 | while (running) { 14 | console.log("DM me for support"); 15 | console.log("https://t.me/benorizz0"); 16 | console.log("solana-scripts.com"); 17 | console.log("\nMenu:"); 18 | console.log("1. Create Keypairs"); 19 | console.log("2. Pre Launch Checklist"); 20 | console.log("3. Create Pool Bundle"); 21 | console.log("4. Sell % of Supply on Pump.Fun"); 22 | console.log("5. Sell % of Supply on Raydium"); 23 | console.log("Type 'exit' to quit."); 24 | 25 | const answer = prompt("Choose an option or 'exit': "); // Use prompt-sync for user input 26 | 27 | switch (answer) { 28 | case "1": 29 | await createKeypairs(); 30 | break; 31 | case "2": 32 | await sender(); 33 | break; 34 | case "3": 35 | await buyBundle(); 36 | break; 37 | case "4": 38 | await sellXPercentagePF(); 39 | break; 40 | case "5": 41 | await sellXPercentageRAY(); 42 | break; 43 | case "exit": 44 | running = false; 45 | break; 46 | default: 47 | console.log("Invalid option, please choose again."); 48 | } 49 | } 50 | 51 | console.log("Exiting..."); 52 | process.exit(0); 53 | } 54 | 55 | main().catch((err) => { 56 | console.error("Error:", err); 57 | }); 58 | -------------------------------------------------------------------------------- /src/clients/config.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from '@solana/web3.js'; 2 | import convict from 'convict'; 3 | import * as dotenv from 'dotenv'; 4 | dotenv.config(); 5 | 6 | const config = convict({ 7 | bot_name: { 8 | format: String, 9 | default: 'local', 10 | env: 'BOT_NAME', 11 | }, 12 | num_worker_threads: { 13 | format: Number, 14 | default: 4, 15 | env: 'NUM_WORKER_THREADS', 16 | }, 17 | block_engine_urls: { 18 | format: Array, 19 | default: ['frankfurt.mainnet.block-engine.jito.wtf'], 20 | doc: 'block engine urls. bot will mempool subscribe to all and send bundles to first one', 21 | env: 'BLOCK_ENGINE_URLS', 22 | }, 23 | auth_keypair_path: { 24 | format: String, 25 | default: './blockengine.json', 26 | env: 'AUTH_KEYPAIR_PATH', 27 | }, 28 | rpc_url: { 29 | format: String, 30 | default: 'https://api.mainnet-beta.solana.com', 31 | env: 'RPC_URL', 32 | }, 33 | rpc_requests_per_second: { 34 | format: Number, 35 | default: 0, 36 | env: 'RPC_REQUESTS_PER_SECOND', 37 | }, 38 | rpc_max_batch_size: { 39 | format: Number, 40 | default: 20, 41 | env: 'RPC_MAX_BATCH_SIZE', 42 | }, 43 | geyser_url: { 44 | format: String, 45 | default: 'mainnet.rpc.jito.wtf', 46 | env: 'GEYSER_URL', 47 | }, 48 | geyser_access_token: { 49 | format: String, 50 | default: '00000000-0000-0000-0000-000000000000', 51 | env: 'GEYSER_ACCESS_TOKEN', 52 | }, 53 | arb_calculation_num_steps: { 54 | format: Number, 55 | default: 3, 56 | env: 'ARB_CALCULATION_NUM_STEPS', 57 | }, 58 | max_arb_calculation_time_ms: { 59 | format: Number, 60 | default: 15, 61 | env: 'MAX_ARB_CALCULATION_TIME_MS', 62 | }, 63 | payer_keypair_path: { 64 | format: String, 65 | default: './payer.json', 66 | env: 'PAYER_KEYPAIR_PATH', 67 | }, 68 | min_tip_lamports: { 69 | format: Number, 70 | default: 10000, 71 | env: 'MIN_TIP_LAMPORTS', 72 | }, 73 | tip_percent: { 74 | format: Number, 75 | default: 50, 76 | env: 'TIP_PERCENT', 77 | }, 78 | }); 79 | 80 | config.validate({ allowed: 'strict' }); 81 | 82 | 83 | const TIP_ACCOUNTS = [ 84 | '96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5', 85 | 'HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe', 86 | 'Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY', 87 | 'ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49', 88 | 'DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh', 89 | 'ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt', 90 | 'DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL', 91 | '3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT', 92 | ].map((pubkey) => new PublicKey(pubkey)); 93 | 94 | const getRandomTipAccount = () => 95 | TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)]; 96 | 97 | 98 | 99 | export { config ,getRandomTipAccount}; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Pump.Fun Bundler 2 | 3 | Welcome to the Open-Source **Pump.Fun Bundler** – your ultimate solution for bundling on Pump.Fun with advanced profile creation and anti-bubble maps! 4 | 5 | This open-source and free tool offers the most efficient self-bundling script for Pump.Fun, enabling you to launch a token with 20 different wallets and profiles. 6 | 7 | Enjoy launches that are completely bubble maps-proof and anti-Photon SB marks. 8 | 9 | For more details, contact here: telegram: [T-rustdev](https://t.me/T_rustdev) 10 | 11 | 12 | 13 | ## Features 14 | 15 | ### Seamless UI 16 | - **💊 Intuitive User Interface:** Experience a straightforward and completely automatic user interface designed for ease of use and efficiency. 17 | 18 | ### Advanced Profile Creation 19 | - **🧑 Random Profiles:** Automatically generate profiles for each wallet to ensure maximum authenticity, with each wallet holding different random tokens. 20 | 21 | ### Custom LUT Program 22 | - **🔥 Custom LUT Program:** Leverage our custom Look-Up Table (LUT) program to optimize your launch strategies. 23 | 24 | ### Automatic Supply Deviation 25 | - **🚨 Supply Management:** Automatically manage supply deviations for smooth and efficient launches. 26 | 27 | ### Custom Configurable Buyers 28 | - **🔔 Configurable Buyers:** Customize and configure up to 20 different keypair buyers for personalized launch strategies. 29 | 30 | ### Unmatched Performance 31 | - **🤖 Performance and Speed:** Benefit from unparalleled performance, stability, and speed with our tool. 32 | 33 | ### Custom Onchain Program 34 | - **📂 Onchain Integration:** Seamlessly integrate and operate with our bespoke onchain program. 35 | 36 | ### Complex Sell Strategies 37 | - **💸 Sell Strategies:** Implement complex percentage-based sell strategies across all keypairs simultaneously. 38 | 39 | ### And Much More! 40 | - Discover even more features designed to optimize your launch experience and help you profit from your Pump.Fun launches. 41 | 42 | ## Installation 43 | 44 | To get started with the Pump.Fun Launch Bundle Tool, follow these steps: 45 | 46 | 1. **Clone the Repository:** 47 | ```bash 48 | git clone https://github.com/T-rustdev/pump.fun-bundler.git 49 | ``` 50 | 51 | 2. **Navigate to the Project Directory:** 52 | ```bash 53 | cd pump.fun-bundler 54 | ``` 55 | 56 | 3. **Install Dependencies:** 57 | ```bash 58 | npm install 59 | ``` 60 | 61 | 4. **Set Up Environment Variables:** 62 | Create a `.env` file in the project directory and add your configuration details: 63 | ```plaintext 64 | SOLANA_RPC_URL= 65 | PRIVATE_KEY= 66 | ``` 67 | 68 | 5. **Start the Application:** 69 | ```bash 70 | npm start 71 | ``` 72 | 73 | ## Usage 74 | 75 | 1. **Configure Buyers and Launch Settings:** 76 | Use the intuitive UI to configure your buyers and launch settings. 77 | 78 | 2. **Start the Bundling Process:** 79 | Initiate the bundling process and let the tool handle the rest automatically. 80 | 81 | 3. **Profit:** 82 | Sit back and profit from your successful Pump.Fun launches! 83 | 84 | -------------------------------------------------------------------------------- /src/createKeys.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from '@solana/web3.js'; 2 | import * as fs from 'fs'; 3 | import promptSync from 'prompt-sync'; 4 | import path from 'path'; 5 | import bs58 from 'bs58'; 6 | 7 | const prompt = promptSync(); 8 | 9 | const keypairsDir = path.join(__dirname, 'keypairs'); 10 | const keyInfoPath = path.join(__dirname, 'keyInfo.json'); 11 | 12 | interface IPoolInfo { 13 | [key: string]: any; 14 | numOfWallets?: number; 15 | } 16 | 17 | // Ensure the keypairs directory exists 18 | if (!fs.existsSync(keypairsDir)) { 19 | fs.mkdirSync(keypairsDir, { recursive: true }); 20 | } 21 | 22 | function generateWallets(numOfWallets: number): Keypair[] { 23 | let wallets: Keypair[] = []; 24 | for (let i = 0; i < numOfWallets; i++) { 25 | const wallet = Keypair.generate(); 26 | wallets.push(wallet); 27 | } 28 | return wallets; 29 | } 30 | 31 | function saveKeypairToFile(keypair: Keypair, index: number) { 32 | const keypairPath = path.join(keypairsDir, `keypair${index + 1}.json`); 33 | fs.writeFileSync(keypairPath, JSON.stringify(Array.from(keypair.secretKey))); 34 | } 35 | 36 | function readKeypairs(): Keypair[] { 37 | const files = fs.readdirSync(keypairsDir); 38 | return files.map(file => { 39 | const filePath = path.join(keypairsDir, file); 40 | const secretKey = JSON.parse(fs.readFileSync(filePath, 'utf-8')); 41 | return Keypair.fromSecretKey(new Uint8Array(secretKey)); 42 | }); 43 | } 44 | 45 | function updatePoolInfo(wallets: Keypair[]) { 46 | let poolInfo: IPoolInfo = {}; // Use the defined type here 47 | 48 | // Check if poolInfo.json exists and read its content 49 | if (fs.existsSync(keyInfoPath)) { 50 | const data = fs.readFileSync(keyInfoPath, 'utf8'); 51 | poolInfo = JSON.parse(data); 52 | } 53 | 54 | // Update wallet-related information 55 | poolInfo.numOfWallets = wallets.length; 56 | wallets.forEach((wallet, index) => { 57 | poolInfo[`pubkey${index + 1}`] = wallet.publicKey.toString(); 58 | }); 59 | 60 | // Write updated data back to poolInfo.json 61 | fs.writeFileSync(keyInfoPath, JSON.stringify(poolInfo, null, 2)); 62 | } 63 | 64 | export async function createKeypairs() { 65 | console.log('WARNING: If you create new ones, ensure you don\'t have SOL, OR ELSE IT WILL BE GONE.'); 66 | const action = prompt('Do you want to (c)reate new wallets or (u)se existing ones? (c/u): '); 67 | let wallets: Keypair[] = []; 68 | 69 | if (action === 'c') { 70 | const numOfWallets = 24; // Hardcode 24 buyer keypairs here. 71 | if (isNaN(numOfWallets) || numOfWallets <= 0) { 72 | console.log('Invalid number. Please enter a positive integer.'); 73 | return; 74 | } 75 | 76 | wallets = generateWallets(numOfWallets); 77 | wallets.forEach((wallet, index) => { 78 | saveKeypairToFile(wallet, index); 79 | console.log(`Wallet ${index + 1} Public Key: ${wallet.publicKey.toString()}`); 80 | }); 81 | } else if (action === 'u') { 82 | wallets = readKeypairs(); 83 | wallets.forEach((wallet, index) => { 84 | console.log(`Read Wallet ${index + 1} Public Key: ${wallet.publicKey.toString()}`); 85 | console.log(`Read Wallet ${index + 1} Private Key: ${bs58.encode(wallet.secretKey)}\n`); 86 | }); 87 | } else { 88 | console.log('Invalid option. Please enter "c" for create or "u" for use existing.'); 89 | return; 90 | } 91 | 92 | updatePoolInfo(wallets); 93 | console.log(`${wallets.length} wallets have been processed.`); 94 | } 95 | 96 | export function loadKeypairs(): Keypair[] { 97 | // Define a regular expression to match filenames like 'keypair1.json', 'keypair2.json', etc. 98 | const keypairRegex = /^keypair\d+\.json$/; 99 | 100 | return fs.readdirSync(keypairsDir) 101 | .filter(file => keypairRegex.test(file)) // Use the regex to test each filename 102 | .map(file => { 103 | const filePath = path.join(keypairsDir, file); 104 | const secretKeyString = fs.readFileSync(filePath, { encoding: 'utf8' }); 105 | const secretKey = Uint8Array.from(JSON.parse(secretKeyString)); 106 | return Keypair.fromSecretKey(secretKey); 107 | }); 108 | } 109 | -------------------------------------------------------------------------------- /src/clients/poolKeysReassigned.ts: -------------------------------------------------------------------------------- 1 | import * as spl from '@solana/spl-token'; 2 | import { Market } from '@openbook-dex/openbook'; 3 | import { AccountInfo, PublicKey } from '@solana/web3.js'; 4 | import { u8, u32, struct } from '@solana/buffer-layout'; 5 | import { u64, publicKey } from '@solana/buffer-layout-utils'; 6 | import { RayLiqPoolv4, connection, wallet } from '../../config'; 7 | import { ApiPoolInfoV4 } from "@raydium-io/raydium-sdk"; 8 | 9 | const openbookProgram = new PublicKey('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX'); 10 | 11 | async function getMarketInfo(marketId: PublicKey) { 12 | let reqs = 0; 13 | let marketInfo = await connection.getAccountInfo(marketId); 14 | reqs++; 15 | 16 | while (!marketInfo) { 17 | marketInfo = await connection.getAccountInfo(marketId); 18 | reqs++; 19 | if (marketInfo) { 20 | break; 21 | } else if (reqs > 20) { 22 | console.log(`Could not get market info..`); 23 | 24 | return null; 25 | } 26 | } 27 | 28 | return marketInfo; 29 | } 30 | 31 | async function getDecodedData(marketInfo: { 32 | executable?: boolean; 33 | owner?: PublicKey; 34 | lamports?: number; 35 | data: any; 36 | rentEpoch?: number | undefined; 37 | }) { 38 | return Market.getLayout(openbookProgram).decode(marketInfo.data); 39 | } 40 | 41 | async function getMintData(mint: PublicKey) { 42 | return connection.getAccountInfo(mint); 43 | } 44 | 45 | async function getDecimals(mintData: AccountInfo | null) { 46 | if (!mintData) throw new Error('No mint data!'); 47 | 48 | return SPL_MINT_LAYOUT.decode(mintData.data).decimals; 49 | } 50 | 51 | async function getOwnerAta(mint: { toBuffer: () => Uint8Array | Buffer }, publicKey: PublicKey) { 52 | const foundAta = PublicKey.findProgramAddressSync( 53 | [publicKey.toBuffer(), spl.TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()], 54 | spl.ASSOCIATED_TOKEN_PROGRAM_ID 55 | )[0]; 56 | 57 | return foundAta; 58 | } 59 | 60 | function getVaultSigner(marketId: { toBuffer: any }, marketDeco: { vaultSignerNonce: { toString: () => any } }) { 61 | const seeds = [marketId.toBuffer()]; 62 | const seedsWithNonce = seeds.concat(Buffer.from([Number(marketDeco.vaultSignerNonce.toString())]), Buffer.alloc(7)); 63 | 64 | return PublicKey.createProgramAddressSync(seedsWithNonce, openbookProgram); 65 | } 66 | 67 | export async function derivePoolKeys(marketId: PublicKey) { 68 | const marketInfo = await getMarketInfo(marketId); 69 | if (!marketInfo) return null; 70 | const marketDeco = await getDecodedData(marketInfo); 71 | const { baseMint } = marketDeco; 72 | const baseMintData = await getMintData(baseMint); 73 | const baseDecimals = await getDecimals(baseMintData); 74 | const ownerBaseAta = await getOwnerAta(baseMint, wallet.publicKey); 75 | const { quoteMint } = marketDeco; 76 | const quoteMintData = await getMintData(quoteMint); 77 | const quoteDecimals = await getDecimals(quoteMintData); 78 | const ownerQuoteAta = await getOwnerAta(quoteMint, wallet.publicKey); 79 | const authority = PublicKey.findProgramAddressSync( 80 | [Buffer.from([97, 109, 109, 32, 97, 117, 116, 104, 111, 114, 105, 116, 121])], 81 | RayLiqPoolv4 82 | )[0]; 83 | 84 | const marketAuthority = getVaultSigner(marketId, marketDeco); 85 | 86 | // get/derive all the pool keys 87 | const poolKeys = { 88 | keg: new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'), 89 | version: 4, 90 | marketVersion: 3, 91 | programId: RayLiqPoolv4, 92 | baseMint, 93 | quoteMint, 94 | ownerBaseAta, 95 | ownerQuoteAta, 96 | baseDecimals, 97 | quoteDecimals, 98 | lpDecimals: baseDecimals, 99 | authority, 100 | marketAuthority, 101 | marketProgramId: openbookProgram, 102 | marketId, 103 | marketBids: marketDeco.bids, 104 | marketAsks: marketDeco.asks, 105 | marketQuoteVault: marketDeco.quoteVault, 106 | marketBaseVault: marketDeco.baseVault, 107 | marketEventQueue: marketDeco.eventQueue, 108 | id: PublicKey.findProgramAddressSync( 109 | [RayLiqPoolv4.toBuffer(), marketId.toBuffer(), Buffer.from('amm_associated_seed', 'utf-8')], 110 | RayLiqPoolv4 111 | )[0], 112 | baseVault: PublicKey.findProgramAddressSync( 113 | [RayLiqPoolv4.toBuffer(), marketId.toBuffer(), Buffer.from('coin_vault_associated_seed', 'utf-8')], 114 | RayLiqPoolv4 115 | )[0], 116 | coinVault: PublicKey.findProgramAddressSync( 117 | [RayLiqPoolv4.toBuffer(), marketId.toBuffer(), Buffer.from('pc_vault_associated_seed', 'utf-8')], 118 | RayLiqPoolv4 119 | )[0], 120 | lpMint: PublicKey.findProgramAddressSync( 121 | [RayLiqPoolv4.toBuffer(), marketId.toBuffer(), Buffer.from('lp_mint_associated_seed', 'utf-8')], 122 | RayLiqPoolv4 123 | )[0], 124 | lpVault: PublicKey.findProgramAddressSync( 125 | [RayLiqPoolv4.toBuffer(), marketId.toBuffer(), Buffer.from('temp_lp_token_associated_seed', 'utf-8')], 126 | RayLiqPoolv4 127 | )[0], 128 | targetOrders: PublicKey.findProgramAddressSync( 129 | [RayLiqPoolv4.toBuffer(), marketId.toBuffer(), Buffer.from('target_associated_seed', 'utf-8')], 130 | RayLiqPoolv4 131 | )[0], 132 | withdrawQueue: PublicKey.findProgramAddressSync( 133 | [RayLiqPoolv4.toBuffer(), marketId.toBuffer(), Buffer.from('withdraw_associated_seed', 'utf-8')], 134 | RayLiqPoolv4 135 | )[0], 136 | openOrders: PublicKey.findProgramAddressSync( 137 | [RayLiqPoolv4.toBuffer(), marketId.toBuffer(), Buffer.from('open_order_associated_seed', 'utf-8')], 138 | RayLiqPoolv4 139 | )[0], 140 | quoteVault: PublicKey.findProgramAddressSync( 141 | [RayLiqPoolv4.toBuffer(), marketId.toBuffer(), Buffer.from('pc_vault_associated_seed', 'utf-8')], 142 | RayLiqPoolv4 143 | )[0], 144 | lookupTableAccount: new PublicKey('11111111111111111111111111111111') 145 | }; 146 | 147 | return poolKeys; 148 | } 149 | 150 | export async function PoolKeysCorrector(poolkeys: IPoolKeys): Promise { 151 | return { 152 | id: poolkeys.id.toString(), 153 | baseMint: poolkeys.baseMint.toString(), 154 | quoteMint: poolkeys.quoteMint.toString(), 155 | lpMint: poolkeys.lpMint.toString(), 156 | baseDecimals: poolkeys.baseDecimals, 157 | quoteDecimals: poolkeys.quoteDecimals, 158 | lpDecimals: poolkeys.lpDecimals, 159 | version: 4, 160 | programId: poolkeys.programId?.toString() || RayLiqPoolv4.toString(), 161 | authority: poolkeys.authority.toString(), 162 | openOrders: poolkeys.openOrders.toString(), 163 | targetOrders: poolkeys.targetOrders.toString(), 164 | baseVault: poolkeys.baseVault.toString(), 165 | quoteVault: poolkeys.quoteVault.toString(), 166 | withdrawQueue: poolkeys.withdrawQueue?.toString() || '', 167 | lpVault: poolkeys.lpVault?.toString() || '', 168 | marketVersion: 3, 169 | marketProgramId: poolkeys.marketProgramId.toString(), 170 | marketId: poolkeys.marketId.toString(), 171 | marketAuthority: poolkeys.marketAuthority.toString(), 172 | marketBaseVault: poolkeys.baseVault.toString(), 173 | marketQuoteVault: poolkeys.quoteVault.toString(), 174 | marketBids: poolkeys.marketBids.toString(), 175 | marketAsks: poolkeys.marketAsks.toString(), 176 | marketEventQueue: poolkeys.marketEventQueue.toString(), 177 | lookupTableAccount: PublicKey.default.toString() 178 | } 179 | } 180 | 181 | export interface IPoolKeys { 182 | keg?: PublicKey; 183 | version?: number; 184 | marketVersion?: number; 185 | programId?: PublicKey; 186 | baseMint: any; 187 | quoteMint?: any; 188 | ownerBaseAta: PublicKey; 189 | ownerQuoteAta: PublicKey; 190 | baseDecimals: any; 191 | quoteDecimals?: any; 192 | lpDecimals?: any; 193 | authority?: any; 194 | marketAuthority?: any; 195 | marketProgramId?: any; 196 | marketId?: any; 197 | marketBids?: any; 198 | marketAsks?: any; 199 | marketQuoteVault?: any; 200 | marketBaseVault?: any; 201 | marketEventQueue?: any; 202 | id?: any; 203 | baseVault?: any; 204 | coinVault?: PublicKey; 205 | lpMint: PublicKey; 206 | lpVault?: PublicKey; 207 | targetOrders?: any; 208 | withdrawQueue?: PublicKey; 209 | openOrders?: any; 210 | quoteVault?: any; 211 | lookupTableAccount?: PublicKey; 212 | } 213 | 214 | export const SPL_MINT_LAYOUT = struct([ 215 | u32('mintAuthorityOption'), 216 | publicKey('mintAuthority'), 217 | u64('supply'), 218 | u8('decimals'), 219 | u8('isInitialized'), 220 | u32('freezeAuthorityOption'), 221 | publicKey('freezeAuthority') 222 | ]); 223 | 224 | export const SPL_ACCOUNT_LAYOUT = struct([ 225 | publicKey('mint'), 226 | publicKey('owner'), 227 | u64('amount'), 228 | u32('delegateOption'), 229 | publicKey('delegate'), 230 | u8('state'), 231 | u32('isNativeOption'), 232 | u64('isNative'), 233 | u64('delegatedAmount'), 234 | u32('closeAuthorityOption'), 235 | publicKey('closeAuthority') 236 | ]); 237 | -------------------------------------------------------------------------------- /src/sellFunc.ts: -------------------------------------------------------------------------------- 1 | import { connection, rpc, wallet, global, feeRecipient, PUMP_PROGRAM, payer } from "../config"; 2 | import { PublicKey, VersionedTransaction, SYSVAR_RENT_PUBKEY, TransactionMessage, SystemProgram, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js"; 3 | import { loadKeypairs } from "./createKeys"; 4 | import { searcherClient } from "./clients/jito"; 5 | import { Bundle as JitoBundle } from "jito-ts/dist/sdk/block-engine/types.js"; 6 | import promptSync from "prompt-sync"; 7 | import * as spl from "@solana/spl-token"; 8 | import bs58 from "bs58"; 9 | import path from "path"; 10 | import fs from "fs"; 11 | import * as anchor from "@coral-xyz/anchor"; 12 | import { randomInt } from "crypto"; 13 | import { getRandomTipAccount } from "./clients/config"; 14 | import BN from "bn.js"; 15 | 16 | const prompt = promptSync(); 17 | const keyInfoPath = path.join(__dirname, "keyInfo.json"); 18 | 19 | function chunkArray(array: T[], size: number): T[][] { 20 | return Array.from({ length: Math.ceil(array.length / size) }, (v, i) => array.slice(i * size, i * size + size)); 21 | } 22 | 23 | async function sendBundle(bundledTxns: VersionedTransaction[]) { 24 | /* 25 | // Simulate each transaction 26 | for (const tx of bundledTxns) { 27 | try { 28 | const simulationResult = await connection.simulateTransaction(tx, { commitment: "processed" }); 29 | 30 | if (simulationResult.value.err) { 31 | console.error("Simulation error for transaction:", simulationResult.value.err); 32 | } else { 33 | console.log("Simulation success for transaction. Logs:"); 34 | simulationResult.value.logs?.forEach(log => console.log(log)); 35 | } 36 | } catch (error) { 37 | console.error("Error during simulation:", error); 38 | } 39 | } 40 | */ 41 | 42 | try { 43 | const bundleId = await searcherClient.sendBundle(new JitoBundle(bundledTxns, bundledTxns.length)); 44 | console.log(`Bundle ${bundleId} sent.`); 45 | 46 | /* 47 | // Assuming onBundleResult returns a Promise 48 | const result = await new Promise((resolve, reject) => { 49 | searcherClient.onBundleResult( 50 | (result) => { 51 | console.log('Received bundle result:', result); 52 | resolve(result); // Resolve the promise with the result 53 | }, 54 | (e: Error) => { 55 | console.error('Error receiving bundle result:', e); 56 | reject(e); // Reject the promise if there's an error 57 | } 58 | ); 59 | }); 60 | 61 | console.log('Result:', result); 62 | */ 63 | } catch (error) { 64 | const err = error as any; 65 | console.error("Error sending bundle:", err.message); 66 | 67 | if (err?.message?.includes("Bundle Dropped, no connected leader up soon")) { 68 | console.error("Error sending bundle: Bundle Dropped, no connected leader up soon."); 69 | } else { 70 | console.error("An unexpected error occurred:", err.message); 71 | } 72 | } 73 | } 74 | 75 | export async function sellXPercentagePF() { 76 | const provider = new anchor.AnchorProvider(new anchor.web3.Connection(rpc), new anchor.Wallet(wallet), { commitment: "confirmed" }); 77 | 78 | // Initialize pumpfun anchor 79 | const IDL_PumpFun = JSON.parse(fs.readFileSync("./pumpfun-IDL.json", "utf-8")) as anchor.Idl; 80 | 81 | const pfprogram = new anchor.Program(IDL_PumpFun, PUMP_PROGRAM, provider); 82 | 83 | // Start selling 84 | const bundledTxns = []; 85 | const keypairs = loadKeypairs(); // Ensure this function is correctly defined to load your Keypairs 86 | 87 | let poolInfo: { [key: string]: any } = {}; 88 | if (fs.existsSync(keyInfoPath)) { 89 | const data = fs.readFileSync(keyInfoPath, "utf-8"); 90 | poolInfo = JSON.parse(data); 91 | } 92 | 93 | const lut = new PublicKey(poolInfo.addressLUT.toString()); 94 | 95 | const lookupTableAccount = (await connection.getAddressLookupTable(lut)).value; 96 | 97 | if (lookupTableAccount == null) { 98 | console.log("Lookup table account not found!"); 99 | process.exit(0); 100 | } 101 | 102 | const mintKp = Keypair.fromSecretKey(Uint8Array.from(bs58.decode(poolInfo.mintPk))); 103 | //console.log(`Mint: ${mintKp.publicKey.toBase58()}`); 104 | 105 | const [bondingCurve] = PublicKey.findProgramAddressSync([Buffer.from("bonding-curve"), mintKp.publicKey.toBytes()], pfprogram.programId); 106 | let [associatedBondingCurve] = PublicKey.findProgramAddressSync( 107 | [bondingCurve.toBytes(), spl.TOKEN_PROGRAM_ID.toBytes(), mintKp.publicKey.toBytes()], 108 | spl.ASSOCIATED_TOKEN_PROGRAM_ID 109 | ); 110 | 111 | const supplyPercent = +prompt("Percentage to sell (Ex. 1 for 1%): ") / 100; 112 | const jitoTipAmt = +prompt("Jito tip in Sol (Ex. 0.01): ") * LAMPORTS_PER_SOL; 113 | 114 | const mintInfo = await connection.getTokenSupply(mintKp.publicKey); 115 | 116 | let sellTotalAmount = 0; 117 | 118 | const chunkedKeypairs = chunkArray(keypairs, 6); // Adjust chunk size as needed 119 | 120 | // start the selling process 121 | const PayerTokenATA = await spl.getAssociatedTokenAddress(new PublicKey(poolInfo.mint), payer.publicKey); 122 | 123 | const { blockhash } = await connection.getLatestBlockhash(); 124 | 125 | for (let chunkIndex = 0; chunkIndex < chunkedKeypairs.length; chunkIndex++) { 126 | const chunk = chunkedKeypairs[chunkIndex]; 127 | const instructionsForChunk = []; 128 | const isFirstChunk = chunkIndex === 0; // Check if this is the first chunk 129 | 130 | if (isFirstChunk) { 131 | // Handle the first chunk separately 132 | const transferAmount = await getSellBalance(wallet, new PublicKey(poolInfo.mint), supplyPercent); 133 | sellTotalAmount += transferAmount; // Keep track to sell at the end 134 | console.log(`Sending ${transferAmount / 1e6} from dev wallet.`); 135 | 136 | const ataIx = spl.createAssociatedTokenAccountIdempotentInstruction(payer.publicKey, PayerTokenATA, payer.publicKey); 137 | 138 | const TokenATA = await spl.getAssociatedTokenAddress(new PublicKey(poolInfo.mint), wallet.publicKey); 139 | const transferIx = spl.createTransferInstruction(TokenATA, PayerTokenATA, wallet.publicKey, transferAmount); 140 | 141 | instructionsForChunk.push(ataIx, transferIx); 142 | } 143 | 144 | for (let keypair of chunk) { 145 | const transferAmount = await getSellBalance(keypair, new PublicKey(poolInfo.mint), supplyPercent); 146 | sellTotalAmount += transferAmount; // Keep track to sell at the end 147 | console.log(`Sending ${transferAmount / 1e6} from ${keypair.publicKey.toString()}.`); 148 | 149 | const TokenATA = await spl.getAssociatedTokenAddress(new PublicKey(poolInfo.mint), keypair.publicKey); 150 | const transferIx = spl.createTransferInstruction(TokenATA, PayerTokenATA, keypair.publicKey, transferAmount); 151 | instructionsForChunk.push(transferIx); 152 | } 153 | 154 | if (instructionsForChunk.length > 0) { 155 | const message = new TransactionMessage({ 156 | payerKey: payer.publicKey, 157 | recentBlockhash: blockhash, 158 | instructions: instructionsForChunk, 159 | }).compileToV0Message([lookupTableAccount]); 160 | 161 | const versionedTx = new VersionedTransaction(message); 162 | 163 | const serializedMsg = versionedTx.serialize(); 164 | console.log("Txn size:", serializedMsg.length); 165 | if (serializedMsg.length > 1232) { 166 | console.log("tx too big"); 167 | } 168 | 169 | versionedTx.sign([payer]); // Sign with payer first 170 | 171 | for (let keypair of chunk) { 172 | versionedTx.sign([keypair]); // Then sign with each keypair in the chunk 173 | } 174 | 175 | bundledTxns.push(versionedTx); 176 | } 177 | } 178 | 179 | const payerNum = randomInt(0, 24); 180 | const payerKey = keypairs[payerNum]; 181 | 182 | const sellPayerIxs = []; 183 | 184 | console.log(`TOTAL: Selling ${sellTotalAmount / 1e6}.`); 185 | 186 | if (+mintInfo.value.amount * 0.25 <= sellTotalAmount) { 187 | // protect investors from fraud and prevent illegal use 188 | console.log("Price impact too high."); 189 | console.log("Cannot sell more than 25% of supply at a time."); 190 | 191 | return; 192 | } 193 | 194 | const sellIx = await pfprogram.methods 195 | .sell(new BN(sellTotalAmount), new BN(0)) 196 | .accounts({ 197 | global, 198 | feeRecipient, 199 | mint: new PublicKey(poolInfo.mint), 200 | bondingCurve, 201 | user: payer.publicKey, 202 | systemProgram: SystemProgram.programId, 203 | associatedTokenProgram: spl.ASSOCIATED_TOKEN_PROGRAM_ID, 204 | tokenProgram: spl.TOKEN_PROGRAM_ID, 205 | program: PUMP_PROGRAM, 206 | }) 207 | .instruction(); 208 | 209 | sellPayerIxs.push( 210 | sellIx, 211 | SystemProgram.transfer({ 212 | fromPubkey: payer.publicKey, 213 | toPubkey: getRandomTipAccount(), 214 | lamports: BigInt(jitoTipAmt), 215 | }) 216 | ); 217 | 218 | const sellMessage = new TransactionMessage({ 219 | payerKey: payerKey.publicKey, 220 | recentBlockhash: blockhash, 221 | instructions: sellPayerIxs, 222 | }).compileToV0Message([lookupTableAccount]); 223 | 224 | const sellTx = new VersionedTransaction(sellMessage); 225 | 226 | const serializedMsg = sellTx.serialize(); 227 | console.log("Txn size:", serializedMsg.length); 228 | if (serializedMsg.length > 1232) { 229 | console.log("tx too big"); 230 | } 231 | 232 | sellTx.sign([payer, payerKey]); 233 | 234 | bundledTxns.push(sellTx); 235 | 236 | await sendBundle(bundledTxns); 237 | 238 | return; 239 | } 240 | 241 | async function getSellBalance(keypair: Keypair, mint: PublicKey, supplyPercent: number) { 242 | let amount; 243 | try { 244 | const tokenAccountPubKey = spl.getAssociatedTokenAddressSync(mint, keypair.publicKey); 245 | const balance = await connection.getTokenAccountBalance(tokenAccountPubKey); 246 | amount = Math.floor(Number(balance.value.amount) * supplyPercent); 247 | } catch (e) { 248 | amount = 0; 249 | } 250 | 251 | return amount; 252 | } 253 | -------------------------------------------------------------------------------- /src/keyInfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "numOfWallets": 24, 3 | "pubkey1": "GSrKPLQASRgbbMXJn5hYp6yQDBChzExNc7BkgF9VnRL9", 4 | "pubkey2": "7ijkANyZBmw8ybxbFWDHDB41D27aswogFLc1ZsrSDdcD", 5 | "pubkey3": "7uuzvKG2y9cvxVG2ucVyBLVBW15J8Hpn9sifSCWnLMyY", 6 | "pubkey4": "6uR7ohVcFTDWGCxviYzNTvQ8daxDJmoyA59sg38F4yFq", 7 | "pubkey5": "B4QmpBUCTLjWaGkeZUj2KfVaUnQax8ZQ9M9AK22sWqjX", 8 | "pubkey6": "97kcpDdhGqu7134SH678nAdcLxTc3WwuxHDBaeaEv64q", 9 | "pubkey7": "HJeBmpPK8g6d1B6cHBkV3ZQguXLJAiw5muBeXK6zbAYW", 10 | "pubkey8": "EwPHafktDWEnCg4QMbTbJ4XB2wV6hMae2ct7aKSBkgZJ", 11 | "pubkey9": "3pP23hkEeCfinu51KWKQhyDE5eXreVmt7Gc3W9mfpawY", 12 | "pubkey10": "HH1Lz3eq3zD71QBxjnhDCcQcin7gE2k85Bcgn32USZkw", 13 | "pubkey11": "BAyhCdHdHWdWWobNbjaNta88WbYxespXWdQTzh9bLFQH", 14 | "pubkey12": "WGeLGomLtbFgkjf85zebMnHXGAYCYJDKQjLe78ERoUx", 15 | "pubkey13": "9ppNCae46wbN95PyaNVMsY7SwQboAWNgpKbSk4Xx4j4z", 16 | "pubkey14": "7uqMMhmzDQDDaK9q8G6t7uCTykrJtQP3sKBih9pu1StQ", 17 | "pubkey15": "Ddv7CrMmzGKjeENoRr7Xmz8vnDttMp14JJhN5isMQkg2", 18 | "pubkey16": "EPfWA7YqLN89h6a1aUFuEk8L64cPbS79Ao8FsG6Kd2X5", 19 | "pubkey17": "DeW67h29cLo2hAFt9ftZJkhezAdyCUBaBZZ4oLCqWUzM", 20 | "pubkey18": "CMjYqtkKWdCbWdpLncRRCKDfznAQYTkWnQyNYoerVTAo", 21 | "pubkey19": "59ZWrCr3s5gcLupwdt8FydAEADxzZr9K23mReVpS5ab6", 22 | "pubkey20": "E9KocfZ7MW8Rm3iSqKC4pzR9wgD2VF3LeVCFwTevNiC8", 23 | "pubkey21": "3mjcvoxLhYU5969QYsUE73tMBadE8Cpftzt6kBpJzBBQ", 24 | "pubkey22": "7qR2nxAsZ3BgSfWo3NMejTVvfb4C8fNcTrBtCvqeSkR1", 25 | "pubkey23": "C86CmhH1zDRuz312A7XHsijYWuSu82188iaFMfZTH7sZ", 26 | "pubkey24": "Dd4LpGWDZmKkqxbZkg6xoshjG4xcJVPEKVoJ81eFEWZs", 27 | "addressLUT": "5YJjzJUGZ4ddcgJpSyvnAW4HnxKiNinLUJbAcs4XbTq9", 28 | "mint": "6ufmqWPwnZAoySddKgSNFGoXUpp26YCVMg9VmL5Gk7RZ", 29 | "mintPk": "4Qm68vxbMogSEsNmZ241AVRoMGMEYbgRr3FJF7hKi787e8VhNfyCbgYVUwVvex1x6727LjCQKWZMSjeb4rDzhhou", 30 | "7qhZk699YBgNcAhzUBVa4Zxd31JMDttKKxxqbZ27foq2": { 31 | "solAmount": "0.013309999999999999", 32 | "tokenAmount": "475843181824", 33 | "percentSupply": 0.047584318182400005 34 | }, 35 | "BBYKAMsVZMXdjb9n4C72p2TjKYBrdtNaMBf8WbsdR6rT": { 36 | "solAmount": "0.01", 37 | "tokenAmount": "357309277986", 38 | "percentSupply": 0.0357309277986 39 | }, 40 | "2xhREKKEQdEvtroJs2rAtP9DjBwkPnsxwCNZTWkNxnpj": { 41 | "solAmount": "0.01", 42 | "tokenAmount": "357071309769", 43 | "percentSupply": 0.035707130976899995 44 | }, 45 | "4RapT2mNZ8bsZinY2Pj6nzSkHgHMD4KyjKJMhtFC1Zxx": { 46 | "solAmount": "0.01", 47 | "tokenAmount": "356833579203", 48 | "percentSupply": 0.0356833579203 49 | }, 50 | "5hvikdaaqTRa46hs6M5LMna2VPmdwuGCQL9xTWsyxjcB": { 51 | "solAmount": "0.01", 52 | "tokenAmount": "356596085973", 53 | "percentSupply": 0.035659608597300003 54 | }, 55 | "FLsfmkV46G1P5thdc9XjAAd5xgGpuujBR74D5weRamUX": { 56 | "solAmount": "0.01", 57 | "tokenAmount": "356358829761", 58 | "percentSupply": 0.0356358829761 59 | }, 60 | "4NyvbYxGsKSWKZe5VQTbmjpapjoisCfojVND5HKV1J1n": { 61 | "solAmount": "0.01", 62 | "tokenAmount": "356121810253", 63 | "percentSupply": 0.0356121810253 64 | }, 65 | "6QveEdBDdt3uME8ThVTY4neQb5gwGk66xvLCsck7T7vd": { 66 | "solAmount": "0.01", 67 | "tokenAmount": "355885027135", 68 | "percentSupply": 0.035588502713499996 69 | }, 70 | "H3BUsZQS13NVfTFNgtTCQkVhjNLsqErM3nhdfQuaS6cQ": { 71 | "solAmount": "0.01", 72 | "tokenAmount": "355648480091", 73 | "percentSupply": 0.0355648480091 74 | }, 75 | "7ZU6gmKxhk6sDwfdah7RYnyj6S6QV8q55EjJ4xRznUJb": { 76 | "solAmount": "0.01", 77 | "tokenAmount": "355412168809", 78 | "percentSupply": 0.0355412168809 79 | }, 80 | "GbgfWVrefi35q2VN5uxXuws2paPxdi37FWzuGoxV27d3": { 81 | "solAmount": "0.01", 82 | "tokenAmount": "355176092974", 83 | "percentSupply": 0.0355176092974 84 | }, 85 | "JBG4hvLmaZXAD4kA18hHjFJjuznx3SUkaNUvW56hNsG1": { 86 | "solAmount": "0.01", 87 | "tokenAmount": "354940252275", 88 | "percentSupply": 0.035494025227499996 89 | }, 90 | "7dcm7d9DDXF4FXwkJHCwx96qMzNFfXYhwoxg8jkKAmp": { 91 | "solAmount": "0.01", 92 | "tokenAmount": "354704646399", 93 | "percentSupply": 0.0354704646399 94 | }, 95 | "AbvcBg1aVVBcBbuPteMy8R2tSRuGcdKSXRzoz5vdhMT2": { 96 | "solAmount": "0.01", 97 | "tokenAmount": "354469275034", 98 | "percentSupply": 0.035446927503400005 99 | }, 100 | "9dFL6KGmeWT3J7cnPy5QMcKTjjXZXbbXGh5Q2xhZh3ET": { 101 | "solAmount": "0.01", 102 | "tokenAmount": "354234137870", 103 | "percentSupply": 0.035423413787 104 | }, 105 | "Fif2CMsVssFxnHzENtRvdyFqUBNn7GhoSY6KJ3oFheLs": { 106 | "solAmount": "0.01", 107 | "tokenAmount": "353999234596", 108 | "percentSupply": 0.0353999234596 109 | }, 110 | "4kpb9cm51ZwkQKBFv3CgAESvoYFiqDvadanLNfFArmD9": { 111 | "solAmount": "0.01", 112 | "tokenAmount": "353764564901", 113 | "percentSupply": 0.0353764564901 114 | }, 115 | "5NSoFyrUr6ok8ZxQpMBRyXtHt8jrNtTFcgaEpmcYh9zZ": { 116 | "solAmount": "0.01", 117 | "tokenAmount": "353530128476", 118 | "percentSupply": 0.0353530128476 119 | }, 120 | "iyh5sBrYth8nizpTVZcskS55mFHmQNNiyn1Na8u1o7R": { 121 | "solAmount": "0.01", 122 | "tokenAmount": "353295925013", 123 | "percentSupply": 0.0353295925013 124 | }, 125 | "99D3iuoqc6evmMmtuaUBTpSJTYKNTtREHsXRS8mNi4cP": { 126 | "solAmount": "0.01", 127 | "tokenAmount": "353061954201", 128 | "percentSupply": 0.0353061954201 129 | }, 130 | "B34DVmMUqZiy2QkNZaAuW9GtkLH5NAXeUH5EhLSvz19w": { 131 | "solAmount": "0.01", 132 | "tokenAmount": "352828215734", 133 | "percentSupply": 0.0352828215734 134 | }, 135 | "3df2bpvGBdu22YC4WaJ4sBZj3W2wMP4QjCBtMhUMEjLo": { 136 | "solAmount": "0.01", 137 | "tokenAmount": "352594709304", 138 | "percentSupply": 0.0352594709304 139 | }, 140 | "6aBxrcJh3XVdqyxe4A9yfp3UasbLYNEEqgeoD6uFooqf": { 141 | "solAmount": "0.01", 142 | "tokenAmount": "352361434604", 143 | "percentSupply": 0.0352361434604 144 | }, 145 | "6XqBbanhwBEz9hZWQboH9vd377F71SXZhsyvvG1S54wB": { 146 | "solAmount": "0.01", 147 | "tokenAmount": "352128391327", 148 | "percentSupply": 0.0352128391327 149 | }, 150 | "635vs6QifBiNQaScH8BWdFmsFf7ZxTnDDXAjve8KGgRh": { 151 | "solAmount": "0.01", 152 | "tokenAmount": "351895579168", 153 | "percentSupply": 0.0351895579168 154 | }, 155 | "GSrKPLQASRgbbMXJn5hYp6yQDBChzExNc7BkgF9VnRL9": { 156 | "solAmount": "0.011", 157 | "tokenAmount": "392940444772", 158 | "percentSupply": 0.039294044477199995 159 | }, 160 | "HH1Lz3eq3zD71QBxjnhDCcQcin7gE2k85Bcgn32USZkw": { 161 | "solAmount": "0.011", 162 | "tokenAmount": "392652627207", 163 | "percentSupply": 0.0392652627207 164 | }, 165 | "BAyhCdHdHWdWWobNbjaNta88WbYxespXWdQTzh9bLFQH": { 166 | "solAmount": "0.011", 167 | "tokenAmount": "392365125754", 168 | "percentSupply": 0.0392365125754 169 | }, 170 | "WGeLGomLtbFgkjf85zebMnHXGAYCYJDKQjLe78ERoUx": { 171 | "solAmount": "0.011", 172 | "tokenAmount": "392077939949", 173 | "percentSupply": 0.0392077939949 174 | }, 175 | "9ppNCae46wbN95PyaNVMsY7SwQboAWNgpKbSk4Xx4j4z": { 176 | "solAmount": "0.011", 177 | "tokenAmount": "391791069331", 178 | "percentSupply": 0.0391791069331 179 | }, 180 | "7uqMMhmzDQDDaK9q8G6t7uCTykrJtQP3sKBih9pu1StQ": { 181 | "solAmount": "0.011", 182 | "tokenAmount": "391504513438", 183 | "percentSupply": 0.0391504513438 184 | }, 185 | "Ddv7CrMmzGKjeENoRr7Xmz8vnDttMp14JJhN5isMQkg2": { 186 | "solAmount": "0.011", 187 | "tokenAmount": "391218271811", 188 | "percentSupply": 0.0391218271811 189 | }, 190 | "EPfWA7YqLN89h6a1aUFuEk8L64cPbS79Ao8FsG6Kd2X5": { 191 | "solAmount": "0.011", 192 | "tokenAmount": "390932343990", 193 | "percentSupply": 0.039093234399 194 | }, 195 | "DeW67h29cLo2hAFt9ftZJkhezAdyCUBaBZZ4oLCqWUzM": { 196 | "solAmount": "0.011", 197 | "tokenAmount": "390646729516", 198 | "percentSupply": 0.0390646729516 199 | }, 200 | "CMjYqtkKWdCbWdpLncRRCKDfznAQYTkWnQyNYoerVTAo": { 201 | "solAmount": "0.011", 202 | "tokenAmount": "390361427932", 203 | "percentSupply": 0.0390361427932 204 | }, 205 | "59ZWrCr3s5gcLupwdt8FydAEADxzZr9K23mReVpS5ab6": { 206 | "solAmount": "0.011", 207 | "tokenAmount": "390076438782", 208 | "percentSupply": 0.0390076438782 209 | }, 210 | "7ijkANyZBmw8ybxbFWDHDB41D27aswogFLc1ZsrSDdcD": { 211 | "solAmount": "0.011", 212 | "tokenAmount": "389791761608", 213 | "percentSupply": 0.038979176160799996 214 | }, 215 | "E9KocfZ7MW8Rm3iSqKC4pzR9wgD2VF3LeVCFwTevNiC8": { 216 | "solAmount": "0.011", 217 | "tokenAmount": "389507395956", 218 | "percentSupply": 0.0389507395956 219 | }, 220 | "3mjcvoxLhYU5969QYsUE73tMBadE8Cpftzt6kBpJzBBQ": { 221 | "solAmount": "0.011", 222 | "tokenAmount": "389223341371", 223 | "percentSupply": 0.0389223341371 224 | }, 225 | "7qR2nxAsZ3BgSfWo3NMejTVvfb4C8fNcTrBtCvqeSkR1": { 226 | "solAmount": "0.011", 227 | "tokenAmount": "388939597401", 228 | "percentSupply": 0.0388939597401 229 | }, 230 | "C86CmhH1zDRuz312A7XHsijYWuSu82188iaFMfZTH7sZ": { 231 | "solAmount": "0.011", 232 | "tokenAmount": "388656163591", 233 | "percentSupply": 0.0388656163591 234 | }, 235 | "Dd4LpGWDZmKkqxbZkg6xoshjG4xcJVPEKVoJ81eFEWZs": { 236 | "solAmount": "0.011", 237 | "tokenAmount": "388373039491", 238 | "percentSupply": 0.038837303949100004 239 | }, 240 | "7uuzvKG2y9cvxVG2ucVyBLVBW15J8Hpn9sifSCWnLMyY": { 241 | "solAmount": "0.011", 242 | "tokenAmount": "388090224648", 243 | "percentSupply": 0.0388090224648 244 | }, 245 | "6uR7ohVcFTDWGCxviYzNTvQ8daxDJmoyA59sg38F4yFq": { 246 | "solAmount": "0.011", 247 | "tokenAmount": "387807718614", 248 | "percentSupply": 0.0387807718614 249 | }, 250 | "B4QmpBUCTLjWaGkeZUj2KfVaUnQax8ZQ9M9AK22sWqjX": { 251 | "solAmount": "0.011", 252 | "tokenAmount": "387525520939", 253 | "percentSupply": 0.0387525520939 254 | }, 255 | "97kcpDdhGqu7134SH678nAdcLxTc3WwuxHDBaeaEv64q": { 256 | "solAmount": "0.011", 257 | "tokenAmount": "387243631173", 258 | "percentSupply": 0.0387243631173 259 | }, 260 | "HJeBmpPK8g6d1B6cHBkV3ZQguXLJAiw5muBeXK6zbAYW": { 261 | "solAmount": "0.011", 262 | "tokenAmount": "386962048869", 263 | "percentSupply": 0.0386962048869 264 | }, 265 | "EwPHafktDWEnCg4QMbTbJ4XB2wV6hMae2ct7aKSBkgZJ": { 266 | "solAmount": "0.011", 267 | "tokenAmount": "386680773581", 268 | "percentSupply": 0.0386680773581 269 | }, 270 | "3pP23hkEeCfinu51KWKQhyDE5eXreVmt7Gc3W9mfpawY": { 271 | "solAmount": "0.011", 272 | "tokenAmount": "386399804861", 273 | "percentSupply": 0.0386399804861 274 | } 275 | } -------------------------------------------------------------------------------- /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": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* 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": [], /* 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 | "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "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. */ 58 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 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 code. */ 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 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "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. */ 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 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 104 | 105 | /* Completeness */ 106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/jitoPool.ts: -------------------------------------------------------------------------------- 1 | import { connection, wallet, PUMP_PROGRAM, feeRecipient, eventAuthority, global, MPL_TOKEN_METADATA_PROGRAM_ID, mintAuthority, rpc, payer } from "../config"; 2 | import { 3 | PublicKey, 4 | VersionedTransaction, 5 | TransactionInstruction, 6 | SYSVAR_RENT_PUBKEY, 7 | TransactionMessage, 8 | SystemProgram, 9 | Keypair, 10 | LAMPORTS_PER_SOL, 11 | AddressLookupTableAccount, 12 | } from "@solana/web3.js"; 13 | import { loadKeypairs } from "./createKeys"; 14 | import { searcherClient } from "./clients/jito"; 15 | import { Bundle as JitoBundle } from "jito-ts/dist/sdk/block-engine/types.js"; 16 | import promptSync from "prompt-sync"; 17 | import * as spl from "@solana/spl-token"; 18 | import bs58 from "bs58"; 19 | import path from "path"; 20 | import fs from "fs"; 21 | import { Program } from "@coral-xyz/anchor"; 22 | import { getRandomTipAccount } from "./clients/config"; 23 | import BN from "bn.js"; 24 | import axios from "axios"; 25 | import * as anchor from "@coral-xyz/anchor"; 26 | 27 | const prompt = promptSync(); 28 | const keyInfoPath = path.join(__dirname, "keyInfo.json"); 29 | 30 | export async function buyBundle() { 31 | const provider = new anchor.AnchorProvider(new anchor.web3.Connection(rpc), new anchor.Wallet(wallet), { commitment: "confirmed" }); 32 | 33 | // Initialize pumpfun anchor 34 | const IDL_PumpFun = JSON.parse(fs.readFileSync("./pumpfun-IDL.json", "utf-8")) as anchor.Idl; 35 | 36 | const program = new anchor.Program(IDL_PumpFun, PUMP_PROGRAM, provider); 37 | 38 | // Start create bundle 39 | const bundledTxns: VersionedTransaction[] = []; 40 | const keypairs: Keypair[] = loadKeypairs(); 41 | 42 | let keyInfo: { [key: string]: any } = {}; 43 | if (fs.existsSync(keyInfoPath)) { 44 | const existingData = fs.readFileSync(keyInfoPath, "utf-8"); 45 | keyInfo = JSON.parse(existingData); 46 | } 47 | 48 | const lut = new PublicKey(keyInfo.addressLUT.toString()); 49 | 50 | const lookupTableAccount = (await connection.getAddressLookupTable(lut)).value; 51 | 52 | if (lookupTableAccount == null) { 53 | console.log("Lookup table account not found!"); 54 | process.exit(0); 55 | } 56 | 57 | // -------- step 1: ask nessesary questions for pool build -------- 58 | const name = prompt("Name of your token: "); 59 | const symbol = prompt("Symbol of your token: "); 60 | const description = prompt("Description of your token: "); 61 | const twitter = prompt("Twitter of your token: "); 62 | const telegram = prompt("Telegram of your token: "); 63 | const website = prompt("Website of your token: "); 64 | const tipAmt = +prompt("Jito tip in SOL: ") * LAMPORTS_PER_SOL; 65 | 66 | // -------- step 2: build pool init + dev snipe -------- 67 | const files = await fs.promises.readdir("./img"); 68 | if (files.length == 0) { 69 | console.log("No image found in the img folder"); 70 | return; 71 | } 72 | if (files.length > 1) { 73 | console.log("Multiple images found in the img folder, please only keep one image"); 74 | return; 75 | } 76 | const data: Buffer = fs.readFileSync(`./img/${files[0]}`); 77 | 78 | let formData = new FormData(); 79 | if (data) { 80 | formData.append("file", new Blob([data], { type: "image/jpeg" })); 81 | } else { 82 | console.log("No image found"); 83 | return; 84 | } 85 | 86 | formData.append("name", name); 87 | formData.append("symbol", symbol); 88 | formData.append("description", description); 89 | formData.append("twitter", twitter); 90 | formData.append("telegram", telegram); 91 | formData.append("website", website); 92 | formData.append("showName", "true"); 93 | 94 | let metadata_uri; 95 | try { 96 | const response = await axios.post("https://pump.fun/api/ipfs", formData, { 97 | headers: { 98 | "Content-Type": "multipart/form-data", 99 | }, 100 | }); 101 | metadata_uri = response.data.metadataUri; 102 | console.log("Metadata URI: ", metadata_uri); 103 | } catch (error) { 104 | console.error("Error uploading metadata:", error); 105 | } 106 | 107 | const mintKp = Keypair.fromSecretKey(Uint8Array.from(bs58.decode(keyInfo.mintPk))); 108 | console.log(`Mint: ${mintKp.publicKey.toBase58()}`); 109 | 110 | const [bondingCurve] = PublicKey.findProgramAddressSync([Buffer.from("bonding-curve"), mintKp.publicKey.toBytes()], program.programId); 111 | const [metadata] = PublicKey.findProgramAddressSync( 112 | [Buffer.from("metadata"), MPL_TOKEN_METADATA_PROGRAM_ID.toBytes(), mintKp.publicKey.toBytes()], 113 | MPL_TOKEN_METADATA_PROGRAM_ID 114 | ); 115 | 116 | const account1 = mintKp.publicKey; 117 | const account2 = mintAuthority; 118 | const account3 = bondingCurve; 119 | const account5 = global; 120 | const account6 = MPL_TOKEN_METADATA_PROGRAM_ID; 121 | const account7 = metadata; 122 | 123 | const createIx = await program.methods 124 | .create(name, symbol, metadata_uri) 125 | .accounts({ 126 | mint: account1, 127 | mintAuthority: account2, 128 | systemProgram: SystemProgram.programId, 129 | tokenProgram: spl.TOKEN_PROGRAM_ID, 130 | associatedTokenProgram: spl.ASSOCIATED_TOKEN_PROGRAM_ID, 131 | rent: SYSVAR_RENT_PUBKEY, 132 | eventAuthority, 133 | program: PUMP_PROGRAM, 134 | }) 135 | .instruction(); 136 | 137 | // Get the associated token address 138 | const ata = spl.getAssociatedTokenAddressSync(mintKp.publicKey, wallet.publicKey); 139 | const ataIx = spl.createAssociatedTokenAccountIdempotentInstruction(wallet.publicKey, ata, wallet.publicKey, mintKp.publicKey); 140 | 141 | // Extract tokenAmount from keyInfo for this keypair 142 | const keypairInfo = keyInfo[wallet.publicKey.toString()]; 143 | if (!keypairInfo) { 144 | console.log(`No key info found for keypair: ${wallet.publicKey.toString()}`); 145 | } 146 | 147 | // Calculate SOL amount based on tokenAmount 148 | const amount = new BN(keypairInfo.tokenAmount); 149 | const solAmount = new BN(100000 * keypairInfo.solAmount * LAMPORTS_PER_SOL); 150 | 151 | const buyIx = await program.methods 152 | .buy(amount, solAmount) 153 | .accounts({ 154 | systemProgram: SystemProgram.programId, 155 | tokenProgram: spl.TOKEN_PROGRAM_ID, 156 | rent: SYSVAR_RENT_PUBKEY, 157 | eventAuthority, 158 | program: PUMP_PROGRAM, 159 | }) 160 | .instruction(); 161 | 162 | const tipIxn = SystemProgram.transfer({ 163 | fromPubkey: wallet.publicKey, 164 | toPubkey: getRandomTipAccount(), 165 | lamports: BigInt(tipAmt), 166 | }); 167 | 168 | const initIxs: TransactionInstruction[] = [createIx, ataIx, buyIx, tipIxn]; 169 | 170 | const { blockhash } = await connection.getLatestBlockhash(); 171 | 172 | const messageV0 = new TransactionMessage({ 173 | payerKey: wallet.publicKey, 174 | instructions: initIxs, 175 | recentBlockhash: blockhash, 176 | }).compileToV0Message(); 177 | 178 | const fullTX = new VersionedTransaction(messageV0); 179 | fullTX.sign([wallet, mintKp]); 180 | 181 | bundledTxns.push(fullTX); 182 | 183 | // -------- step 3: create swap txns -------- 184 | const txMainSwaps: VersionedTransaction[] = await createWalletSwaps(blockhash, keypairs, lookupTableAccount, bondingCurve, mintKp.publicKey, program); 185 | bundledTxns.push(...txMainSwaps); 186 | 187 | // -------- step 4: send bundle -------- 188 | /* 189 | // Simulate each transaction 190 | for (const tx of bundledTxns) { 191 | try { 192 | const simulationResult = await connection.simulateTransaction(tx, { commitment: "processed" }); 193 | console.log(simulationResult); 194 | 195 | if (simulationResult.value.err) { 196 | console.error("Simulation error for transaction:", simulationResult.value.err); 197 | } else { 198 | console.log("Simulation success for transaction. Logs:"); 199 | simulationResult.value.logs?.forEach(log => console.log(log)); 200 | } 201 | } catch (error) { 202 | console.error("Error during simulation:", error); 203 | } 204 | } 205 | */ 206 | 207 | await sendBundle(bundledTxns); 208 | } 209 | 210 | async function createWalletSwaps( 211 | blockhash: string, 212 | keypairs: Keypair[], 213 | lut: AddressLookupTableAccount, 214 | bondingCurve: PublicKey, 215 | associatedBondingCurve: PublicKey, 216 | mint: PublicKey, 217 | program: Program 218 | ): Promise { 219 | const txsSigned: VersionedTransaction[] = []; 220 | const chunkedKeypairs = chunkArray(keypairs, 6); 221 | 222 | // Load keyInfo data from JSON file 223 | let keyInfo: { [key: string]: { solAmount: number; tokenAmount: string; percentSupply: number } } = {}; 224 | if (fs.existsSync(keyInfoPath)) { 225 | const existingData = fs.readFileSync(keyInfoPath, "utf-8"); 226 | keyInfo = JSON.parse(existingData); 227 | } 228 | 229 | // Iterate over each chunk of keypairs 230 | for (let chunkIndex = 0; chunkIndex < chunkedKeypairs.length; chunkIndex++) { 231 | const chunk = chunkedKeypairs[chunkIndex]; 232 | const instructionsForChunk: TransactionInstruction[] = []; 233 | 234 | // Iterate over each keypair in the chunk to create swap instructions 235 | for (let i = 0; i < chunk.length; i++) { 236 | const keypair = chunk[i]; 237 | console.log(`Processing keypair ${i + 1}/${chunk.length}:`, keypair.publicKey.toString()); 238 | 239 | const ataAddress = await spl.getAssociatedTokenAddress(mint, keypair.publicKey); 240 | 241 | const createTokenAta = spl.createAssociatedTokenAccountIdempotentInstruction(payer.publicKey, ataAddress, keypair.publicKey, mint); 242 | 243 | // Extract tokenAmount from keyInfo for this keypair 244 | const keypairInfo = keyInfo[keypair.publicKey.toString()]; 245 | if (!keypairInfo) { 246 | console.log(`No key info found for keypair: ${keypair.publicKey.toString()}`); 247 | continue; 248 | } 249 | 250 | // Calculate SOL amount based on tokenAmount 251 | const amount = new BN(keypairInfo.tokenAmount); 252 | const solAmount = new BN(100000 * keypairInfo.solAmount * LAMPORTS_PER_SOL); 253 | 254 | const buyIx = await program.methods 255 | .buy(amount, solAmount) 256 | .accounts({ 257 | systemProgram: SystemProgram.programId, 258 | tokenProgram: spl.TOKEN_PROGRAM_ID, 259 | rent: SYSVAR_RENT_PUBKEY, 260 | eventAuthority, 261 | program: PUMP_PROGRAM, 262 | }) 263 | .instruction(); 264 | 265 | instructionsForChunk.push(createTokenAta, buyIx); 266 | } 267 | 268 | 269 | const message = new TransactionMessage({ 270 | payerKey: keypair.publicKey, 271 | recentBlockhash: blockhash, 272 | instructions: instructionsForChunk, 273 | }).compileToV0Message([lut]); 274 | 275 | const serializedMsg = message.serialize(); 276 | console.log("Txn size:", message.length); 277 | if (message.length > 1232) { 278 | console.log("tx too big"); 279 | } 280 | 281 | console.log( 282 | "Signing transaction with chunk signers", 283 | chunk.map((kp) => kp.publicKey.toString()) 284 | ); 285 | 286 | // Sign with the wallet for tip on the last instruction 287 | for (const kp of chunk) { 288 | if (kp.publicKey.toString() in keyInfo) { 289 | versionedTx.sign([kp]); 290 | } 291 | } 292 | 293 | versionedTx.sign([payer]); 294 | 295 | txsSigned.push(versionedTx); 296 | } 297 | 298 | return txsSigned; 299 | } 300 | 301 | function chunkArray(array: T[], size: number): T[][] { 302 | return Array.from({ length: Math.ceil(array.length / size) }, (v, i) => array.slice(i * size, i * size + size)); 303 | } 304 | 305 | export async function sendBundle(bundledTxns: VersionedTransaction[]) { 306 | /* 307 | // Simulate each transaction 308 | for (const tx of bundledTxns) { 309 | try { 310 | const simulationResult = await connection.simulateTransaction(tx, { commitment: "processed" }); 311 | 312 | if (simulationResult.value.err) { 313 | console.error("Simulation error for transaction:", simulationResult.value.err); 314 | } else { 315 | console.log("Simulation success for transaction. Logs:"); 316 | simulationResult.value.logs?.forEach(log => console.log(log)); 317 | } 318 | } catch (error) { 319 | console.error("Error during simulation:", error); 320 | } 321 | } 322 | //*/ 323 | 324 | try { 325 | const bundleId = await searcherClient.sendBundle(new JitoBundle(bundledTxns, bundledTxns.length)); 326 | console.log(`Bundle ${bundleId} sent.`); 327 | 328 | ///* 329 | // Assuming onBundleResult returns a Promise 330 | const result = await new Promise((resolve, reject) => { 331 | searcherClient.onBundleResult( 332 | (result) => { 333 | console.log("Received bundle result:", result); 334 | resolve(result); // Resolve the promise with the result 335 | }, 336 | (e: Error) => { 337 | console.error("Error receiving bundle result:", e); 338 | reject(e); // Reject the promise if there's an error 339 | } 340 | ); 341 | }); 342 | 343 | console.log("Result:", result); 344 | //*/ 345 | } catch (error) { 346 | const err = error as any; 347 | console.error("Error sending bundle:", err.message); 348 | 349 | if (err?.message?.includes("Bundle Dropped, no connected leader up soon")) { 350 | console.error("Error sending bundle: Bundle Dropped, no connected leader up soon."); 351 | } else { 352 | console.error("An unexpected error occurred:", err.message); 353 | } 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /src/sellRay.ts: -------------------------------------------------------------------------------- 1 | import { connection, rpc, wallet, payer, RayLiqPoolv4 } from "../config"; 2 | import { PublicKey, VersionedTransaction, SYSVAR_RENT_PUBKEY, TransactionMessage, SystemProgram, Keypair, LAMPORTS_PER_SOL, TransactionInstruction } from "@solana/web3.js"; 3 | import { loadKeypairs } from "./createKeys"; 4 | import { searcherClient } from "./clients/jito"; 5 | import { Bundle as JitoBundle } from "jito-ts/dist/sdk/block-engine/types.js"; 6 | import promptSync from "prompt-sync"; 7 | import * as spl from "@solana/spl-token"; 8 | import bs58 from "bs58"; 9 | import path from "path"; 10 | import fs from "fs"; 11 | import * as anchor from "@coral-xyz/anchor"; 12 | import { randomInt } from "crypto"; 13 | import { getRandomTipAccount } from "./clients/config"; 14 | import BN from "bn.js"; 15 | import { derivePoolKeys, IPoolKeys } from "./clients/poolKeysReassigned"; 16 | 17 | const prompt = promptSync(); 18 | const keyInfoPath = path.join(__dirname, "keyInfo.json"); 19 | 20 | function chunkArray(array: T[], size: number): T[][] { 21 | return Array.from({ length: Math.ceil(array.length / size) }, (v, i) => array.slice(i * size, i * size + size)); 22 | } 23 | 24 | async function sendBundle(bundledTxns: VersionedTransaction[]) { 25 | /* 26 | // Simulate each transaction 27 | for (const tx of bundledTxns) { 28 | try { 29 | const simulationResult = await connection.simulateTransaction(tx, { commitment: "processed" }); 30 | 31 | if (simulationResult.value.err) { 32 | console.error("Simulation error for transaction:", simulationResult.value.err); 33 | } else { 34 | console.log("Simulation success for transaction. Logs:"); 35 | simulationResult.value.logs?.forEach(log => console.log(log)); 36 | } 37 | } catch (error) { 38 | console.error("Error during simulation:", error); 39 | } 40 | } 41 | */ 42 | 43 | try { 44 | const bundleId = await searcherClient.sendBundle(new JitoBundle(bundledTxns, bundledTxns.length)); 45 | console.log(`Bundle ${bundleId} sent.`); 46 | 47 | /* 48 | // Assuming onBundleResult returns a Promise 49 | const result = await new Promise((resolve, reject) => { 50 | searcherClient.onBundleResult( 51 | (result) => { 52 | console.log('Received bundle result:', result); 53 | resolve(result); // Resolve the promise with the result 54 | }, 55 | (e: Error) => { 56 | console.error('Error receiving bundle result:', e); 57 | reject(e); // Reject the promise if there's an error 58 | } 59 | ); 60 | }); 61 | 62 | console.log('Result:', result); 63 | */ 64 | } catch (error) { 65 | const err = error as any; 66 | console.error("Error sending bundle:", err.message); 67 | 68 | if (err?.message?.includes("Bundle Dropped, no connected leader up soon")) { 69 | console.error("Error sending bundle: Bundle Dropped, no connected leader up soon."); 70 | } else { 71 | console.error("An unexpected error occurred:", err.message); 72 | } 73 | } 74 | } 75 | 76 | export async function sellXPercentageRAY() { 77 | // Start selling 78 | const bundledTxns = []; 79 | const keypairs = loadKeypairs(); // Ensure this function is correctly defined to load your Keypairs 80 | 81 | let poolInfo: { [key: string]: any } = {}; 82 | if (fs.existsSync(keyInfoPath)) { 83 | const data = fs.readFileSync(keyInfoPath, "utf-8"); 84 | poolInfo = JSON.parse(data); 85 | } 86 | 87 | const lut = new PublicKey(poolInfo.addressLUT.toString()); 88 | 89 | const lookupTableAccount = (await connection.getAddressLookupTable(lut)).value; 90 | 91 | if (lookupTableAccount == null) { 92 | console.log("Lookup table account not found!"); 93 | process.exit(0); 94 | } 95 | 96 | const mintKp = Keypair.fromSecretKey(Uint8Array.from(bs58.decode(poolInfo.mintPk))); 97 | //console.log(`Mint: ${mintKp.publicKey.toBase58()}`); 98 | 99 | const marketID = new PublicKey(prompt("Enter marketID of your migration: ")); 100 | const supplyPercent = +prompt("Percentage to sell (Ex. 1 for 1%): ") / 100; 101 | const jitoTipAmt = +prompt("Jito tip in Sol (Ex. 0.01): ") * LAMPORTS_PER_SOL; 102 | 103 | if (supplyPercent > 0.25) { 104 | // protect investors and prevent fraud 105 | console.log("You cannot sell over 25% at a time."); 106 | console.log("The price impact is too high."); 107 | 108 | return; 109 | } 110 | 111 | const keys = await derivePoolKeys(marketID); // Ensure this function is correctly defined to derive necessary keys 112 | 113 | if (keys == null) { 114 | console.log("Keys not found!"); 115 | process.exit(0); 116 | } 117 | 118 | const mintInfo = await connection.getTokenSupply(mintKp.publicKey); 119 | 120 | let sellTotalAmount = 0; 121 | 122 | const chunkedKeypairs = chunkArray(keypairs, 6); // Adjust chunk size as needed 123 | 124 | // start the selling process 125 | const PayerTokenATA = await spl.getAssociatedTokenAddress(new PublicKey(poolInfo.mint), payer.publicKey); 126 | 127 | const { blockhash } = await connection.getLatestBlockhash(); 128 | 129 | for (let chunkIndex = 0; chunkIndex < chunkedKeypairs.length; chunkIndex++) { 130 | const chunk = chunkedKeypairs[chunkIndex]; 131 | const instructionsForChunk = []; 132 | const isFirstChunk = chunkIndex === 0; // Check if this is the first chunk 133 | 134 | if (isFirstChunk) { 135 | // Handle the first chunk separately 136 | const transferAmount = await getSellBalance(wallet, new PublicKey(poolInfo.mint), supplyPercent); 137 | sellTotalAmount += transferAmount; // Keep track to sell at the end 138 | console.log(`Sending ${transferAmount / 1e6} from dev wallet.`); 139 | 140 | const ataIx = spl.createAssociatedTokenAccountIdempotentInstruction(payer.publicKey, PayerTokenATA, mintKp.publicKey); 141 | 142 | const TokenATA = await spl.getAssociatedTokenAddress(new PublicKey(poolInfo.mint), wallet.publicKey); 143 | const transferIx = spl.createTransferInstruction(TokenATA, PayerTokenATA, wallet.publicKey, transferAmount); 144 | 145 | instructionsForChunk.push(ataIx, transferIx); 146 | } 147 | 148 | for (let keypair of chunk) { 149 | const transferAmount = await getSellBalance(keypair, new PublicKey(poolInfo.mint), supplyPercent); 150 | sellTotalAmount += transferAmount; // Keep track to sell at the end 151 | console.log(`Sending ${transferAmount / 1e6} from ${keypair.publicKey.toString()}.`); 152 | 153 | const TokenATA = await spl.getAssociatedTokenAddress(new PublicKey(poolInfo.mint), keypair.publicKey); 154 | const transferIx = spl.createTransferInstruction(TokenATA, PayerTokenATA, keypair.publicKey, transferAmount); 155 | instructionsForChunk.push(transferIx); 156 | } 157 | 158 | if (instructionsForChunk.length > 0) { 159 | const message = new TransactionMessage({ 160 | payerKey: payer.publicKey, 161 | recentBlockhash: blockhash, 162 | instructions: instructionsForChunk, 163 | }).compileToV0Message([lookupTableAccount]); 164 | 165 | const versionedTx = new VersionedTransaction(message); 166 | 167 | const serializedMsg = versionedTx.serialize(); 168 | console.log("Txn size:", serializedMsg.length); 169 | if (serializedMsg.length > 1232) { 170 | console.log("tx too big"); 171 | } 172 | 173 | versionedTx.sign([payer]); // Sign with payer first 174 | 175 | if (isFirstChunk) { 176 | versionedTx.sign([wallet]); // Sign with the dev wallet for the first chunk 177 | } 178 | 179 | bundledTxns.push(versionedTx); 180 | } 181 | } 182 | 183 | const payerNum = randomInt(0, 24); 184 | const payerKey = keypairs[payerNum]; 185 | 186 | const sellPayerIxs = []; 187 | 188 | const PayerwSolATA = await spl.getAssociatedTokenAddress(spl.NATIVE_MINT, payer.publicKey); 189 | 190 | const { sellIxs } = makeSwap(keys, PayerwSolATA, PayerTokenATA, true, payer, sellTotalAmount); 191 | 192 | console.log(`TOTAL: Selling ${sellTotalAmount / 1e6}.`); 193 | 194 | if (+mintInfo.value.amount * 0.25 <= sellTotalAmount) { 195 | // protect investors from fraud and prevent illegal use 196 | console.log("Price impact too high."); 197 | console.log("Cannot sell more than 25% of supply at a time."); 198 | 199 | return; 200 | } 201 | 202 | sellPayerIxs.push( 203 | spl.createAssociatedTokenAccountIdempotentInstruction(payer.publicKey, PayerwSolATA, payer.publicKey, spl.NATIVE_MINT), 204 | ...sellIxs, 205 | SystemProgram.transfer({ 206 | fromPubkey: payer.publicKey, 207 | toPubkey: getRandomTipAccount(), 208 | lamports: BigInt(jitoTipAmt), 209 | }) 210 | ); 211 | 212 | const sellMessage = new TransactionMessage({ 213 | payerKey: payerKey.publicKey, 214 | recentBlockhash: blockhash, 215 | instructions: sellPayerIxs, 216 | }).compileToV0Message([lookupTableAccount]); 217 | 218 | const sellTx = new VersionedTransaction(sellMessage); 219 | 220 | const serializedMsg = sellTx.serialize(); 221 | console.log("Txn size:", serializedMsg.length); 222 | if (serializedMsg.length > 1232) { 223 | console.log("tx too big"); 224 | } 225 | 226 | sellTx.sign([payer, payerKey]); 227 | 228 | bundledTxns.push(sellTx); 229 | 230 | await sendBundle(bundledTxns); 231 | 232 | return; 233 | } 234 | 235 | async function getSellBalance(keypair: Keypair, mint: PublicKey, supplyPercent: number) { 236 | let amount; 237 | try { 238 | const tokenAccountPubKey = spl.getAssociatedTokenAddressSync(mint, keypair.publicKey); 239 | const balance = await connection.getTokenAccountBalance(tokenAccountPubKey); 240 | amount = Math.floor(Number(balance.value.amount) * supplyPercent); 241 | } catch (e) { 242 | amount = 0; 243 | } 244 | 245 | return amount; 246 | } 247 | 248 | function makeSwap(poolKeys: IPoolKeys, wSolATA: PublicKey, TokenATA: PublicKey, reverse: boolean, keypair: Keypair, amountIn: number | bigint, minAmountOut = 0) { 249 | const account1 = spl.TOKEN_PROGRAM_ID; // token program 250 | const account2 = poolKeys.id; // amm id writable 251 | const account3 = poolKeys.authority; // amm authority 252 | const account4 = poolKeys.openOrders; // amm open orders writable 253 | const account5 = poolKeys.targetOrders; // amm target orders writable 254 | const account6 = poolKeys.baseVault; // pool coin token account writable AKA baseVault 255 | const account7 = poolKeys.quoteVault; // pool pc token account writable AKA quoteVault 256 | const account8 = poolKeys.marketProgramId; // serum program id 257 | const account9 = poolKeys.marketId; // serum market writable 258 | const account10 = poolKeys.marketBids; // serum bids writable 259 | const account11 = poolKeys.marketAsks; // serum asks writable 260 | const account12 = poolKeys.marketEventQueue; // serum event queue writable 261 | const account13 = poolKeys.marketBaseVault; // serum coin vault writable AKA marketBaseVault 262 | const account14 = poolKeys.marketQuoteVault; // serum pc vault writable AKA marketQuoteVault 263 | const inAmount = amountIn; 264 | const minAmount = minAmountOut; 265 | let account16 = wSolATA; // user source token account writable 266 | let account17 = TokenATA; // user dest token account writable 267 | const account18 = keypair.publicKey; // user owner (signer) writable 268 | 269 | if (reverse === true) { 270 | account16 = TokenATA; 271 | account17 = wSolATA; 272 | } 273 | 274 | const args = { 275 | amountIn: new BN(inAmount.toString()), 276 | minimumAmountOut: new BN(minAmount), 277 | }; 278 | 279 | const buffer = Buffer.alloc(16); 280 | args.amountIn.toArrayLike(Buffer, "le", 8).copy(buffer, 0); 281 | args.minimumAmountOut.toArrayLike(Buffer, "le", 8).copy(buffer, 8); 282 | const prefix = Buffer.from([0x09]); 283 | const instructionData = Buffer.concat([prefix, buffer]); 284 | const accountMetas = [ 285 | { pubkey: account1, isSigner: false, isWritable: false }, 286 | { pubkey: account2, isSigner: false, isWritable: true }, 287 | { pubkey: account3, isSigner: false, isWritable: false }, 288 | { pubkey: account4, isSigner: false, isWritable: true }, 289 | { pubkey: account5, isSigner: false, isWritable: true }, 290 | { pubkey: account6, isSigner: false, isWritable: true }, 291 | { pubkey: account7, isSigner: false, isWritable: true }, 292 | { pubkey: account8, isSigner: false, isWritable: false }, 293 | { pubkey: account9, isSigner: false, isWritable: true }, 294 | { pubkey: account10, isSigner: false, isWritable: true }, 295 | { pubkey: account11, isSigner: false, isWritable: true }, 296 | { pubkey: account12, isSigner: false, isWritable: true }, 297 | { pubkey: account13, isSigner: false, isWritable: true }, 298 | { pubkey: account14, isSigner: false, isWritable: true }, 299 | { pubkey: account16, isSigner: false, isWritable: true }, 300 | { pubkey: account17, isSigner: false, isWritable: true }, 301 | { pubkey: account18, isSigner: true, isWritable: true }, 302 | ]; 303 | 304 | const swap = new TransactionInstruction({ 305 | keys: accountMetas, 306 | programId: RayLiqPoolv4, 307 | data: instructionData, 308 | }); 309 | 310 | let buyIxs: TransactionInstruction[] = []; 311 | let sellIxs: TransactionInstruction[] = []; 312 | 313 | if (reverse === false) { 314 | buyIxs.push(swap); 315 | } 316 | 317 | if (reverse === true) { 318 | sellIxs.push(swap); 319 | } 320 | 321 | return { buyIxs, sellIxs }; 322 | } 323 | -------------------------------------------------------------------------------- /src/senderUI.ts: -------------------------------------------------------------------------------- 1 | import { Keypair, PublicKey, SystemProgram, TransactionInstruction, VersionedTransaction, LAMPORTS_PER_SOL, TransactionMessage, Blockhash } from "@solana/web3.js"; 2 | import { loadKeypairs } from "./createKeys"; 3 | import { wallet, connection, payer } from "../config"; 4 | import * as spl from "@solana/spl-token"; 5 | import { searcherClient } from "./clients/jito"; 6 | import { Bundle as JitoBundle } from "jito-ts/dist/sdk/block-engine/types.js"; 7 | import promptSync from "prompt-sync"; 8 | import { createLUT, extendLUT } from "./createLUT"; 9 | import fs from "fs"; 10 | import path from "path"; 11 | import { getRandomTipAccount } from "./clients/config"; 12 | import BN from "bn.js"; 13 | 14 | const prompt = promptSync(); 15 | const keyInfoPath = path.join(__dirname, "keyInfo.json"); 16 | 17 | let poolInfo: { [key: string]: any } = {}; 18 | if (fs.existsSync(keyInfoPath)) { 19 | const data = fs.readFileSync(keyInfoPath, "utf-8"); 20 | poolInfo = JSON.parse(data); 21 | } 22 | 23 | interface Buy { 24 | pubkey: PublicKey; 25 | solAmount: Number; 26 | tokenAmount: BN; 27 | percentSupply: number; 28 | } 29 | 30 | async function generateSOLTransferForKeypairs(tipAmt: number, steps: number = 24): Promise { 31 | const keypairs: Keypair[] = loadKeypairs(); 32 | const ixs: TransactionInstruction[] = []; 33 | 34 | let existingData: any = {}; 35 | if (fs.existsSync(keyInfoPath)) { 36 | existingData = JSON.parse(fs.readFileSync(keyInfoPath, "utf-8")); 37 | } 38 | 39 | // Dev wallet send first 40 | if (!existingData[wallet.publicKey.toString()] || !existingData[wallet.publicKey.toString()].solAmount) { 41 | console.log(`Missing solAmount for dev wallet, skipping.`); 42 | } 43 | 44 | const solAmount = parseFloat(existingData[wallet.publicKey.toString()].solAmount); 45 | 46 | ixs.push( 47 | SystemProgram.transfer({ 48 | fromPubkey: payer.publicKey, 49 | toPubkey: wallet.publicKey, 50 | lamports: Math.floor((solAmount * 1.015 + 0.0025) * LAMPORTS_PER_SOL), 51 | }) 52 | ); 53 | 54 | // Loop through the keypairs and process each one 55 | for (let i = 0; i < Math.min(steps, keypairs.length); i++) { 56 | const keypair = keypairs[i]; 57 | const keypairPubkeyStr = keypair.publicKey.toString(); 58 | 59 | if (!existingData[keypairPubkeyStr] || !existingData[keypairPubkeyStr].solAmount) { 60 | console.log(`Missing solAmount for wallet ${i + 1}, skipping.`); 61 | continue; 62 | } 63 | 64 | const solAmount = parseFloat(existingData[keypairPubkeyStr].solAmount); 65 | 66 | try { 67 | ixs.push( 68 | SystemProgram.transfer({ 69 | fromPubkey: payer.publicKey, 70 | toPubkey: keypair.publicKey, 71 | lamports: Math.floor((solAmount * 1.015 + 0.0025) * LAMPORTS_PER_SOL), 72 | }) 73 | ); 74 | console.log(`Sent ${(solAmount * 1.015 + 0.0025).toFixed(3)} SOL to Wallet ${i + 1} (${keypair.publicKey.toString()})`); 75 | } catch (error) { 76 | console.error(`Error creating transfer instruction for wallet ${i + 1}:`, error); 77 | continue; 78 | } 79 | } 80 | 81 | ixs.push( 82 | SystemProgram.transfer({ 83 | fromPubkey: payer.publicKey, 84 | toPubkey: getRandomTipAccount(), 85 | lamports: BigInt(tipAmt), 86 | }) 87 | ); 88 | 89 | return ixs; 90 | } 91 | 92 | function chunkArray(array: T[], chunkSize: number): T[][] { 93 | const chunks = []; 94 | for (let i = 0; i < array.length; i += chunkSize) { 95 | chunks.push(array.slice(i, i + chunkSize)); 96 | } 97 | return chunks; 98 | } 99 | 100 | async function createAndSignVersionedTxWithKeypairs(instructionsChunk: TransactionInstruction[], blockhash: Blockhash | string): Promise { 101 | let poolInfo: { [key: string]: any } = {}; 102 | if (fs.existsSync(keyInfoPath)) { 103 | const data = fs.readFileSync(keyInfoPath, "utf-8"); 104 | poolInfo = JSON.parse(data); 105 | } 106 | 107 | const lut = new PublicKey(poolInfo.addressLUT.toString()); 108 | 109 | const lookupTableAccount = (await connection.getAddressLookupTable(lut)).value; 110 | 111 | if (lookupTableAccount == null) { 112 | console.log("Lookup table account not found!"); 113 | process.exit(0); 114 | } 115 | 116 | const addressesMain: PublicKey[] = []; 117 | instructionsChunk.forEach((ixn) => { 118 | ixn.keys.forEach((key) => { 119 | addressesMain.push(key.pubkey); 120 | }); 121 | }); 122 | 123 | const message = new TransactionMessage({ 124 | payerKey: payer.publicKey, 125 | recentBlockhash: blockhash, 126 | instructions: instructionsChunk, 127 | }).compileToV0Message([lookupTableAccount]); 128 | 129 | const versionedTx = new VersionedTransaction(message); 130 | 131 | versionedTx.sign([payer]); 132 | 133 | /* 134 | // Simulate each txn 135 | const simulationResult = await connection.simulateTransaction(versionedTx, { commitment: "processed" }); 136 | 137 | if (simulationResult.value.err) { 138 | console.log("Simulation error:", simulationResult.value.err); 139 | } else { 140 | console.log("Simulation success. Logs:"); 141 | simulationResult.value.logs?.forEach(log => console.log(log)); 142 | } 143 | */ 144 | 145 | return versionedTx; 146 | } 147 | 148 | async function processInstructionsSOL(ixs: TransactionInstruction[], blockhash: string | Blockhash): Promise { 149 | const txns: VersionedTransaction[] = []; 150 | const instructionChunks = chunkArray(ixs, 45); 151 | 152 | for (let i = 0; i < instructionChunks.length; i++) { 153 | const versionedTx = await createAndSignVersionedTxWithKeypairs(instructionChunks[i], blockhash); 154 | txns.push(versionedTx); 155 | } 156 | 157 | return txns; 158 | } 159 | 160 | async function sendBundle(txns: VersionedTransaction[]) { 161 | /* 162 | // Simulate each transaction 163 | for (const tx of txns) { 164 | try { 165 | const simulationResult = await connection.simulateTransaction(tx, { commitment: "processed" }); 166 | 167 | if (simulationResult.value.err) { 168 | console.error("Simulation error for transaction:", simulationResult.value.err); 169 | } else { 170 | console.log("Simulation success for transaction. Logs:"); 171 | simulationResult.value.logs?.forEach(log => console.log(log)); 172 | } 173 | } catch (error) { 174 | console.error("Error during simulation:", error); 175 | } 176 | } 177 | */ 178 | 179 | try { 180 | const bundleId = await searcherClient.sendBundle(new JitoBundle(txns, txns.length)); 181 | console.log(`Bundle ${bundleId} sent.`); 182 | } catch (error) { 183 | const err = error as any; 184 | console.error("Error sending bundle:", err.message); 185 | 186 | if (err?.message?.includes("Bundle Dropped, no connected leader up soon")) { 187 | console.error("Error sending bundle: Bundle Dropped, no connected leader up soon."); 188 | } else { 189 | console.error("An unexpected error occurred:", err.message); 190 | } 191 | } 192 | } 193 | 194 | async function generateATAandSOL() { 195 | const jitoTipAmt = +prompt("Jito tip in Sol (Ex. 0.01): ") * LAMPORTS_PER_SOL; 196 | 197 | const { blockhash } = await connection.getLatestBlockhash(); 198 | const sendTxns: VersionedTransaction[] = []; 199 | 200 | const solIxs = await generateSOLTransferForKeypairs(jitoTipAmt); 201 | 202 | const solTxns = await processInstructionsSOL(solIxs, blockhash); 203 | sendTxns.push(...solTxns); 204 | 205 | await sendBundle(sendTxns); 206 | } 207 | 208 | async function createReturns() { 209 | const txsSigned: VersionedTransaction[] = []; 210 | const keypairs = loadKeypairs(); 211 | const chunkedKeypairs = chunkArray(keypairs, 7); // EDIT CHUNKS? 212 | 213 | const jitoTipIn = prompt("Jito tip in Sol (Ex. 0.01): "); 214 | const TipAmt = parseFloat(jitoTipIn) * LAMPORTS_PER_SOL; 215 | 216 | const { blockhash } = await connection.getLatestBlockhash(); 217 | 218 | // Iterate over each chunk of keypairs 219 | for (let chunkIndex = 0; chunkIndex < chunkedKeypairs.length; chunkIndex++) { 220 | const chunk = chunkedKeypairs[chunkIndex]; 221 | const instructionsForChunk: TransactionInstruction[] = []; 222 | 223 | // Iterate over each keypair in the chunk to create swap instructions 224 | for (let i = 0; i < chunk.length; i++) { 225 | const keypair = chunk[i]; 226 | console.log(`Processing keypair ${i + 1}/${chunk.length}:`, keypair.publicKey.toString()); 227 | 228 | const balance = await connection.getBalance(keypair.publicKey); 229 | 230 | const sendSOLixs = SystemProgram.transfer({ 231 | fromPubkey: keypair.publicKey, 232 | toPubkey: payer.publicKey, 233 | lamports: balance, 234 | }); 235 | 236 | instructionsForChunk.push(sendSOLixs); 237 | } 238 | 239 | if (chunkIndex === chunkedKeypairs.length - 1) { 240 | const tipSwapIxn = SystemProgram.transfer({ 241 | fromPubkey: payer.publicKey, 242 | toPubkey: getRandomTipAccount(), 243 | lamports: BigInt(TipAmt), 244 | }); 245 | instructionsForChunk.push(tipSwapIxn); 246 | console.log("Jito tip added :)."); 247 | } 248 | 249 | const lut = new PublicKey(poolInfo.addressLUT.toString()); 250 | 251 | const message = new TransactionMessage({ 252 | payerKey: payer.publicKey, 253 | recentBlockhash: blockhash, 254 | instructions: instructionsForChunk, 255 | }).compileToV0Message([poolInfo.addressLUT]); 256 | 257 | const versionedTx = new VersionedTransaction(message); 258 | 259 | const serializedMsg = versionedTx.serialize(); 260 | console.log("Txn size:", serializedMsg.length); 261 | if (serializedMsg.length > 1232) { 262 | console.log("tx too big"); 263 | } 264 | 265 | console.log( 266 | "Signing transaction with chunk signers", 267 | chunk.map((kp) => kp.publicKey.toString()) 268 | ); 269 | 270 | versionedTx.sign([payer]); 271 | 272 | for (const keypair of chunk) { 273 | versionedTx.sign([keypair]); 274 | } 275 | 276 | txsSigned.push(versionedTx); 277 | } 278 | 279 | await sendBundle(txsSigned); 280 | } 281 | 282 | async function simulateAndWriteBuys() { 283 | const keypairs = loadKeypairs(); 284 | 285 | const tokenDecimals = 10 ** 6; 286 | const tokenTotalSupply = 1000000000 * tokenDecimals; 287 | let initialRealSolReserves = 0; 288 | let initialVirtualTokenReserves = 1073000000 * tokenDecimals; 289 | let initialRealTokenReserves = 793100000 * tokenDecimals; 290 | let totalTokensBought = 0; 291 | const buys: { pubkey: PublicKey; solAmount: Number; tokenAmount: BN; percentSupply: number }[] = []; 292 | 293 | for (let it = 0; it <= 24; it++) { 294 | let keypair; 295 | 296 | let solInput; 297 | if (it === 0) { 298 | solInput = prompt(`Enter the amount of SOL for dev wallet: `); 299 | solInput = Number(solInput) * 1.21; 300 | keypair = wallet; 301 | } else { 302 | solInput = +prompt(`Enter the amount of SOL for wallet ${it}: `); 303 | keypair = keypairs[it - 1]; 304 | } 305 | 306 | const solAmount = solInput * LAMPORTS_PER_SOL; 307 | 308 | if (isNaN(solAmount) || solAmount <= 0) { 309 | console.log(`Invalid input for wallet ${it}, skipping.`); 310 | continue; 311 | } 312 | 313 | const e = new BN(solAmount); 314 | const initialVirtualSolReserves = 30 * LAMPORTS_PER_SOL + initialRealSolReserves; 315 | const a = new BN(initialVirtualSolReserves).mul(new BN(initialVirtualTokenReserves)); 316 | const i = new BN(initialVirtualSolReserves).add(e); 317 | const l = a.div(i).add(new BN(1)); 318 | let tokensToBuy = new BN(initialVirtualTokenReserves).sub(l); 319 | tokensToBuy = BN.min(tokensToBuy, new BN(initialRealTokenReserves)); 320 | 321 | const tokensBought = tokensToBuy.toNumber(); 322 | const percentSupply = (tokensBought / tokenTotalSupply) * 100; 323 | 324 | console.log(`Wallet ${it}: Bought ${tokensBought / tokenDecimals} tokens for ${e.toNumber() / LAMPORTS_PER_SOL} SOL`); 325 | console.log(`Wallet ${it}: Owns ${percentSupply.toFixed(4)}% of total supply\n`); 326 | 327 | buys.push({ pubkey: keypair.publicKey, solAmount: Number(solInput), tokenAmount: tokensToBuy, percentSupply }); 328 | 329 | initialRealSolReserves += e.toNumber(); 330 | initialRealTokenReserves -= tokensBought; 331 | initialVirtualTokenReserves -= tokensBought; 332 | totalTokensBought += tokensBought; 333 | } 334 | 335 | console.log("Final real sol reserves: ", initialRealSolReserves / LAMPORTS_PER_SOL); 336 | console.log("Final real token reserves: ", initialRealTokenReserves / tokenDecimals); 337 | console.log("Final virtual token reserves: ", initialVirtualTokenReserves / tokenDecimals); 338 | console.log("Total tokens bought: ", totalTokensBought / tokenDecimals); 339 | console.log("Total % of tokens bought: ", (totalTokensBought / tokenTotalSupply) * 100); 340 | console.log(); // \n 341 | 342 | const confirm = prompt("Do you want to use these buys? (yes/no): ").toLowerCase(); 343 | if (confirm === "yes") { 344 | writeBuysToFile(buys); 345 | } else { 346 | console.log("Simulation aborted. Restarting..."); 347 | simulateAndWriteBuys(); // Restart the simulation 348 | } 349 | } 350 | 351 | function writeBuysToFile(buys: Buy[]) { 352 | let existingData: any = {}; 353 | 354 | if (fs.existsSync(keyInfoPath)) { 355 | existingData = JSON.parse(fs.readFileSync(keyInfoPath, "utf-8")); 356 | } 357 | 358 | // Convert buys array to an object keyed by public key 359 | const buysObj = buys.reduce((acc, buy) => { 360 | acc[buy.pubkey.toString()] = { 361 | solAmount: buy.solAmount.toString(), 362 | tokenAmount: buy.tokenAmount.toString(), 363 | percentSupply: buy.percentSupply, 364 | }; 365 | return acc; 366 | }, existingData); // Initialize with existing data 367 | 368 | // Write updated data to file 369 | fs.writeFileSync(keyInfoPath, JSON.stringify(buysObj, null, 2), "utf8"); 370 | console.log("Buys have been successfully saved to keyinfo.json"); 371 | } 372 | 373 | export async function sender() { 374 | let running = true; 375 | 376 | while (running) { 377 | console.log("\nBuyer UI:"); 378 | console.log("1. Create LUT"); 379 | console.log("2. Extend LUT Bundle"); 380 | console.log("3. Simulate Buys"); 381 | console.log("4. Send Simulation SOL Bundle"); 382 | console.log("5. Reclaim Buyers Sol"); 383 | 384 | const answer = prompt("Choose an option or 'exit': "); // Use prompt-sync for user input 385 | 386 | switch (answer) { 387 | case "1": 388 | await createLUT(); 389 | break; 390 | case "2": 391 | await extendLUT(); 392 | break; 393 | case "3": 394 | await simulateAndWriteBuys(); 395 | break; 396 | case "4": 397 | await generateATAandSOL(); 398 | break; 399 | case "5": 400 | await createReturns(); 401 | break; 402 | case "exit": 403 | running = false; 404 | break; 405 | default: 406 | console.log("Invalid option, please choose again."); 407 | } 408 | } 409 | 410 | console.log("Exiting..."); 411 | } 412 | -------------------------------------------------------------------------------- /pumpfun-IDL.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "name": "pump", 4 | "instructions": [ 5 | { 6 | "name": "initialize", 7 | "docs": ["Creates the global state."], 8 | "accounts": [ 9 | { 10 | "name": "global", 11 | "isMut": true, 12 | "isSigner": false 13 | }, 14 | { 15 | "name": "user", 16 | "isMut": true, 17 | "isSigner": true 18 | }, 19 | { 20 | "name": "systemProgram", 21 | "isMut": false, 22 | "isSigner": false 23 | } 24 | ], 25 | "args": [] 26 | }, 27 | { 28 | "name": "setParams", 29 | "docs": ["Sets the global state parameters."], 30 | "accounts": [ 31 | { 32 | "name": "global", 33 | "isMut": true, 34 | "isSigner": false 35 | }, 36 | { 37 | "name": "user", 38 | "isMut": true, 39 | "isSigner": true 40 | }, 41 | { 42 | "name": "systemProgram", 43 | "isMut": false, 44 | "isSigner": false 45 | }, 46 | { 47 | "name": "eventAuthority", 48 | "isMut": false, 49 | "isSigner": false 50 | }, 51 | { 52 | "name": "program", 53 | "isMut": false, 54 | "isSigner": false 55 | } 56 | ], 57 | "args": [ 58 | { 59 | "name": "feeRecipient", 60 | "type": "publicKey" 61 | }, 62 | { 63 | "name": "initialVirtualTokenReserves", 64 | "type": "u64" 65 | }, 66 | { 67 | "name": "initialVirtualSolReserves", 68 | "type": "u64" 69 | }, 70 | { 71 | "name": "initialRealTokenReserves", 72 | "type": "u64" 73 | }, 74 | { 75 | "name": "tokenTotalSupply", 76 | "type": "u64" 77 | }, 78 | { 79 | "name": "feeBasisPoints", 80 | "type": "u64" 81 | } 82 | ] 83 | }, 84 | { 85 | "name": "create", 86 | "docs": ["Creates a new coin and bonding curve."], 87 | "accounts": [ 88 | { 89 | "name": "mint", 90 | "isMut": true, 91 | "isSigner": true 92 | }, 93 | { 94 | "name": "mintAuthority", 95 | "isMut": false, 96 | "isSigner": false 97 | }, 98 | { 99 | "name": "bondingCurve", 100 | "isMut": true, 101 | "isSigner": false 102 | }, 103 | { 104 | "name": "associatedBondingCurve", 105 | "isMut": true, 106 | "isSigner": false 107 | }, 108 | { 109 | "name": "global", 110 | "isMut": false, 111 | "isSigner": false 112 | }, 113 | { 114 | "name": "mplTokenMetadata", 115 | "isMut": false, 116 | "isSigner": false 117 | }, 118 | { 119 | "name": "metadata", 120 | "isMut": true, 121 | "isSigner": false 122 | }, 123 | { 124 | "name": "user", 125 | "isMut": true, 126 | "isSigner": true 127 | }, 128 | { 129 | "name": "systemProgram", 130 | "isMut": false, 131 | "isSigner": false 132 | }, 133 | { 134 | "name": "tokenProgram", 135 | "isMut": false, 136 | "isSigner": false 137 | }, 138 | { 139 | "name": "associatedTokenProgram", 140 | "isMut": false, 141 | "isSigner": false 142 | }, 143 | { 144 | "name": "rent", 145 | "isMut": false, 146 | "isSigner": false 147 | }, 148 | { 149 | "name": "eventAuthority", 150 | "isMut": false, 151 | "isSigner": false 152 | }, 153 | { 154 | "name": "program", 155 | "isMut": false, 156 | "isSigner": false 157 | } 158 | ], 159 | "args": [ 160 | { 161 | "name": "name", 162 | "type": "string" 163 | }, 164 | { 165 | "name": "symbol", 166 | "type": "string" 167 | }, 168 | { 169 | "name": "uri", 170 | "type": "string" 171 | } 172 | ] 173 | }, 174 | { 175 | "name": "buy", 176 | "docs": ["Buys tokens from a bonding curve."], 177 | "accounts": [ 178 | { 179 | "name": "global", 180 | "isMut": false, 181 | "isSigner": false 182 | }, 183 | { 184 | "name": "feeRecipient", 185 | "isMut": true, 186 | "isSigner": false 187 | }, 188 | { 189 | "name": "mint", 190 | "isMut": false, 191 | "isSigner": false 192 | }, 193 | { 194 | "name": "bondingCurve", 195 | "isMut": true, 196 | "isSigner": false 197 | }, 198 | { 199 | "name": "associatedBondingCurve", 200 | "isMut": true, 201 | "isSigner": false 202 | }, 203 | { 204 | "name": "associatedUser", 205 | "isMut": true, 206 | "isSigner": false 207 | }, 208 | { 209 | "name": "user", 210 | "isMut": true, 211 | "isSigner": true 212 | }, 213 | { 214 | "name": "systemProgram", 215 | "isMut": false, 216 | "isSigner": false 217 | }, 218 | { 219 | "name": "tokenProgram", 220 | "isMut": false, 221 | "isSigner": false 222 | }, 223 | { 224 | "name": "rent", 225 | "isMut": false, 226 | "isSigner": false 227 | }, 228 | { 229 | "name": "eventAuthority", 230 | "isMut": false, 231 | "isSigner": false 232 | }, 233 | { 234 | "name": "program", 235 | "isMut": false, 236 | "isSigner": false 237 | } 238 | ], 239 | "args": [ 240 | { 241 | "name": "amount", 242 | "type": "u64" 243 | }, 244 | { 245 | "name": "maxSolCost", 246 | "type": "u64" 247 | } 248 | ] 249 | }, 250 | { 251 | "name": "sell", 252 | "docs": ["Sells tokens into a bonding curve."], 253 | "accounts": [ 254 | { 255 | "name": "global", 256 | "isMut": false, 257 | "isSigner": false 258 | }, 259 | { 260 | "name": "feeRecipient", 261 | "isMut": true, 262 | "isSigner": false 263 | }, 264 | { 265 | "name": "mint", 266 | "isMut": false, 267 | "isSigner": false 268 | }, 269 | { 270 | "name": "bondingCurve", 271 | "isMut": true, 272 | "isSigner": false 273 | }, 274 | { 275 | "name": "associatedBondingCurve", 276 | "isMut": true, 277 | "isSigner": false 278 | }, 279 | { 280 | "name": "associatedUser", 281 | "isMut": true, 282 | "isSigner": false 283 | }, 284 | { 285 | "name": "user", 286 | "isMut": true, 287 | "isSigner": true 288 | }, 289 | { 290 | "name": "systemProgram", 291 | "isMut": false, 292 | "isSigner": false 293 | }, 294 | { 295 | "name": "associatedTokenProgram", 296 | "isMut": false, 297 | "isSigner": false 298 | }, 299 | { 300 | "name": "tokenProgram", 301 | "isMut": false, 302 | "isSigner": false 303 | }, 304 | { 305 | "name": "eventAuthority", 306 | "isMut": false, 307 | "isSigner": false 308 | }, 309 | { 310 | "name": "program", 311 | "isMut": false, 312 | "isSigner": false 313 | } 314 | ], 315 | "args": [ 316 | { 317 | "name": "amount", 318 | "type": "u64" 319 | }, 320 | { 321 | "name": "minSolOutput", 322 | "type": "u64" 323 | } 324 | ] 325 | }, 326 | { 327 | "name": "withdraw", 328 | "docs": [ 329 | "Allows the admin to withdraw liquidity for a migration once the bonding curve completes" 330 | ], 331 | "accounts": [ 332 | { 333 | "name": "global", 334 | "isMut": false, 335 | "isSigner": false 336 | }, 337 | { 338 | "name": "mint", 339 | "isMut": false, 340 | "isSigner": false 341 | }, 342 | { 343 | "name": "bondingCurve", 344 | "isMut": true, 345 | "isSigner": false 346 | }, 347 | { 348 | "name": "associatedBondingCurve", 349 | "isMut": true, 350 | "isSigner": false 351 | }, 352 | { 353 | "name": "associatedUser", 354 | "isMut": true, 355 | "isSigner": false 356 | }, 357 | { 358 | "name": "user", 359 | "isMut": true, 360 | "isSigner": true 361 | }, 362 | { 363 | "name": "systemProgram", 364 | "isMut": false, 365 | "isSigner": false 366 | }, 367 | { 368 | "name": "tokenProgram", 369 | "isMut": false, 370 | "isSigner": false 371 | }, 372 | { 373 | "name": "rent", 374 | "isMut": false, 375 | "isSigner": false 376 | }, 377 | { 378 | "name": "eventAuthority", 379 | "isMut": false, 380 | "isSigner": false 381 | }, 382 | { 383 | "name": "program", 384 | "isMut": false, 385 | "isSigner": false 386 | } 387 | ], 388 | "args": [] 389 | } 390 | ], 391 | "accounts": [ 392 | { 393 | "name": "Global", 394 | "type": { 395 | "kind": "struct", 396 | "fields": [ 397 | { 398 | "name": "initialized", 399 | "type": "bool" 400 | }, 401 | { 402 | "name": "authority", 403 | "type": "publicKey" 404 | }, 405 | { 406 | "name": "feeRecipient", 407 | "type": "publicKey" 408 | }, 409 | { 410 | "name": "initialVirtualTokenReserves", 411 | "type": "u64" 412 | }, 413 | { 414 | "name": "initialVirtualSolReserves", 415 | "type": "u64" 416 | }, 417 | { 418 | "name": "initialRealTokenReserves", 419 | "type": "u64" 420 | }, 421 | { 422 | "name": "tokenTotalSupply", 423 | "type": "u64" 424 | }, 425 | { 426 | "name": "feeBasisPoints", 427 | "type": "u64" 428 | } 429 | ] 430 | } 431 | }, 432 | { 433 | "name": "BondingCurve", 434 | "type": { 435 | "kind": "struct", 436 | "fields": [ 437 | { 438 | "name": "virtualTokenReserves", 439 | "type": "u64" 440 | }, 441 | { 442 | "name": "virtualSolReserves", 443 | "type": "u64" 444 | }, 445 | { 446 | "name": "realTokenReserves", 447 | "type": "u64" 448 | }, 449 | { 450 | "name": "realSolReserves", 451 | "type": "u64" 452 | }, 453 | { 454 | "name": "tokenTotalSupply", 455 | "type": "u64" 456 | }, 457 | { 458 | "name": "complete", 459 | "type": "bool" 460 | } 461 | ] 462 | } 463 | } 464 | ], 465 | "events": [ 466 | { 467 | "name": "CreateEvent", 468 | "fields": [ 469 | { 470 | "name": "name", 471 | "type": "string", 472 | "index": false 473 | }, 474 | { 475 | "name": "symbol", 476 | "type": "string", 477 | "index": false 478 | }, 479 | { 480 | "name": "uri", 481 | "type": "string", 482 | "index": false 483 | }, 484 | { 485 | "name": "mint", 486 | "type": "publicKey", 487 | "index": false 488 | }, 489 | { 490 | "name": "bondingCurve", 491 | "type": "publicKey", 492 | "index": false 493 | }, 494 | { 495 | "name": "user", 496 | "type": "publicKey", 497 | "index": false 498 | } 499 | ] 500 | }, 501 | { 502 | "name": "TradeEvent", 503 | "fields": [ 504 | { 505 | "name": "mint", 506 | "type": "publicKey", 507 | "index": false 508 | }, 509 | { 510 | "name": "solAmount", 511 | "type": "u64", 512 | "index": false 513 | }, 514 | { 515 | "name": "tokenAmount", 516 | "type": "u64", 517 | "index": false 518 | }, 519 | { 520 | "name": "isBuy", 521 | "type": "bool", 522 | "index": false 523 | }, 524 | { 525 | "name": "user", 526 | "type": "publicKey", 527 | "index": false 528 | }, 529 | { 530 | "name": "timestamp", 531 | "type": "i64", 532 | "index": false 533 | }, 534 | { 535 | "name": "virtualSolReserves", 536 | "type": "u64", 537 | "index": false 538 | }, 539 | { 540 | "name": "virtualTokenReserves", 541 | "type": "u64", 542 | "index": false 543 | } 544 | ] 545 | }, 546 | { 547 | "name": "CompleteEvent", 548 | "fields": [ 549 | { 550 | "name": "user", 551 | "type": "publicKey", 552 | "index": false 553 | }, 554 | { 555 | "name": "mint", 556 | "type": "publicKey", 557 | "index": false 558 | }, 559 | { 560 | "name": "bondingCurve", 561 | "type": "publicKey", 562 | "index": false 563 | }, 564 | { 565 | "name": "timestamp", 566 | "type": "i64", 567 | "index": false 568 | } 569 | ] 570 | }, 571 | { 572 | "name": "SetParamsEvent", 573 | "fields": [ 574 | { 575 | "name": "feeRecipient", 576 | "type": "publicKey", 577 | "index": false 578 | }, 579 | { 580 | "name": "initialVirtualTokenReserves", 581 | "type": "u64", 582 | "index": false 583 | }, 584 | { 585 | "name": "initialVirtualSolReserves", 586 | "type": "u64", 587 | "index": false 588 | }, 589 | { 590 | "name": "initialRealTokenReserves", 591 | "type": "u64", 592 | "index": false 593 | }, 594 | { 595 | "name": "tokenTotalSupply", 596 | "type": "u64", 597 | "index": false 598 | }, 599 | { 600 | "name": "feeBasisPoints", 601 | "type": "u64", 602 | "index": false 603 | } 604 | ] 605 | } 606 | ], 607 | "errors": [ 608 | { 609 | "code": 6000, 610 | "name": "NotAuthorized", 611 | "msg": "The given account is not authorized to execute this instruction." 612 | }, 613 | { 614 | "code": 6001, 615 | "name": "AlreadyInitialized", 616 | "msg": "The program is already initialized." 617 | }, 618 | { 619 | "code": 6002, 620 | "name": "TooMuchSolRequired", 621 | "msg": "slippage: Too much SOL required to buy the given amount of tokens." 622 | }, 623 | { 624 | "code": 6003, 625 | "name": "TooLittleSolReceived", 626 | "msg": "slippage: Too little SOL received to sell the given amount of tokens." 627 | }, 628 | { 629 | "code": 6004, 630 | "name": "MintDoesNotMatchBondingCurve", 631 | "msg": "The mint does not match the bonding curve." 632 | }, 633 | { 634 | "code": 6005, 635 | "name": "BondingCurveComplete", 636 | "msg": "The bonding curve has completed and liquidity migrated to raydium." 637 | }, 638 | { 639 | "code": 6006, 640 | "name": "BondingCurveNotComplete", 641 | "msg": "The bonding curve has not completed." 642 | }, 643 | { 644 | "code": 6007, 645 | "name": "NotInitialized", 646 | "msg": "The program is not initialized." 647 | } 648 | ], 649 | "metadata": { 650 | "address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" 651 | } 652 | } 653 | --------------------------------------------------------------------------------