├── .changeset ├── README.md ├── config.json └── fixedexports.md_bkp ├── .env.example ├── .github └── workflows │ ├── main.yml │ └── publish.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode └── settings.json ├── CHANGELOG.md ├── README.MD ├── dist ├── index.cjs ├── index.d.cts ├── index.d.mts ├── index.d.ts ├── index.js └── index.mjs ├── index.js ├── jest.config.ts ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── src ├── index.ts └── utils │ ├── create-transaction.ts │ ├── get-token-data.ts │ ├── helper.ts │ └── send-transaction.ts ├── test └── checker │ └── metadata-checker.test.ts ├── tsconfig.build.json └── tsconfig.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /.changeset/fixedexports.md_bkp: -------------------------------------------------------------------------------- 1 | --- 2 | '@degenfrends/solana-pumpfun-trader': patch 3 | --- 4 | 5 | ## @degenfrends/solana-pumpfun-trader: Discord fixes 6 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | RPC_URL="" 2 | PRIVATE_KEY="" -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: pnpm/action-setup@v2 13 | with: 14 | version: 9 15 | - uses: actions/setup-node@v3 16 | with: 17 | node-version: 20.x 18 | cache: 'pnpm' 19 | 20 | - run: pnpm install --frozen-lockfile 21 | - run: pnpm run lint && pnpm run build 22 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | on: 3 | workflow_run: 4 | workflows: [CI] 5 | branches: [main] 6 | types: [completed] 7 | 8 | concurrency: ${{ github.workflow }}-${{ github.ref }} 9 | 10 | permissions: 11 | contents: write 12 | pull-requests: write 13 | 14 | jobs: 15 | publish: 16 | if: ${{ github.event.workflow_run.conclusion == 'success' }} 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | with: 21 | node-version: 20.x 22 | - uses: pnpm/action-setup@v2 23 | with: 24 | version: 9 25 | node-version: 20.x 26 | - uses: actions/setup-node@v3 27 | with: 28 | node-version: 20.x 29 | cache: 'pnpm' 30 | 31 | - run: pnpm install --frozen-lockfile 32 | - name: Create Release Pull Request or Publish 33 | id: changesets 34 | uses: changesets/action@v1 35 | with: 36 | publish: pnpm run release 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules/ 5 | docs/ 6 | /.pnp 7 | .pnp.js 8 | all_pools.json 9 | # testing 10 | coverage/ 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | var/* 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | 24 | # Custom 25 | .vstags 26 | **.pem 27 | **.crt 28 | **.bak -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "printWidth": 150, 4 | "proseWrap": "always", 5 | "tabWidth": 4, 6 | "useTabs": false, 7 | "trailingComma": "none", 8 | "bracketSpacing": true, 9 | "jsxBracketSameLine": false, 10 | "semi": true 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.bracketPairColorization.enabled": true, 4 | "editor.formatOnSave": true, 5 | "editor.formatOnPaste": true 6 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @degenfrends/solana-pumpfun-trader 2 | 3 | ## 0.0.16 4 | 5 | ### Patch Changes 6 | 7 | - 36a568f: ## @degenfrends/solana-pumpfun-trader: Discord fixes 8 | 9 | ## 0.0.15 10 | 11 | ### Patch Changes 12 | 13 | - af61422: ## @degenfrends/solana-pumpfun-trader: Discord fixes 14 | 15 | ## 0.0.14 16 | 17 | ### Patch Changes 18 | 19 | - 5b5fabf: ## @degenfrends/solana-pumpfun-trader: Discord fixes 20 | 21 | ## 0.0.13 22 | 23 | ### Patch Changes 24 | 25 | - 0855477: ## @degenfrends/solana-pumpfun-trader: Discord fixes 26 | 27 | ## 0.0.12 28 | 29 | ### Patch Changes 30 | 31 | - 3a7a3f0: ## @degenfrends/solana-pumpfun-trader: Discord fixes 32 | 33 | ## 0.0.11 34 | 35 | ### Patch Changes 36 | 37 | - a1e41a9: ## @degenfrends/solana-pumpfun-trader: Discord fixes 38 | 39 | ## 0.0.10 40 | 41 | ### Patch Changes 42 | 43 | - 51b6b03: ## @degenfrends/solana-pumpfun-trader: Discord fixes 44 | 45 | ## 0.0.9 46 | 47 | ### Patch Changes 48 | 49 | - 027bd3f: ## @degenfrends/solana-pumpfun-trader: Discord fixes 50 | 51 | ## 0.0.8 52 | 53 | ### Patch Changes 54 | 55 | - 6490dc7: ## @degenfrends/solana-pumpfun-trader: Discord fixes 56 | 57 | ## 0.0.7 58 | 59 | ### Patch Changes 60 | 61 | - ed7f838: ## @degenfrends/solana-pumpfun-trader: Discord fixes 62 | 63 | ## 0.0.6 64 | 65 | ### Patch Changes 66 | 67 | - a228476: ## @degenfrends/solana-pumpfun-trader: Discord fixes 68 | 69 | ## 0.0.5 70 | 71 | ### Patch Changes 72 | 73 | - a5dad60: ## @degenfrends/solana-pumpfun-trader: Fixed method stub 74 | 75 | ## 0.0.4 76 | 77 | ### Patch Changes 78 | 79 | - 3163b90: ## @degenfrends/solana-pumpfun-trader: Fixed method stub 80 | - 3163b90: ## @degenfrends/solana-pumpfun-trader: Fixed method stub 81 | 82 | ## 0.0.3 83 | 84 | ### Patch Changes 85 | 86 | - 0f17864: ## @degenfrends/solana-pumpfun-trader: initial version 87 | 88 | ## 0.0.2 89 | 90 | ### Patch Changes 91 | 92 | - 246b3ed: ## @degenfrends/solana-pumpfun-trader: initial version 93 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Solana Pump.fun Trader 2 | 3 | ![Static Badge](https://img.shields.io/badge/degen-100%25-pink) 4 | ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/degenfrends/solana-pumpfun-trader/publish.yml) 5 | ![NPM License](https://img.shields.io/npm/l/%40degenfrends%2Fsolana-pumpfun-trader) 6 | ![NPM Version](https://img.shields.io/npm/v/@degenfrends/solana-pumpfun-trader) 7 | ![NPM Downloads](https://img.shields.io/npm/dw/@degenfrends/solana-pumpfun-trader) 8 | ![GitHub Repo stars](https://img.shields.io/github/stars/degenfrends/solana-pumpfun-trader) 9 | ![X (formerly Twitter) URL](https://img.shields.io/twitter/url?url=https%3A%2F%2Fx.com%2Fkryptobrah&label=Twitter%2FX) 10 | 11 | ## This project is more or less a copy of https://github.com/bilix-software/solana-pump-fun. I made a npm package out of it and resturctured/refactored the code a little bit. 12 | 13 | [Join the discord if you are looking for fellow degen developers!](https://discord.gg/HUVAbet2Dp) 14 | 15 | > [!CAUTION] 16 | > Do not use your main wallet with this script! Always use a trading wallet with your trading budget. Don't be lazy! Create a wallet for this now! 17 | 18 | Solan Pump.fun Trader is a library to execute buy and sell orders for SPL tokens that were created on pump.fun. 19 | 20 | ## Installation 21 | 22 | Just install it with npm or yarn or whatever. 23 | 24 | ```bash 25 | npm install "@degenfrends/solana-pumpfun-trader" 26 | ``` 27 | 28 | ## Configuration & Usage 29 | 30 | ```typescript 31 | import PumpFunTrader from '@degenfrends/solana-pumpfun-trader'; 32 | 33 | const pumpFunTrader = new PumpFunTrader(); 34 | this.pumpFunTrader.setSolanaRpcUrl('https://yoursolanarpc.com'); 35 | 36 | await this.pumpFunTrader.buy( 37 | privateKey: '12123423434234', // your private key 38 | tokenAddress: 'ejddjsldjsdlks', // the address of the token you want to buy 39 | amount: 0.5, // amount in solana 40 | priorityFee: 0, // (optional) you should increase the priority fee when you want to make sure that transactions are always succesfull. 41 | slippage: 0.25, // (optional) 0.25 equals 25% slippage. 42 | isSimulation: false // (optional) 43 | ); 44 | 45 | await this.pumpFunTrader.sell( 46 | privateKey: '12123423434234', // your private key 47 | tokenAddress: 'ejddjsldjsdlks', // the address of the token you want to sell 48 | tokenBalance: 10000000 // the amounts of token you want to sell, you need to multiply the amount you want to sell by 1000000 since pump.fun tokens have 6 digits, 49 | priorityFee: 0, // (optional) you should increase the priority fee when you want to make sure that transactions are always succesfull. 50 | slippage: 0.25, // (optional) 0.25 equals 25% slippage. 51 | isSimulation: false // (optional) 52 | ); 53 | ``` 54 | 55 | There are functions to build sell and buy transaction instructions too, which you can use to bundle transactions. 56 | 57 | If you have any questions or suggestions, [join the discord!](https://discord.gg/HUVAbet2Dp) -------------------------------------------------------------------------------- /dist/index.cjs: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __create = Object.create; 3 | var __defProp = Object.defineProperty; 4 | var __getOwnPropDesc = Object.getOwnPropertyDescriptor; 5 | var __getOwnPropNames = Object.getOwnPropertyNames; 6 | var __getProtoOf = Object.getPrototypeOf; 7 | var __hasOwnProp = Object.prototype.hasOwnProperty; 8 | var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); 9 | var __export = (target, all) => { 10 | for (var name in all) 11 | __defProp(target, name, { get: all[name], enumerable: true }); 12 | }; 13 | var __copyProps = (to, from, except, desc) => { 14 | if (from && typeof from === "object" || typeof from === "function") { 15 | for (let key of __getOwnPropNames(from)) 16 | if (!__hasOwnProp.call(to, key) && key !== except) 17 | __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); 18 | } 19 | return to; 20 | }; 21 | var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( 22 | // If the importer is in node compatibility mode or this is not an ESM 23 | // file that has been converted to a CommonJS file using a Babel- 24 | // compatible transform (i.e. "__esModule" has not been set), then set 25 | // "default" to the CommonJS "module.exports" for node compatibility. 26 | isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, 27 | mod 28 | )); 29 | var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); 30 | 31 | // src/index.ts 32 | var src_exports = {}; 33 | __export(src_exports, { 34 | ASSOC_TOKEN_ACC_PROG: () => ASSOC_TOKEN_ACC_PROG, 35 | FEE_RECIPIENT: () => FEE_RECIPIENT, 36 | GLOBAL: () => GLOBAL, 37 | PUMP_FUN_ACCOUNT: () => PUMP_FUN_ACCOUNT, 38 | PUMP_FUN_PROGRAM: () => PUMP_FUN_PROGRAM, 39 | RENT: () => RENT, 40 | SYSTEM_PROGRAM_ID: () => SYSTEM_PROGRAM_ID, 41 | TOKEN_PROGRAM_ID: () => TOKEN_PROGRAM_ID, 42 | default: () => PumpFunTrader 43 | }); 44 | module.exports = __toCommonJS(src_exports); 45 | var import_web34 = require("@solana/web3.js"); 46 | var import_spl_token = require("@solana/spl-token"); 47 | 48 | // src/utils/create-transaction.ts 49 | var import_web3 = require("@solana/web3.js"); 50 | async function createTransaction(connection, instructions, wallet, priorityFee = 0) { 51 | const modifyComputeUnits = import_web3.ComputeBudgetProgram.setComputeUnitLimit({ 52 | units: 14e5 53 | }); 54 | const transaction = new import_web3.Transaction().add(modifyComputeUnits); 55 | if (priorityFee > 0) { 56 | const microLamports = priorityFee * 1e9; 57 | const addPriorityFee = import_web3.ComputeBudgetProgram.setComputeUnitPrice({ 58 | microLamports 59 | }); 60 | transaction.add(addPriorityFee); 61 | } 62 | transaction.add(...instructions); 63 | transaction.feePayer = wallet; 64 | transaction.recentBlockhash = (await connection.getRecentBlockhash()).blockhash; 65 | return transaction; 66 | } 67 | __name(createTransaction, "createTransaction"); 68 | 69 | // src/utils/send-transaction.ts 70 | var import_web32 = require("@solana/web3.js"); 71 | async function sendTransaction(connection, transaction, signers) { 72 | try { 73 | const signature = await (0, import_web32.sendAndConfirmTransaction)(connection, transaction, signers, { 74 | skipPreflight: true, 75 | preflightCommitment: "confirmed" 76 | }); 77 | console.log("Transaction confirmed with signature:", signature); 78 | return signature; 79 | } catch (error) { 80 | console.error("Error sending transaction:", error); 81 | return null; 82 | } 83 | } 84 | __name(sendTransaction, "sendTransaction"); 85 | 86 | // src/utils/helper.ts 87 | var import_web33 = require("@solana/web3.js"); 88 | var import_bs58 = __toESM(require("bs58"), 1); 89 | async function getKeyPairFromPrivateKey(key) { 90 | return import_web33.Keypair.fromSecretKey(new Uint8Array(import_bs58.default.decode(key))); 91 | } 92 | __name(getKeyPairFromPrivateKey, "getKeyPairFromPrivateKey"); 93 | function bufferFromUInt64(value) { 94 | let buffer = Buffer.alloc(8); 95 | buffer.writeBigUInt64LE(BigInt(value)); 96 | return buffer; 97 | } 98 | __name(bufferFromUInt64, "bufferFromUInt64"); 99 | 100 | // src/utils/get-token-data.ts 101 | var import_axios = __toESM(require("axios"), 1); 102 | async function getCoinData(mintStr) { 103 | try { 104 | const url = `https://frontend-api.pump.fun/coins/${mintStr}`; 105 | const response = await import_axios.default.get(url, { 106 | headers: { 107 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0", 108 | Accept: "*/*", 109 | "Accept-Language": "en-US,en;q=0.5", 110 | "Accept-Encoding": "gzip, deflate, br", 111 | Referer: "https://www.pump.fun/", 112 | Origin: "https://www.pump.fun", 113 | Connection: "keep-alive", 114 | "Sec-Fetch-Dest": "empty", 115 | "Sec-Fetch-Mode": "cors", 116 | "Sec-Fetch-Site": "cross-site", 117 | "If-None-Match": 'W/"43a-tWaCcS4XujSi30IFlxDCJYxkMKg"' 118 | } 119 | }); 120 | if (response.status === 200) { 121 | return response.data; 122 | } else { 123 | console.error("Failed to retrieve coin data:", response.status); 124 | return null; 125 | } 126 | } catch (error) { 127 | console.error("Error fetching coin data:", error); 128 | return null; 129 | } 130 | } 131 | __name(getCoinData, "getCoinData"); 132 | 133 | // src/index.ts 134 | var GLOBAL = new import_web34.PublicKey("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"); 135 | var FEE_RECIPIENT = new import_web34.PublicKey("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM"); 136 | var TOKEN_PROGRAM_ID = new import_web34.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); 137 | var ASSOC_TOKEN_ACC_PROG = new import_web34.PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); 138 | var RENT = new import_web34.PublicKey("SysvarRent111111111111111111111111111111111"); 139 | var PUMP_FUN_PROGRAM = new import_web34.PublicKey("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"); 140 | var PUMP_FUN_ACCOUNT = new import_web34.PublicKey("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"); 141 | var SYSTEM_PROGRAM_ID = import_web34.SystemProgram.programId; 142 | var PumpFunTrader = class { 143 | static { 144 | __name(this, "PumpFunTrader"); 145 | } 146 | connection; 147 | logger; 148 | constructor(solanaRpcUrl = "https://api.mainnet-beta.solana.com", logger = console) { 149 | this.connection = new import_web34.Connection(solanaRpcUrl, "confirmed"); 150 | this.logger = logger; 151 | } 152 | setSolanaRpcUrl(solanaRpcUrl) { 153 | this.connection = new import_web34.Connection(solanaRpcUrl, "confirmed"); 154 | return this; 155 | } 156 | setLogger(logger) { 157 | this.logger = logger; 158 | return this; 159 | } 160 | async buy(privateKey, tokenAddress, amount, priorityFee = 0, slippage = 0.25, isSimulation = true) { 161 | try { 162 | const txBuilder = new import_web34.Transaction(); 163 | const instruction = await this.getBuyInstruction(privateKey, tokenAddress, amount, slippage, txBuilder); 164 | if (!instruction) { 165 | this.logger.error("Failed to retrieve buy instruction..."); 166 | return; 167 | } 168 | txBuilder.add(instruction); 169 | const walletPrivateKey = await getKeyPairFromPrivateKey(privateKey); 170 | const transaction = await createTransaction(this.connection, txBuilder.instructions, walletPrivateKey.publicKey, priorityFee); 171 | if (isSimulation == false) { 172 | const signature = await sendTransaction(this.connection, transaction, [ 173 | walletPrivateKey 174 | ]); 175 | this.logger.log("Buy transaction confirmed:", signature); 176 | } else if (isSimulation == true) { 177 | const simulatedResult = await this.connection.simulateTransaction(transaction); 178 | this.logger.log(simulatedResult); 179 | } 180 | } catch (error) { 181 | this.logger.log(error); 182 | } 183 | } 184 | async sell(privateKey, tokenAddress, tokenBalance, priorityFee = 0, slippage = 0.25, isSimulation = true) { 185 | try { 186 | const coinData = await getCoinData(tokenAddress); 187 | if (!coinData) { 188 | this.logger.error("Failed to retrieve coin data..."); 189 | return; 190 | } 191 | const payer = await getKeyPairFromPrivateKey(privateKey); 192 | const owner = payer.publicKey; 193 | const mint = new import_web34.PublicKey(tokenAddress); 194 | const txBuilder = new import_web34.Transaction(); 195 | const tokenAccountAddress = await (0, import_spl_token.getAssociatedTokenAddress)(mint, owner, false); 196 | const tokenAccountInfo = await this.connection.getAccountInfo(tokenAccountAddress); 197 | let tokenAccount; 198 | if (!tokenAccountInfo) { 199 | txBuilder.add((0, import_spl_token.createAssociatedTokenAccountInstruction)(payer.publicKey, tokenAccountAddress, payer.publicKey, mint)); 200 | tokenAccount = tokenAccountAddress; 201 | } else { 202 | tokenAccount = tokenAccountAddress; 203 | } 204 | const minSolOutput = Math.floor(tokenBalance * (1 - slippage) * coinData["virtual_sol_reserves"] / coinData["virtual_token_reserves"]); 205 | const keys = [ 206 | { 207 | pubkey: GLOBAL, 208 | isSigner: false, 209 | isWritable: false 210 | }, 211 | { 212 | pubkey: FEE_RECIPIENT, 213 | isSigner: false, 214 | isWritable: true 215 | }, 216 | { 217 | pubkey: mint, 218 | isSigner: false, 219 | isWritable: false 220 | }, 221 | { 222 | pubkey: new import_web34.PublicKey(coinData["bonding_curve"]), 223 | isSigner: false, 224 | isWritable: true 225 | }, 226 | { 227 | pubkey: new import_web34.PublicKey(coinData["associated_bonding_curve"]), 228 | isSigner: false, 229 | isWritable: true 230 | }, 231 | { 232 | pubkey: tokenAccount, 233 | isSigner: false, 234 | isWritable: true 235 | }, 236 | { 237 | pubkey: owner, 238 | isSigner: false, 239 | isWritable: true 240 | }, 241 | { 242 | pubkey: SYSTEM_PROGRAM_ID, 243 | isSigner: false, 244 | isWritable: false 245 | }, 246 | { 247 | pubkey: ASSOC_TOKEN_ACC_PROG, 248 | isSigner: false, 249 | isWritable: false 250 | }, 251 | { 252 | pubkey: TOKEN_PROGRAM_ID, 253 | isSigner: false, 254 | isWritable: false 255 | }, 256 | { 257 | pubkey: PUMP_FUN_ACCOUNT, 258 | isSigner: false, 259 | isWritable: false 260 | }, 261 | { 262 | pubkey: PUMP_FUN_PROGRAM, 263 | isSigner: false, 264 | isWritable: false 265 | } 266 | ]; 267 | const data = Buffer.concat([ 268 | bufferFromUInt64("12502976635542562355"), 269 | bufferFromUInt64(tokenBalance), 270 | bufferFromUInt64(minSolOutput) 271 | ]); 272 | const instruction = new import_web34.TransactionInstruction({ 273 | keys, 274 | programId: PUMP_FUN_PROGRAM, 275 | data 276 | }); 277 | txBuilder.add(instruction); 278 | const transaction = await createTransaction(this.connection, txBuilder.instructions, payer.publicKey, priorityFee); 279 | if (isSimulation == false) { 280 | const signature = await sendTransaction(this.connection, transaction, [ 281 | payer 282 | ]); 283 | this.logger.log("Sell transaction confirmed:", signature); 284 | } else if (isSimulation == true) { 285 | const simulatedResult = await this.connection.simulateTransaction(transaction); 286 | this.logger.log(simulatedResult); 287 | } 288 | } catch (error) { 289 | this.logger.log(error); 290 | } 291 | } 292 | async getBuyInstruction(privateKey, tokenAddress, amount, slippage = 0.25, txBuilder) { 293 | const coinData = await getCoinData(tokenAddress); 294 | if (!coinData) { 295 | this.logger.error("Failed to retrieve coin data..."); 296 | return; 297 | } 298 | const walletPrivateKey = await getKeyPairFromPrivateKey(privateKey); 299 | const owner = walletPrivateKey.publicKey; 300 | const token = new import_web34.PublicKey(tokenAddress); 301 | const tokenAccountAddress = await (0, import_spl_token.getAssociatedTokenAddress)(token, owner, false); 302 | const tokenAccountInfo = await this.connection.getAccountInfo(tokenAccountAddress); 303 | let tokenAccount; 304 | if (!tokenAccountInfo) { 305 | txBuilder.add((0, import_spl_token.createAssociatedTokenAccountInstruction)(walletPrivateKey.publicKey, tokenAccountAddress, walletPrivateKey.publicKey, token)); 306 | tokenAccount = tokenAccountAddress; 307 | } else { 308 | tokenAccount = tokenAccountAddress; 309 | } 310 | const solInLamports = amount * import_web34.LAMPORTS_PER_SOL; 311 | const tokenOut = Math.floor(solInLamports * coinData["virtual_token_reserves"] / coinData["virtual_sol_reserves"]); 312 | const amountWithSlippage = amount * (1 + slippage); 313 | const maxSolCost = Math.floor(amountWithSlippage * import_web34.LAMPORTS_PER_SOL); 314 | const ASSOCIATED_USER = tokenAccount; 315 | const USER = owner; 316 | const BONDING_CURVE = new import_web34.PublicKey(coinData["bonding_curve"]); 317 | const ASSOCIATED_BONDING_CURVE = new import_web34.PublicKey(coinData["associated_bonding_curve"]); 318 | const keys = [ 319 | { 320 | pubkey: GLOBAL, 321 | isSigner: false, 322 | isWritable: false 323 | }, 324 | { 325 | pubkey: FEE_RECIPIENT, 326 | isSigner: false, 327 | isWritable: true 328 | }, 329 | { 330 | pubkey: token, 331 | isSigner: false, 332 | isWritable: false 333 | }, 334 | { 335 | pubkey: BONDING_CURVE, 336 | isSigner: false, 337 | isWritable: true 338 | }, 339 | { 340 | pubkey: ASSOCIATED_BONDING_CURVE, 341 | isSigner: false, 342 | isWritable: true 343 | }, 344 | { 345 | pubkey: ASSOCIATED_USER, 346 | isSigner: false, 347 | isWritable: true 348 | }, 349 | { 350 | pubkey: USER, 351 | isSigner: false, 352 | isWritable: true 353 | }, 354 | { 355 | pubkey: SYSTEM_PROGRAM_ID, 356 | isSigner: false, 357 | isWritable: false 358 | }, 359 | { 360 | pubkey: TOKEN_PROGRAM_ID, 361 | isSigner: false, 362 | isWritable: false 363 | }, 364 | { 365 | pubkey: RENT, 366 | isSigner: false, 367 | isWritable: false 368 | }, 369 | { 370 | pubkey: PUMP_FUN_ACCOUNT, 371 | isSigner: false, 372 | isWritable: false 373 | }, 374 | { 375 | pubkey: PUMP_FUN_PROGRAM, 376 | isSigner: false, 377 | isWritable: false 378 | } 379 | ]; 380 | const data = Buffer.concat([ 381 | bufferFromUInt64("16927863322537952870"), 382 | bufferFromUInt64(tokenOut), 383 | bufferFromUInt64(maxSolCost) 384 | ]); 385 | const instruction = new import_web34.TransactionInstruction({ 386 | keys, 387 | programId: PUMP_FUN_PROGRAM, 388 | data 389 | }); 390 | return instruction; 391 | } 392 | }; 393 | // Annotate the CommonJS export names for ESM import in node: 394 | 0 && (module.exports = { 395 | ASSOC_TOKEN_ACC_PROG, 396 | FEE_RECIPIENT, 397 | GLOBAL, 398 | PUMP_FUN_ACCOUNT, 399 | PUMP_FUN_PROGRAM, 400 | RENT, 401 | SYSTEM_PROGRAM_ID, 402 | TOKEN_PROGRAM_ID 403 | }); 404 | -------------------------------------------------------------------------------- /dist/index.d.cts: -------------------------------------------------------------------------------- 1 | import { PublicKey, Transaction, TransactionInstruction } from '@solana/web3.js'; 2 | 3 | declare const GLOBAL: PublicKey; 4 | declare const FEE_RECIPIENT: PublicKey; 5 | declare const TOKEN_PROGRAM_ID: PublicKey; 6 | declare const ASSOC_TOKEN_ACC_PROG: PublicKey; 7 | declare const RENT: PublicKey; 8 | declare const PUMP_FUN_PROGRAM: PublicKey; 9 | declare const PUMP_FUN_ACCOUNT: PublicKey; 10 | declare const SYSTEM_PROGRAM_ID: PublicKey; 11 | declare class PumpFunTrader { 12 | private connection; 13 | private logger; 14 | constructor(solanaRpcUrl?: string, logger?: any); 15 | setSolanaRpcUrl(solanaRpcUrl: string): this; 16 | setLogger(logger: any): this; 17 | buy(privateKey: string, tokenAddress: string, amount: number, priorityFee?: number, slippage?: number, isSimulation?: boolean): Promise; 18 | sell(privateKey: string, tokenAddress: string, tokenBalance: number, priorityFee?: number, slippage?: number, isSimulation?: boolean): Promise; 19 | getBuyInstruction(privateKey: string, tokenAddress: string, amount: number, slippage: number | undefined, txBuilder: Transaction): Promise; 20 | } 21 | 22 | export { ASSOC_TOKEN_ACC_PROG, FEE_RECIPIENT, GLOBAL, PUMP_FUN_ACCOUNT, PUMP_FUN_PROGRAM, RENT, SYSTEM_PROGRAM_ID, TOKEN_PROGRAM_ID, PumpFunTrader as default }; 23 | -------------------------------------------------------------------------------- /dist/index.d.mts: -------------------------------------------------------------------------------- 1 | import { PublicKey, Transaction, TransactionInstruction } from '@solana/web3.js'; 2 | 3 | declare const GLOBAL: PublicKey; 4 | declare const FEE_RECIPIENT: PublicKey; 5 | declare const TOKEN_PROGRAM_ID: PublicKey; 6 | declare const ASSOC_TOKEN_ACC_PROG: PublicKey; 7 | declare const RENT: PublicKey; 8 | declare const PUMP_FUN_PROGRAM: PublicKey; 9 | declare const PUMP_FUN_ACCOUNT: PublicKey; 10 | declare const SYSTEM_PROGRAM_ID: PublicKey; 11 | declare class PumpFunTrader { 12 | private connection; 13 | private logger; 14 | constructor(solanaRpcUrl?: string, logger?: any); 15 | setSolanaRpcUrl(solanaRpcUrl: string): this; 16 | setLogger(logger: any): this; 17 | buy(privateKey: string, tokenAddress: string, amount: number, priorityFee?: number, slippage?: number, isSimulation?: boolean): Promise; 18 | sell(privateKey: string, tokenAddress: string, tokenBalance: number, priorityFee?: number, slippage?: number, isSimulation?: boolean): Promise; 19 | createAndSendTransaction(txBuilder: Transaction, privateKey: string, priorityFee?: number, isSimulation?: boolean): Promise; 20 | getBuyInstruction(privateKey: string, tokenAddress: string, amount: number, slippage: number | undefined, txBuilder: Transaction): Promise<{ 21 | instruction: TransactionInstruction; 22 | tokenAmount: number; 23 | } | undefined>; 24 | getSellInstruction(privateKey: string, tokenAddress: string, tokenBalance: number, slippage?: number): Promise; 25 | } 26 | 27 | export { ASSOC_TOKEN_ACC_PROG, FEE_RECIPIENT, GLOBAL, PUMP_FUN_ACCOUNT, PUMP_FUN_PROGRAM, RENT, SYSTEM_PROGRAM_ID, TOKEN_PROGRAM_ID, PumpFunTrader as default }; 28 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey, Transaction, TransactionInstruction } from '@solana/web3.js'; 2 | 3 | declare const GLOBAL: PublicKey; 4 | declare const FEE_RECIPIENT: PublicKey; 5 | declare const TOKEN_PROGRAM_ID: PublicKey; 6 | declare const ASSOC_TOKEN_ACC_PROG: PublicKey; 7 | declare const RENT: PublicKey; 8 | declare const PUMP_FUN_PROGRAM: PublicKey; 9 | declare const PUMP_FUN_ACCOUNT: PublicKey; 10 | declare const SYSTEM_PROGRAM_ID: PublicKey; 11 | declare class PumpFunTrader { 12 | private connection; 13 | private logger; 14 | constructor(solanaRpcUrl?: string, logger?: any); 15 | setSolanaRpcUrl(solanaRpcUrl: string): this; 16 | setLogger(logger: any): this; 17 | buy(privateKey: string, tokenAddress: string, amount: number, priorityFee?: number, slippage?: number, isSimulation?: boolean): Promise; 18 | sell(privateKey: string, tokenAddress: string, tokenBalance: number, priorityFee?: number, slippage?: number, isSimulation?: boolean): Promise; 19 | createAndSendTransaction(txBuilder: Transaction, privateKey: string, priorityFee?: number, isSimulation?: boolean): Promise; 20 | getBuyInstruction(privateKey: string, tokenAddress: string, amount: number, slippage: number | undefined, txBuilder: Transaction): Promise<{ 21 | instruction: TransactionInstruction; 22 | tokenAmount: number; 23 | } | undefined>; 24 | getSellInstruction(privateKey: string, tokenAddress: string, tokenBalance: number, slippage?: number): Promise; 25 | } 26 | 27 | export { ASSOC_TOKEN_ACC_PROG, FEE_RECIPIENT, GLOBAL, PUMP_FUN_ACCOUNT, PUMP_FUN_PROGRAM, RENT, SYSTEM_PROGRAM_ID, TOKEN_PROGRAM_ID, PumpFunTrader as default }; 28 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __create = Object.create; 3 | var __defProp = Object.defineProperty; 4 | var __getOwnPropDesc = Object.getOwnPropertyDescriptor; 5 | var __getOwnPropNames = Object.getOwnPropertyNames; 6 | var __getProtoOf = Object.getPrototypeOf; 7 | var __hasOwnProp = Object.prototype.hasOwnProperty; 8 | var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); 9 | var __export = (target, all) => { 10 | for (var name in all) 11 | __defProp(target, name, { get: all[name], enumerable: true }); 12 | }; 13 | var __copyProps = (to, from, except, desc) => { 14 | if (from && typeof from === "object" || typeof from === "function") { 15 | for (let key of __getOwnPropNames(from)) 16 | if (!__hasOwnProp.call(to, key) && key !== except) 17 | __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); 18 | } 19 | return to; 20 | }; 21 | var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( 22 | // If the importer is in node compatibility mode or this is not an ESM 23 | // file that has been converted to a CommonJS file using a Babel- 24 | // compatible transform (i.e. "__esModule" has not been set), then set 25 | // "default" to the CommonJS "module.exports" for node compatibility. 26 | isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, 27 | mod 28 | )); 29 | var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); 30 | 31 | // src/index.ts 32 | var src_exports = {}; 33 | __export(src_exports, { 34 | ASSOC_TOKEN_ACC_PROG: () => ASSOC_TOKEN_ACC_PROG, 35 | FEE_RECIPIENT: () => FEE_RECIPIENT, 36 | GLOBAL: () => GLOBAL, 37 | PUMP_FUN_ACCOUNT: () => PUMP_FUN_ACCOUNT, 38 | PUMP_FUN_PROGRAM: () => PUMP_FUN_PROGRAM, 39 | RENT: () => RENT, 40 | SYSTEM_PROGRAM_ID: () => SYSTEM_PROGRAM_ID, 41 | TOKEN_PROGRAM_ID: () => TOKEN_PROGRAM_ID, 42 | default: () => PumpFunTrader 43 | }); 44 | module.exports = __toCommonJS(src_exports); 45 | var import_web34 = require("@solana/web3.js"); 46 | var import_spl_token = require("@solana/spl-token"); 47 | 48 | // src/utils/create-transaction.ts 49 | var import_web3 = require("@solana/web3.js"); 50 | async function createTransaction(connection, instructions, wallet, priorityFee = 0) { 51 | const modifyComputeUnits = import_web3.ComputeBudgetProgram.setComputeUnitLimit({ 52 | units: 14e5 53 | }); 54 | const transaction = new import_web3.Transaction().add(modifyComputeUnits); 55 | if (priorityFee > 0) { 56 | const microLamports = priorityFee * 1e9; 57 | const addPriorityFee = import_web3.ComputeBudgetProgram.setComputeUnitPrice({ 58 | microLamports 59 | }); 60 | transaction.add(addPriorityFee); 61 | } 62 | transaction.add(...instructions); 63 | transaction.feePayer = wallet; 64 | transaction.recentBlockhash = (await connection.getRecentBlockhash()).blockhash; 65 | return transaction; 66 | } 67 | __name(createTransaction, "createTransaction"); 68 | 69 | // src/utils/send-transaction.ts 70 | var import_web32 = require("@solana/web3.js"); 71 | async function sendTransaction(connection, transaction, signers, logger = console) { 72 | try { 73 | const signature = await (0, import_web32.sendAndConfirmTransaction)(connection, transaction, signers, { 74 | skipPreflight: true, 75 | preflightCommitment: "confirmed" 76 | }); 77 | return signature; 78 | } catch (error) { 79 | logger.error("Error sending transaction:", error); 80 | return null; 81 | } 82 | } 83 | __name(sendTransaction, "sendTransaction"); 84 | 85 | // src/utils/helper.ts 86 | var import_web33 = require("@solana/web3.js"); 87 | var import_bs58 = __toESM(require("bs58")); 88 | async function getKeyPairFromPrivateKey(key) { 89 | return import_web33.Keypair.fromSecretKey(new Uint8Array(import_bs58.default.decode(key))); 90 | } 91 | __name(getKeyPairFromPrivateKey, "getKeyPairFromPrivateKey"); 92 | function bufferFromUInt64(value) { 93 | let buffer = Buffer.alloc(8); 94 | buffer.writeBigUInt64LE(BigInt(value)); 95 | return buffer; 96 | } 97 | __name(bufferFromUInt64, "bufferFromUInt64"); 98 | 99 | // src/utils/get-token-data.ts 100 | var import_axios = __toESM(require("axios")); 101 | async function getTokenData(mintStr, logger = console) { 102 | try { 103 | const url = `https://frontend-api.pump.fun/coins/${mintStr}`; 104 | const response = await import_axios.default.get(url, { 105 | headers: { 106 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0", 107 | Accept: "*/*", 108 | "Accept-Language": "en-US,en;q=0.5", 109 | "Accept-Encoding": "gzip, deflate, br", 110 | Referer: "https://www.pump.fun/", 111 | Origin: "https://www.pump.fun", 112 | Connection: "keep-alive", 113 | "Sec-Fetch-Dest": "empty", 114 | "Sec-Fetch-Mode": "cors", 115 | "Sec-Fetch-Site": "cross-site", 116 | "If-None-Match": 'W/"43a-tWaCcS4XujSi30IFlxDCJYxkMKg"' 117 | } 118 | }); 119 | if (response.status === 200) { 120 | return response.data; 121 | } else { 122 | logger.error("Failed to retrieve coin data:", response.status); 123 | return null; 124 | } 125 | } catch (error) { 126 | logger.error("Error fetching coin data:", error); 127 | return null; 128 | } 129 | } 130 | __name(getTokenData, "getTokenData"); 131 | 132 | // src/index.ts 133 | var import_dotenv = require("dotenv"); 134 | (0, import_dotenv.config)(); 135 | var GLOBAL = new import_web34.PublicKey("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"); 136 | var FEE_RECIPIENT = new import_web34.PublicKey("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM"); 137 | var TOKEN_PROGRAM_ID = new import_web34.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); 138 | var ASSOC_TOKEN_ACC_PROG = new import_web34.PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); 139 | var RENT = new import_web34.PublicKey("SysvarRent111111111111111111111111111111111"); 140 | var PUMP_FUN_PROGRAM = new import_web34.PublicKey("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"); 141 | var PUMP_FUN_ACCOUNT = new import_web34.PublicKey("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"); 142 | var SYSTEM_PROGRAM_ID = import_web34.SystemProgram.programId; 143 | var PumpFunTrader = class { 144 | static { 145 | __name(this, "PumpFunTrader"); 146 | } 147 | connection; 148 | logger; 149 | constructor(solanaRpcUrl = "https://api.mainnet-beta.solana.com", logger = console) { 150 | if (process.env.RPC_URL) { 151 | this.connection = new import_web34.Connection(process.env.RPC_URL, "confirmed"); 152 | } else { 153 | this.connection = new import_web34.Connection(solanaRpcUrl, "confirmed"); 154 | } 155 | this.logger = logger; 156 | } 157 | setSolanaRpcUrl(solanaRpcUrl) { 158 | this.connection = new import_web34.Connection(solanaRpcUrl, "confirmed"); 159 | return this; 160 | } 161 | setLogger(logger) { 162 | this.logger = logger; 163 | return this; 164 | } 165 | async buy(privateKey, tokenAddress, amount, priorityFee = 0, slippage = 0.25, isSimulation = true) { 166 | try { 167 | const txBuilder = new import_web34.Transaction(); 168 | const instruction = await this.getBuyInstruction(privateKey, tokenAddress, amount, slippage, txBuilder); 169 | if (!instruction?.instruction) { 170 | this.logger.error("Failed to retrieve buy instruction..."); 171 | return; 172 | } 173 | txBuilder.add(instruction.instruction); 174 | const signature = await this.createAndSendTransaction(txBuilder, privateKey, priorityFee, isSimulation); 175 | this.logger.log("Buy transaction confirmed:", signature); 176 | return signature; 177 | } catch (error) { 178 | this.logger.log(error); 179 | } 180 | } 181 | async sell(privateKey, tokenAddress, tokenBalance, priorityFee = 0, slippage = 0.25, isSimulation = true) { 182 | try { 183 | const instruction = await this.getSellInstruction(privateKey, tokenAddress, tokenBalance, slippage); 184 | const txBuilder = new import_web34.Transaction(); 185 | if (!instruction) { 186 | this.logger.error("Failed to retrieve sell instruction..."); 187 | return; 188 | } 189 | txBuilder.add(instruction); 190 | const signature = await this.createAndSendTransaction(txBuilder, privateKey, priorityFee, isSimulation); 191 | this.logger.log("Sell transaction confirmed:", signature); 192 | } catch (error) { 193 | this.logger.log(error); 194 | } 195 | } 196 | async createAndSendTransaction(txBuilder, privateKey, priorityFee = 0, isSimulation = true) { 197 | const walletPrivateKey = await getKeyPairFromPrivateKey(privateKey); 198 | const transaction = await createTransaction(this.connection, txBuilder.instructions, walletPrivateKey.publicKey, priorityFee); 199 | if (isSimulation == false) { 200 | const signature = await sendTransaction(this.connection, transaction, [ 201 | walletPrivateKey 202 | ], this.logger); 203 | this.logger.log("Transaction confirmed:", signature); 204 | return signature; 205 | } else if (isSimulation == true) { 206 | const simulatedResult = await this.connection.simulateTransaction(transaction); 207 | this.logger.log(simulatedResult); 208 | } 209 | } 210 | async getBuyInstruction(privateKey, tokenAddress, amount, slippage = 0.25, txBuilder) { 211 | const coinData = await getTokenData(tokenAddress, this.logger); 212 | if (!coinData) { 213 | this.logger.error("Failed to retrieve coin data..."); 214 | return; 215 | } 216 | const walletPrivateKey = await getKeyPairFromPrivateKey(privateKey); 217 | const owner = walletPrivateKey.publicKey; 218 | const token = new import_web34.PublicKey(tokenAddress); 219 | const tokenAccountAddress = await (0, import_spl_token.getAssociatedTokenAddress)(token, owner, false); 220 | const tokenAccountInfo = await this.connection.getAccountInfo(tokenAccountAddress); 221 | let tokenAccount; 222 | if (!tokenAccountInfo) { 223 | txBuilder.add((0, import_spl_token.createAssociatedTokenAccountInstruction)(walletPrivateKey.publicKey, tokenAccountAddress, walletPrivateKey.publicKey, token)); 224 | tokenAccount = tokenAccountAddress; 225 | } else { 226 | tokenAccount = tokenAccountAddress; 227 | } 228 | const solInLamports = amount * import_web34.LAMPORTS_PER_SOL; 229 | const tokenOut = Math.floor(solInLamports * coinData["virtual_token_reserves"] / coinData["virtual_sol_reserves"]); 230 | const amountWithSlippage = amount * (1 + slippage); 231 | const maxSolCost = Math.floor(amountWithSlippage * import_web34.LAMPORTS_PER_SOL); 232 | const ASSOCIATED_USER = tokenAccount; 233 | const USER = owner; 234 | const BONDING_CURVE = new import_web34.PublicKey(coinData["bonding_curve"]); 235 | const ASSOCIATED_BONDING_CURVE = new import_web34.PublicKey(coinData["associated_bonding_curve"]); 236 | const keys = [ 237 | { 238 | pubkey: GLOBAL, 239 | isSigner: false, 240 | isWritable: false 241 | }, 242 | { 243 | pubkey: FEE_RECIPIENT, 244 | isSigner: false, 245 | isWritable: true 246 | }, 247 | { 248 | pubkey: token, 249 | isSigner: false, 250 | isWritable: false 251 | }, 252 | { 253 | pubkey: BONDING_CURVE, 254 | isSigner: false, 255 | isWritable: true 256 | }, 257 | { 258 | pubkey: ASSOCIATED_BONDING_CURVE, 259 | isSigner: false, 260 | isWritable: true 261 | }, 262 | { 263 | pubkey: ASSOCIATED_USER, 264 | isSigner: false, 265 | isWritable: true 266 | }, 267 | { 268 | pubkey: USER, 269 | isSigner: false, 270 | isWritable: true 271 | }, 272 | { 273 | pubkey: SYSTEM_PROGRAM_ID, 274 | isSigner: false, 275 | isWritable: false 276 | }, 277 | { 278 | pubkey: TOKEN_PROGRAM_ID, 279 | isSigner: false, 280 | isWritable: false 281 | }, 282 | { 283 | pubkey: RENT, 284 | isSigner: false, 285 | isWritable: false 286 | }, 287 | { 288 | pubkey: PUMP_FUN_ACCOUNT, 289 | isSigner: false, 290 | isWritable: false 291 | }, 292 | { 293 | pubkey: PUMP_FUN_PROGRAM, 294 | isSigner: false, 295 | isWritable: false 296 | } 297 | ]; 298 | const data = Buffer.concat([ 299 | bufferFromUInt64("16927863322537952870"), 300 | bufferFromUInt64(tokenOut), 301 | bufferFromUInt64(maxSolCost) 302 | ]); 303 | const instruction = new import_web34.TransactionInstruction({ 304 | keys, 305 | programId: PUMP_FUN_PROGRAM, 306 | data 307 | }); 308 | return { 309 | instruction, 310 | tokenAmount: tokenOut 311 | }; 312 | } 313 | async getSellInstruction(privateKey, tokenAddress, tokenBalance, slippage = 0.25) { 314 | const coinData = await getTokenData(tokenAddress); 315 | if (!coinData) { 316 | this.logger.error("Failed to retrieve coin data..."); 317 | return; 318 | } 319 | const payer = await getKeyPairFromPrivateKey(privateKey); 320 | const owner = payer.publicKey; 321 | const mint = new import_web34.PublicKey(tokenAddress); 322 | const txBuilder = new import_web34.Transaction(); 323 | const tokenAccountAddress = await (0, import_spl_token.getAssociatedTokenAddress)(mint, owner, false); 324 | const tokenAccountInfo = await this.connection.getAccountInfo(tokenAccountAddress); 325 | let tokenAccount; 326 | if (!tokenAccountInfo) { 327 | txBuilder.add((0, import_spl_token.createAssociatedTokenAccountInstruction)(payer.publicKey, tokenAccountAddress, payer.publicKey, mint)); 328 | tokenAccount = tokenAccountAddress; 329 | } else { 330 | tokenAccount = tokenAccountAddress; 331 | } 332 | const minSolOutput = Math.floor(tokenBalance * (1 - slippage) * coinData["virtual_sol_reserves"] / coinData["virtual_token_reserves"]); 333 | const keys = [ 334 | { 335 | pubkey: GLOBAL, 336 | isSigner: false, 337 | isWritable: false 338 | }, 339 | { 340 | pubkey: FEE_RECIPIENT, 341 | isSigner: false, 342 | isWritable: true 343 | }, 344 | { 345 | pubkey: mint, 346 | isSigner: false, 347 | isWritable: false 348 | }, 349 | { 350 | pubkey: new import_web34.PublicKey(coinData["bonding_curve"]), 351 | isSigner: false, 352 | isWritable: true 353 | }, 354 | { 355 | pubkey: new import_web34.PublicKey(coinData["associated_bonding_curve"]), 356 | isSigner: false, 357 | isWritable: true 358 | }, 359 | { 360 | pubkey: tokenAccount, 361 | isSigner: false, 362 | isWritable: true 363 | }, 364 | { 365 | pubkey: owner, 366 | isSigner: false, 367 | isWritable: true 368 | }, 369 | { 370 | pubkey: SYSTEM_PROGRAM_ID, 371 | isSigner: false, 372 | isWritable: false 373 | }, 374 | { 375 | pubkey: ASSOC_TOKEN_ACC_PROG, 376 | isSigner: false, 377 | isWritable: false 378 | }, 379 | { 380 | pubkey: TOKEN_PROGRAM_ID, 381 | isSigner: false, 382 | isWritable: false 383 | }, 384 | { 385 | pubkey: PUMP_FUN_ACCOUNT, 386 | isSigner: false, 387 | isWritable: false 388 | }, 389 | { 390 | pubkey: PUMP_FUN_PROGRAM, 391 | isSigner: false, 392 | isWritable: false 393 | } 394 | ]; 395 | const data = Buffer.concat([ 396 | bufferFromUInt64("12502976635542562355"), 397 | bufferFromUInt64(tokenBalance), 398 | bufferFromUInt64(minSolOutput) 399 | ]); 400 | const instruction = new import_web34.TransactionInstruction({ 401 | keys, 402 | programId: PUMP_FUN_PROGRAM, 403 | data 404 | }); 405 | return instruction; 406 | } 407 | }; 408 | // Annotate the CommonJS export names for ESM import in node: 409 | 0 && (module.exports = { 410 | ASSOC_TOKEN_ACC_PROG, 411 | FEE_RECIPIENT, 412 | GLOBAL, 413 | PUMP_FUN_ACCOUNT, 414 | PUMP_FUN_PROGRAM, 415 | RENT, 416 | SYSTEM_PROGRAM_ID, 417 | TOKEN_PROGRAM_ID 418 | }); 419 | -------------------------------------------------------------------------------- /dist/index.mjs: -------------------------------------------------------------------------------- 1 | var __defProp = Object.defineProperty; 2 | var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); 3 | 4 | // src/index.ts 5 | import { Connection, LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction as Transaction2, TransactionInstruction } from "@solana/web3.js"; 6 | import { createAssociatedTokenAccountInstruction, getAssociatedTokenAddress } from "@solana/spl-token"; 7 | 8 | // src/utils/create-transaction.ts 9 | import { Transaction, ComputeBudgetProgram } from "@solana/web3.js"; 10 | async function createTransaction(connection, instructions, wallet, priorityFee = 0) { 11 | const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({ 12 | units: 14e5 13 | }); 14 | const transaction = new Transaction().add(modifyComputeUnits); 15 | if (priorityFee > 0) { 16 | const microLamports = priorityFee * 1e9; 17 | const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({ 18 | microLamports 19 | }); 20 | transaction.add(addPriorityFee); 21 | } 22 | transaction.add(...instructions); 23 | transaction.feePayer = wallet; 24 | transaction.recentBlockhash = (await connection.getRecentBlockhash()).blockhash; 25 | return transaction; 26 | } 27 | __name(createTransaction, "createTransaction"); 28 | 29 | // src/utils/send-transaction.ts 30 | import { sendAndConfirmTransaction } from "@solana/web3.js"; 31 | async function sendTransaction(connection, transaction, signers, logger = console) { 32 | try { 33 | const signature = await sendAndConfirmTransaction(connection, transaction, signers, { 34 | skipPreflight: true, 35 | preflightCommitment: "confirmed" 36 | }); 37 | return signature; 38 | } catch (error) { 39 | logger.error("Error sending transaction:", error); 40 | return null; 41 | } 42 | } 43 | __name(sendTransaction, "sendTransaction"); 44 | 45 | // src/utils/helper.ts 46 | import { Keypair } from "@solana/web3.js"; 47 | import bs58 from "bs58"; 48 | async function getKeyPairFromPrivateKey(key) { 49 | return Keypair.fromSecretKey(new Uint8Array(bs58.decode(key))); 50 | } 51 | __name(getKeyPairFromPrivateKey, "getKeyPairFromPrivateKey"); 52 | function bufferFromUInt64(value) { 53 | let buffer = Buffer.alloc(8); 54 | buffer.writeBigUInt64LE(BigInt(value)); 55 | return buffer; 56 | } 57 | __name(bufferFromUInt64, "bufferFromUInt64"); 58 | 59 | // src/utils/get-token-data.ts 60 | import axios from "axios"; 61 | async function getTokenData(mintStr, logger = console) { 62 | try { 63 | const url = `https://frontend-api.pump.fun/coins/${mintStr}`; 64 | const response = await axios.get(url, { 65 | headers: { 66 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0", 67 | Accept: "*/*", 68 | "Accept-Language": "en-US,en;q=0.5", 69 | "Accept-Encoding": "gzip, deflate, br", 70 | Referer: "https://www.pump.fun/", 71 | Origin: "https://www.pump.fun", 72 | Connection: "keep-alive", 73 | "Sec-Fetch-Dest": "empty", 74 | "Sec-Fetch-Mode": "cors", 75 | "Sec-Fetch-Site": "cross-site", 76 | "If-None-Match": 'W/"43a-tWaCcS4XujSi30IFlxDCJYxkMKg"' 77 | } 78 | }); 79 | if (response.status === 200) { 80 | return response.data; 81 | } else { 82 | logger.error("Failed to retrieve coin data:", response.status); 83 | return null; 84 | } 85 | } catch (error) { 86 | logger.error("Error fetching coin data:", error); 87 | return null; 88 | } 89 | } 90 | __name(getTokenData, "getTokenData"); 91 | 92 | // src/index.ts 93 | import { config } from "dotenv"; 94 | config(); 95 | var GLOBAL = new PublicKey("4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf"); 96 | var FEE_RECIPIENT = new PublicKey("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM"); 97 | var TOKEN_PROGRAM_ID = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); 98 | var ASSOC_TOKEN_ACC_PROG = new PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); 99 | var RENT = new PublicKey("SysvarRent111111111111111111111111111111111"); 100 | var PUMP_FUN_PROGRAM = new PublicKey("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"); 101 | var PUMP_FUN_ACCOUNT = new PublicKey("Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"); 102 | var SYSTEM_PROGRAM_ID = SystemProgram.programId; 103 | var PumpFunTrader = class { 104 | static { 105 | __name(this, "PumpFunTrader"); 106 | } 107 | connection; 108 | logger; 109 | constructor(solanaRpcUrl = "https://api.mainnet-beta.solana.com", logger = console) { 110 | if (process.env.RPC_URL) { 111 | this.connection = new Connection(process.env.RPC_URL, "confirmed"); 112 | } else { 113 | this.connection = new Connection(solanaRpcUrl, "confirmed"); 114 | } 115 | this.logger = logger; 116 | } 117 | setSolanaRpcUrl(solanaRpcUrl) { 118 | this.connection = new Connection(solanaRpcUrl, "confirmed"); 119 | return this; 120 | } 121 | setLogger(logger) { 122 | this.logger = logger; 123 | return this; 124 | } 125 | async buy(privateKey, tokenAddress, amount, priorityFee = 0, slippage = 0.25, isSimulation = true) { 126 | try { 127 | const txBuilder = new Transaction2(); 128 | const instruction = await this.getBuyInstruction(privateKey, tokenAddress, amount, slippage, txBuilder); 129 | if (!instruction?.instruction) { 130 | this.logger.error("Failed to retrieve buy instruction..."); 131 | return; 132 | } 133 | txBuilder.add(instruction.instruction); 134 | const signature = await this.createAndSendTransaction(txBuilder, privateKey, priorityFee, isSimulation); 135 | this.logger.log("Buy transaction confirmed:", signature); 136 | return signature; 137 | } catch (error) { 138 | this.logger.log(error); 139 | } 140 | } 141 | async sell(privateKey, tokenAddress, tokenBalance, priorityFee = 0, slippage = 0.25, isSimulation = true) { 142 | try { 143 | const instruction = await this.getSellInstruction(privateKey, tokenAddress, tokenBalance, slippage); 144 | const txBuilder = new Transaction2(); 145 | if (!instruction) { 146 | this.logger.error("Failed to retrieve sell instruction..."); 147 | return; 148 | } 149 | txBuilder.add(instruction); 150 | const signature = await this.createAndSendTransaction(txBuilder, privateKey, priorityFee, isSimulation); 151 | this.logger.log("Sell transaction confirmed:", signature); 152 | } catch (error) { 153 | this.logger.log(error); 154 | } 155 | } 156 | async createAndSendTransaction(txBuilder, privateKey, priorityFee = 0, isSimulation = true) { 157 | const walletPrivateKey = await getKeyPairFromPrivateKey(privateKey); 158 | const transaction = await createTransaction(this.connection, txBuilder.instructions, walletPrivateKey.publicKey, priorityFee); 159 | if (isSimulation == false) { 160 | const signature = await sendTransaction(this.connection, transaction, [ 161 | walletPrivateKey 162 | ], this.logger); 163 | this.logger.log("Transaction confirmed:", signature); 164 | return signature; 165 | } else if (isSimulation == true) { 166 | const simulatedResult = await this.connection.simulateTransaction(transaction); 167 | this.logger.log(simulatedResult); 168 | } 169 | } 170 | async getBuyInstruction(privateKey, tokenAddress, amount, slippage = 0.25, txBuilder) { 171 | const coinData = await getTokenData(tokenAddress, this.logger); 172 | if (!coinData) { 173 | this.logger.error("Failed to retrieve coin data..."); 174 | return; 175 | } 176 | const walletPrivateKey = await getKeyPairFromPrivateKey(privateKey); 177 | const owner = walletPrivateKey.publicKey; 178 | const token = new PublicKey(tokenAddress); 179 | const tokenAccountAddress = await getAssociatedTokenAddress(token, owner, false); 180 | const tokenAccountInfo = await this.connection.getAccountInfo(tokenAccountAddress); 181 | let tokenAccount; 182 | if (!tokenAccountInfo) { 183 | txBuilder.add(createAssociatedTokenAccountInstruction(walletPrivateKey.publicKey, tokenAccountAddress, walletPrivateKey.publicKey, token)); 184 | tokenAccount = tokenAccountAddress; 185 | } else { 186 | tokenAccount = tokenAccountAddress; 187 | } 188 | const solInLamports = amount * LAMPORTS_PER_SOL; 189 | const tokenOut = Math.floor(solInLamports * coinData["virtual_token_reserves"] / coinData["virtual_sol_reserves"]); 190 | const amountWithSlippage = amount * (1 + slippage); 191 | const maxSolCost = Math.floor(amountWithSlippage * LAMPORTS_PER_SOL); 192 | const ASSOCIATED_USER = tokenAccount; 193 | const USER = owner; 194 | const BONDING_CURVE = new PublicKey(coinData["bonding_curve"]); 195 | const ASSOCIATED_BONDING_CURVE = new PublicKey(coinData["associated_bonding_curve"]); 196 | const keys = [ 197 | { 198 | pubkey: GLOBAL, 199 | isSigner: false, 200 | isWritable: false 201 | }, 202 | { 203 | pubkey: FEE_RECIPIENT, 204 | isSigner: false, 205 | isWritable: true 206 | }, 207 | { 208 | pubkey: token, 209 | isSigner: false, 210 | isWritable: false 211 | }, 212 | { 213 | pubkey: BONDING_CURVE, 214 | isSigner: false, 215 | isWritable: true 216 | }, 217 | { 218 | pubkey: ASSOCIATED_BONDING_CURVE, 219 | isSigner: false, 220 | isWritable: true 221 | }, 222 | { 223 | pubkey: ASSOCIATED_USER, 224 | isSigner: false, 225 | isWritable: true 226 | }, 227 | { 228 | pubkey: USER, 229 | isSigner: false, 230 | isWritable: true 231 | }, 232 | { 233 | pubkey: SYSTEM_PROGRAM_ID, 234 | isSigner: false, 235 | isWritable: false 236 | }, 237 | { 238 | pubkey: TOKEN_PROGRAM_ID, 239 | isSigner: false, 240 | isWritable: false 241 | }, 242 | { 243 | pubkey: RENT, 244 | isSigner: false, 245 | isWritable: false 246 | }, 247 | { 248 | pubkey: PUMP_FUN_ACCOUNT, 249 | isSigner: false, 250 | isWritable: false 251 | }, 252 | { 253 | pubkey: PUMP_FUN_PROGRAM, 254 | isSigner: false, 255 | isWritable: false 256 | } 257 | ]; 258 | const data = Buffer.concat([ 259 | bufferFromUInt64("16927863322537952870"), 260 | bufferFromUInt64(tokenOut), 261 | bufferFromUInt64(maxSolCost) 262 | ]); 263 | const instruction = new TransactionInstruction({ 264 | keys, 265 | programId: PUMP_FUN_PROGRAM, 266 | data 267 | }); 268 | return { 269 | instruction, 270 | tokenAmount: tokenOut 271 | }; 272 | } 273 | async getSellInstruction(privateKey, tokenAddress, tokenBalance, slippage = 0.25) { 274 | const coinData = await getTokenData(tokenAddress); 275 | if (!coinData) { 276 | this.logger.error("Failed to retrieve coin data..."); 277 | return; 278 | } 279 | const payer = await getKeyPairFromPrivateKey(privateKey); 280 | const owner = payer.publicKey; 281 | const mint = new PublicKey(tokenAddress); 282 | const txBuilder = new Transaction2(); 283 | const tokenAccountAddress = await getAssociatedTokenAddress(mint, owner, false); 284 | const tokenAccountInfo = await this.connection.getAccountInfo(tokenAccountAddress); 285 | let tokenAccount; 286 | if (!tokenAccountInfo) { 287 | txBuilder.add(createAssociatedTokenAccountInstruction(payer.publicKey, tokenAccountAddress, payer.publicKey, mint)); 288 | tokenAccount = tokenAccountAddress; 289 | } else { 290 | tokenAccount = tokenAccountAddress; 291 | } 292 | const minSolOutput = Math.floor(tokenBalance * (1 - slippage) * coinData["virtual_sol_reserves"] / coinData["virtual_token_reserves"]); 293 | const keys = [ 294 | { 295 | pubkey: GLOBAL, 296 | isSigner: false, 297 | isWritable: false 298 | }, 299 | { 300 | pubkey: FEE_RECIPIENT, 301 | isSigner: false, 302 | isWritable: true 303 | }, 304 | { 305 | pubkey: mint, 306 | isSigner: false, 307 | isWritable: false 308 | }, 309 | { 310 | pubkey: new PublicKey(coinData["bonding_curve"]), 311 | isSigner: false, 312 | isWritable: true 313 | }, 314 | { 315 | pubkey: new PublicKey(coinData["associated_bonding_curve"]), 316 | isSigner: false, 317 | isWritable: true 318 | }, 319 | { 320 | pubkey: tokenAccount, 321 | isSigner: false, 322 | isWritable: true 323 | }, 324 | { 325 | pubkey: owner, 326 | isSigner: false, 327 | isWritable: true 328 | }, 329 | { 330 | pubkey: SYSTEM_PROGRAM_ID, 331 | isSigner: false, 332 | isWritable: false 333 | }, 334 | { 335 | pubkey: ASSOC_TOKEN_ACC_PROG, 336 | isSigner: false, 337 | isWritable: false 338 | }, 339 | { 340 | pubkey: TOKEN_PROGRAM_ID, 341 | isSigner: false, 342 | isWritable: false 343 | }, 344 | { 345 | pubkey: PUMP_FUN_ACCOUNT, 346 | isSigner: false, 347 | isWritable: false 348 | }, 349 | { 350 | pubkey: PUMP_FUN_PROGRAM, 351 | isSigner: false, 352 | isWritable: false 353 | } 354 | ]; 355 | const data = Buffer.concat([ 356 | bufferFromUInt64("12502976635542562355"), 357 | bufferFromUInt64(tokenBalance), 358 | bufferFromUInt64(minSolOutput) 359 | ]); 360 | const instruction = new TransactionInstruction({ 361 | keys, 362 | programId: PUMP_FUN_PROGRAM, 363 | data 364 | }); 365 | return instruction; 366 | } 367 | }; 368 | export { 369 | ASSOC_TOKEN_ACC_PROG, 370 | FEE_RECIPIENT, 371 | GLOBAL, 372 | PUMP_FUN_ACCOUNT, 373 | PUMP_FUN_PROGRAM, 374 | RENT, 375 | SYSTEM_PROGRAM_ID, 376 | TOKEN_PROGRAM_ID, 377 | PumpFunTrader as default 378 | }; 379 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const PumpFunTrader = require('./dist/index.js').default; 2 | require('dotenv').config(); 3 | 4 | async function test() { 5 | try { 6 | const pumpFunTrader = new PumpFunTrader(); 7 | //pumpFunTrader.setSolanaRpcUrl('https://smart-dimensional-wish.solana-mainnet.quiknode.pro/05451aac2fe8d3efcab2bfdf3e3ef5f75090c9ee/'); 8 | const buySignature = await pumpFunTrader.buy(process.env.PRIVATE_KEY, 'ANxaB4vsAKwVV6XaLfBTddZ4JQxboaGsjRnC8tdwnsYf', 0.01, 0, 0.25, false); 9 | console.log('buySignature', buySignature); 10 | 11 | const sellSignature = await pumpFunTrader.sell( 12 | process.env.PRIVATE_KEY, 13 | 'ANxaB4vsAKwVV6XaLfBTddZ4JQxboaGsjRnC8tdwnsYf', 14 | //pump.fun tokens have 6 decimals, so you need to multiply by 1,000,000 15 | 178176 * 1000000, 16 | 0, 17 | 0.25, 18 | false 19 | ); 20 | console.log('sellSignature', sellSignature); 21 | } catch (error) { 22 | console.error('error', error); 23 | } 24 | } 25 | 26 | test(); 27 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'node', 6 | roots: ['/test'], 7 | detectOpenHandles: true, 8 | maxWorkers: 1 9 | }; 10 | 11 | export default config; 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@degenfrends/solana-pumpfun-trader", 3 | "version": "0.0.16", 4 | "description": "Functions to buy and sell SPL tokens on pump.fun", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "scripts": { 9 | "build": "tsup src/index.ts --format cjs,esm --dts", 10 | "test": "jest --config jest.config.ts --detectOpenHandles --coverage --maxWorkers=1", 11 | "lint": "tsc", 12 | "release": "pnpm run build && changeset publish" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "@solana/spl-token": "^0.4.6", 18 | "@solana/web3.js": "^1.93.1", 19 | "axios": "^1.7.2", 20 | "bs58": "^5.0.0", 21 | "dotenv": "^16.4.5" 22 | }, 23 | "devDependencies": { 24 | "@changesets/cli": "^2.27.5", 25 | "@swc/core": "^1.6.5", 26 | "@types/jest": "^29.5.12", 27 | "jest": "^29.7.0", 28 | "ts-jest": "^29.1.5", 29 | "ts-node": "^10.9.2", 30 | "tsup": "^8.1.0", 31 | "typescript": "^5.5.2" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Connection, LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction, TransactionInstruction, clusterApiUrl } from '@solana/web3.js'; 2 | import { createAssociatedTokenAccountInstruction, getAssociatedTokenAddress } from '@solana/spl-token'; 3 | import { createTransaction } from './utils/create-transaction'; 4 | import { sendTransaction } from './utils/send-transaction'; 5 | import { bufferFromUInt64, getKeyPairFromPrivateKey } from './utils/helper'; 6 | import getCoinData from './utils/get-token-data'; 7 | import { config } from 'dotenv'; 8 | import getTokenData from './utils/get-token-data'; 9 | config(); 10 | export const GLOBAL = new PublicKey('4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf'); 11 | export const FEE_RECIPIENT = new PublicKey('CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM'); 12 | export const TOKEN_PROGRAM_ID = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'); 13 | export const ASSOC_TOKEN_ACC_PROG = new PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'); 14 | export const RENT = new PublicKey('SysvarRent111111111111111111111111111111111'); 15 | export const PUMP_FUN_PROGRAM = new PublicKey('6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P'); 16 | export const PUMP_FUN_ACCOUNT = new PublicKey('Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1'); 17 | export const SYSTEM_PROGRAM_ID = SystemProgram.programId; 18 | 19 | export default class PumpFunTrader { 20 | private connection: Connection; 21 | private logger: any; 22 | 23 | constructor(solanaRpcUrl: string = 'https://api.mainnet-beta.solana.com', logger: any = console) { 24 | if (process.env.RPC_URL) { 25 | this.connection = new Connection(process.env.RPC_URL, 'confirmed'); 26 | } else { 27 | this.connection = new Connection(solanaRpcUrl, 'confirmed'); 28 | } 29 | this.logger = logger; 30 | } 31 | 32 | setSolanaRpcUrl(solanaRpcUrl: string) { 33 | this.connection = new Connection(solanaRpcUrl, 'confirmed'); 34 | 35 | return this; 36 | } 37 | 38 | setLogger(logger: any) { 39 | this.logger = logger; 40 | 41 | return this; 42 | } 43 | async buy( 44 | privateKey: string, 45 | tokenAddress: string, 46 | amount: number, 47 | priorityFee: number = 0, 48 | slippage: number = 0.25, 49 | isSimulation: boolean = true 50 | ) { 51 | try { 52 | const txBuilder = new Transaction(); 53 | const instruction = await this.getBuyInstruction(privateKey, tokenAddress, amount, slippage, txBuilder); 54 | if (!instruction?.instruction) { 55 | this.logger.error('Failed to retrieve buy instruction...'); 56 | return; 57 | } 58 | txBuilder.add(instruction.instruction); 59 | const signature = await this.createAndSendTransaction(txBuilder, privateKey, priorityFee, isSimulation); 60 | this.logger.log('Buy transaction confirmed:', signature); 61 | 62 | return signature; 63 | } catch (error) { 64 | this.logger.log(error); 65 | } 66 | } 67 | 68 | async sell( 69 | privateKey: string, 70 | tokenAddress: string, 71 | tokenBalance: number, 72 | priorityFee: number = 0, 73 | slippage: number = 0.25, 74 | isSimulation: boolean = true 75 | ) { 76 | try { 77 | const instruction = await this.getSellInstruction(privateKey, tokenAddress, tokenBalance, slippage); 78 | const txBuilder = new Transaction(); 79 | if (!instruction) { 80 | this.logger.error('Failed to retrieve sell instruction...'); 81 | return; 82 | } 83 | 84 | txBuilder.add(instruction); 85 | 86 | const signature = await this.createAndSendTransaction(txBuilder, privateKey, priorityFee, isSimulation); 87 | this.logger.log('Sell transaction confirmed:', signature); 88 | } catch (error) { 89 | this.logger.log(error); 90 | } 91 | } 92 | async createAndSendTransaction(txBuilder: Transaction, privateKey: string, priorityFee: number = 0, isSimulation: boolean = true) { 93 | const walletPrivateKey = await getKeyPairFromPrivateKey(privateKey); 94 | 95 | const transaction = await createTransaction(this.connection, txBuilder.instructions, walletPrivateKey.publicKey, priorityFee); 96 | if (isSimulation == false) { 97 | const signature = await sendTransaction(this.connection, transaction, [walletPrivateKey], this.logger); 98 | this.logger.log('Transaction confirmed:', signature); 99 | return signature; 100 | } else if (isSimulation == true) { 101 | const simulatedResult = await this.connection.simulateTransaction(transaction); 102 | this.logger.log(simulatedResult); 103 | } 104 | } 105 | async getBuyInstruction(privateKey: string, tokenAddress: string, amount: number, slippage: number = 0.25, txBuilder: Transaction) { 106 | const coinData = await getTokenData(tokenAddress, this.logger); 107 | if (!coinData) { 108 | this.logger.error('Failed to retrieve coin data...'); 109 | return; 110 | } 111 | 112 | const walletPrivateKey = await getKeyPairFromPrivateKey(privateKey); 113 | const owner = walletPrivateKey.publicKey; 114 | const token = new PublicKey(tokenAddress); 115 | 116 | const tokenAccountAddress = await getAssociatedTokenAddress(token, owner, false); 117 | 118 | const tokenAccountInfo = await this.connection.getAccountInfo(tokenAccountAddress); 119 | 120 | let tokenAccount: PublicKey; 121 | if (!tokenAccountInfo) { 122 | txBuilder.add( 123 | createAssociatedTokenAccountInstruction(walletPrivateKey.publicKey, tokenAccountAddress, walletPrivateKey.publicKey, token) 124 | ); 125 | tokenAccount = tokenAccountAddress; 126 | } else { 127 | tokenAccount = tokenAccountAddress; 128 | } 129 | 130 | const solInLamports = amount * LAMPORTS_PER_SOL; 131 | const tokenOut = Math.floor((solInLamports * coinData['virtual_token_reserves']) / coinData['virtual_sol_reserves']); 132 | 133 | const amountWithSlippage = amount * (1 + slippage); 134 | const maxSolCost = Math.floor(amountWithSlippage * LAMPORTS_PER_SOL); 135 | const ASSOCIATED_USER = tokenAccount; 136 | const USER = owner; 137 | const BONDING_CURVE = new PublicKey(coinData['bonding_curve']); 138 | const ASSOCIATED_BONDING_CURVE = new PublicKey(coinData['associated_bonding_curve']); 139 | 140 | const keys = [ 141 | { pubkey: GLOBAL, isSigner: false, isWritable: false }, 142 | { pubkey: FEE_RECIPIENT, isSigner: false, isWritable: true }, 143 | { pubkey: token, isSigner: false, isWritable: false }, 144 | { pubkey: BONDING_CURVE, isSigner: false, isWritable: true }, 145 | { pubkey: ASSOCIATED_BONDING_CURVE, isSigner: false, isWritable: true }, 146 | { pubkey: ASSOCIATED_USER, isSigner: false, isWritable: true }, 147 | { pubkey: USER, isSigner: false, isWritable: true }, 148 | { pubkey: SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false }, 149 | { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, 150 | { pubkey: RENT, isSigner: false, isWritable: false }, 151 | { pubkey: PUMP_FUN_ACCOUNT, isSigner: false, isWritable: false }, 152 | { pubkey: PUMP_FUN_PROGRAM, isSigner: false, isWritable: false } 153 | ]; 154 | const data = Buffer.concat([bufferFromUInt64('16927863322537952870'), bufferFromUInt64(tokenOut), bufferFromUInt64(maxSolCost)]); 155 | 156 | const instruction = new TransactionInstruction({ 157 | keys: keys, 158 | programId: PUMP_FUN_PROGRAM, 159 | data: data 160 | }); 161 | 162 | return { instruction: instruction, tokenAmount: tokenOut }; 163 | } 164 | async getSellInstruction(privateKey: string, tokenAddress: string, tokenBalance: number, slippage: number = 0.25) { 165 | const coinData = await getCoinData(tokenAddress); 166 | if (!coinData) { 167 | this.logger.error('Failed to retrieve coin data...'); 168 | return; 169 | } 170 | 171 | const payer = await getKeyPairFromPrivateKey(privateKey); 172 | const owner = payer.publicKey; 173 | const mint = new PublicKey(tokenAddress); 174 | const txBuilder = new Transaction(); 175 | 176 | const tokenAccountAddress = await getAssociatedTokenAddress(mint, owner, false); 177 | 178 | const tokenAccountInfo = await this.connection.getAccountInfo(tokenAccountAddress); 179 | 180 | let tokenAccount: PublicKey; 181 | if (!tokenAccountInfo) { 182 | txBuilder.add(createAssociatedTokenAccountInstruction(payer.publicKey, tokenAccountAddress, payer.publicKey, mint)); 183 | tokenAccount = tokenAccountAddress; 184 | } else { 185 | tokenAccount = tokenAccountAddress; 186 | } 187 | 188 | const minSolOutput = Math.floor((tokenBalance! * (1 - slippage) * coinData['virtual_sol_reserves']) / coinData['virtual_token_reserves']); 189 | 190 | const keys = [ 191 | { pubkey: GLOBAL, isSigner: false, isWritable: false }, 192 | { pubkey: FEE_RECIPIENT, isSigner: false, isWritable: true }, 193 | { pubkey: mint, isSigner: false, isWritable: false }, 194 | { pubkey: new PublicKey(coinData['bonding_curve']), isSigner: false, isWritable: true }, 195 | { pubkey: new PublicKey(coinData['associated_bonding_curve']), isSigner: false, isWritable: true }, 196 | { pubkey: tokenAccount, isSigner: false, isWritable: true }, 197 | { pubkey: owner, isSigner: false, isWritable: true }, 198 | { pubkey: SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false }, 199 | { pubkey: ASSOC_TOKEN_ACC_PROG, isSigner: false, isWritable: false }, 200 | { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, 201 | { pubkey: PUMP_FUN_ACCOUNT, isSigner: false, isWritable: false }, 202 | { pubkey: PUMP_FUN_PROGRAM, isSigner: false, isWritable: false } 203 | ]; 204 | 205 | const data = Buffer.concat([bufferFromUInt64('12502976635542562355'), bufferFromUInt64(tokenBalance), bufferFromUInt64(minSolOutput)]); 206 | 207 | const instruction = new TransactionInstruction({ 208 | keys: keys, 209 | programId: PUMP_FUN_PROGRAM, 210 | data: data 211 | }); 212 | 213 | return instruction; 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/utils/create-transaction.ts: -------------------------------------------------------------------------------- 1 | import { Connection, TransactionInstruction, PublicKey, Transaction, ComputeBudgetProgram } from '@solana/web3.js'; 2 | 3 | export async function createTransaction( 4 | connection: Connection, 5 | instructions: TransactionInstruction[], 6 | wallet: PublicKey, 7 | priorityFee: number = 0 8 | ): Promise { 9 | const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({ 10 | units: 1400000 11 | }); 12 | 13 | const transaction = new Transaction().add(modifyComputeUnits); 14 | 15 | if (priorityFee > 0) { 16 | const microLamports = priorityFee * 1_000_000_000; // convert SOL to microLamports 17 | const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({ 18 | microLamports 19 | }); 20 | transaction.add(addPriorityFee); 21 | } 22 | 23 | transaction.add(...instructions); 24 | 25 | transaction.feePayer = wallet; 26 | transaction.recentBlockhash = (await connection.getRecentBlockhash()).blockhash; 27 | return transaction; 28 | } 29 | -------------------------------------------------------------------------------- /src/utils/get-token-data.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export default async function getTokenData(mintStr: string, logger: any = console) { 4 | try { 5 | const url = `https://frontend-api.pump.fun/coins/${mintStr}`; 6 | const response = await axios.get(url, { 7 | headers: { 8 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0', 9 | Accept: '*/*', 10 | 'Accept-Language': 'en-US,en;q=0.5', 11 | 'Accept-Encoding': 'gzip, deflate, br', 12 | Referer: 'https://www.pump.fun/', 13 | Origin: 'https://www.pump.fun', 14 | Connection: 'keep-alive', 15 | 'Sec-Fetch-Dest': 'empty', 16 | 'Sec-Fetch-Mode': 'cors', 17 | 'Sec-Fetch-Site': 'cross-site', 18 | 'If-None-Match': 'W/"43a-tWaCcS4XujSi30IFlxDCJYxkMKg"' 19 | } 20 | }); 21 | if (response.status === 200) { 22 | return response.data; 23 | } else { 24 | logger.error('Failed to retrieve coin data:', response.status); 25 | return null; 26 | } 27 | } catch (error) { 28 | logger.error('Error fetching coin data:', error); 29 | return null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/utils/helper.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from '@solana/web3.js'; 2 | import bs58 from 'bs58'; 3 | 4 | export async function getKeyPairFromPrivateKey(key: string) { 5 | return Keypair.fromSecretKey(new Uint8Array(bs58.decode(key))); 6 | } 7 | 8 | export function bufferFromUInt64(value: number | string) { 9 | let buffer = Buffer.alloc(8); 10 | buffer.writeBigUInt64LE(BigInt(value)); 11 | return buffer; 12 | } 13 | -------------------------------------------------------------------------------- /src/utils/send-transaction.ts: -------------------------------------------------------------------------------- 1 | import { Connection, Transaction, sendAndConfirmTransaction } from '@solana/web3.js'; 2 | 3 | export async function sendTransaction(connection: Connection, transaction: Transaction, signers: any[], logger: any = console) { 4 | try { 5 | const signature = await sendAndConfirmTransaction(connection, transaction, signers, { 6 | skipPreflight: true, 7 | preflightCommitment: 'confirmed' 8 | }); 9 | return signature; 10 | } catch (error) { 11 | logger.error('Error sending transaction:', error); 12 | return null; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/checker/metadata-checker.test.ts: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["test"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "CommonJS", 5 | "allowSyntheticDefaultImports": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "esModuleInterop": true, 9 | "strictPropertyInitialization": false, 10 | "outDir": "dist", 11 | "forceConsistentCasingInFileNames": true, 12 | "strict": true, 13 | "skipLibCheck": true 14 | }, 15 | "exclude": ["node_modules/"], 16 | "include": ["src/**/*.ts", "test/**/*.ts"] 17 | } 18 | --------------------------------------------------------------------------------