diff --git a/README.md b/README.md index c3704c4..7429598 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,19 @@ - Create your own Solana **_SPL tokens_** on mainnet | Pump.fun -- Swap tokens on top of Raydium, Orca, Meteora, and pump.fun +- Swap tokens on Raydium, Orca, Meteora, and pump.fun -- Predefined Jito tips and Priority fee +- land transactions faster using Jito/bloXroute -- Fastest Copy Trade Program +- Fetch the real-time lp-burn percentage, pool reserve and market cap of any liquidity pool -- **_Got everything needed for any developer to create their own trading bot_** +- fixed % tp/sl module + +- Open-Source grpc pump.fun sniper bot (0-1x seconds latency) [here](https://github.com/outsmartchad/solana-trading-cli/tree/typescript-main/src/Trading_dev/grpc-pf-sniper) + +- Open-Source grpc copy bot [here](https://github.com/outsmartchad/solana-trading-cli/tree/typescript-main/src/Trading_dev/grpc-copy-bot) + +- **_Got everything needed to create your own trading bot_** ## Credits - https://github.com/raydium-io/raydium-sdk-V2 @@ -24,8 +30,7 @@ 3. `nvm install v22.2.0` 4. `nvm use v22.2.0` 5. `npm install` -6. `node help.js `(to see commands or read cli_doc.txt file) -7. also see the command examples in examples/ +6. also see the command examples in examples/ ### Prerequisites 🚨 @@ -68,60 +73,60 @@ 1. Specify the token symbol, name, mint keypair(optional, will help u to generate), supply, decimals, path to metadata json file, path to image file, the cluster you want to use, and the file type(png, jpg, jpeg). ``` -node create --payer --symbol --token_name --mint --supply --decimals --metadata --image --cluster --priority-fee --file_type +ts-node create --payer --symbol --token_name --mint --supply --decimals --metadata --image --cluster --priority-fee --file_type ``` 2. Specify the token address, the percentage of the token you want to burn and the cluster you want to use. ``` -node burn --payer --token_address --percentage --cluster +ts-node burn --payer --token_address --percentage --cluster ``` 3. Specify the token address and the cluster you want to use. ``` -node revoke_authority --payer --mint_address --cluster --mint --freeze +ts-node revoke_authority --payer --mint_address --cluster --mint --freeze ``` 4. Specify the token address you want to query and the cluster for boosting the volume of the token. ``` -node boost_volume --token_address --payer --cluster --sol_per_order +ts-node boost_volume --token_address --payer --cluster --sol_per_order ``` 5. Specify the token address, the amount of Sol you want to swap, and the cluster you want to use. ``` -node buy --payer --token_address --sol --cluster +ts-node buy --payer --token_address --sol --cluster ``` 6. Specify the token address, the percentage of the token you want to sell, and the cluster you want to use. ``` -node sell --payer --token_address --percentage --cluster +ts-node sell --payer --token_address --percentage --cluster ``` 7. Specify the token address, the pool id(optional, will help to find the pool with the most liquidity using the given token address), the amount of Sol you want to add, and the cluster you want to use. ``` -node add_pool --payer --token_address --pool_id --sol --cluster --priority_fee +ts-node add_pool --payer --token_address --pool_id --sol --cluster --priority_fee ``` 8. Specify the token address, the percentage of the LP token you want to remove(1=1%), and the cluster you want to use. ``` -node remove_pool --payer --token_address --percentage --cluster +ts-node remove_pool --payer --token_address --percentage --cluster ``` 9. wrap your sol to wsol. ``` -node wrap_sol.js --size +ts-node wrap_sol.js --size ``` 10. unwrap your wsol to sol. ``` -node unwrap_sol.js +ts-node unwrap_sol.js ``` ### Pump.fun commands @@ -129,19 +134,19 @@ node unwrap_sol.js 9. Specify the path to your mint keypair, the amount of Sol you want to buy, the name of the token, the symbol of the token, the description of the token, the telegram link, the twitter link, the website link, and the image file path. ``` -node createAndBuy --pathToMintKeypair --sol --name --symbol --description --telegram --twitter --website --file +ts-node createAndBuy --pathToMintKeypair --sol --name --symbol --description --telegram --twitter --website --file ``` 10. Specify the token address, the sol you want to buy ``` -node buy --token_address --sol +ts-node buy --token_address --sol ``` 11. Specify the token address, the percentage of the token you want to sell ``` -node sell --token_address --percentage +ts-node sell --token_address --percentage ``` # Code Usage @@ -312,6 +317,14 @@ node sell --token_address --percentage - ``` git pull --rebase # Pull the latest changes``` - ``` git stash pop # Apply Your stashed changes``` +## Disclaimer + +This software is provided "as is," without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software. + +**Use at your own risk.** The authors take no responsibility for any harm or damage caused by the use of this software. Users are responsible for ensuring the suitability and safety of this software for their specific use cases. + +By using this software, you acknowledge that you have read, understood, and agree to this disclaimer. + ### If you think this project is useful, please give us a star🌟, it will help us a lot. ### Discord channel: https://discord.gg/hFhQeBCqWX diff --git a/package-lock.json b/package-lock.json index bfc3471..7fa840f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "solana-memecoin-cli", + "name": "solana-trading-cli", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "solana-memecoin-cli", + "name": "solana-trading-cli", "version": "1.0.0", "license": "ISC", "dependencies": { @@ -31,7 +31,8 @@ "@raydium-io/raydium-sdk-v2": "^0.1.23-alpha", "@rollup/plugin-json": "^6.1.0", "@solana/spl-token": "^0.4.0", - "@solana/web3.js": "^1.95.3", + "@solana/web3.js": "^1.89.1", + "@triton-one/yellowstone-grpc": "^0.4.0", "axios": "^1.6.8", "bigint-buffer": "^1.1.5", "bip39": "^3.1.0", @@ -42,14 +43,17 @@ "dotenv": "^16.4.5", "graphql-request": "^4.0.0", "i": "^0.3.7", + "jito-ts": "^4.0.0", "npm": "^10.5.2", "pino": "^8.18.0", "pino-pretty": "^10.3.1", "pino-std-serializers": "^6.2.2", "pumpdotfun-sdk": "^1.3.2", "random-js": "^2.1.0", - "rpc-websockets": "^7.11.2", - "ws": "^8.18.0" + "rpc-websockets": "7.10.0" + }, + "devDependencies": { + "typescript": "^5.5.4" } }, "node_modules/@aptos-labs/aptos-cli": { @@ -4847,6 +4851,15 @@ "node": ">=10" } }, + "node_modules/@triton-one/yellowstone-grpc": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@triton-one/yellowstone-grpc/-/yellowstone-grpc-0.4.0.tgz", + "integrity": "sha512-YJaX+ByPtN6aG4HiKfd62Yd5NUZIiEMoBmSfxdRLBEgT3J9WWqoCRqVTzS93sWpP7IJ5pkGBfxMpDlugM8zn3g==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.8.0" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", @@ -4877,6 +4890,25 @@ "integrity": "sha512-e2cOW9YlVzFY2iScnGBBkplKsrn2CsObHQ2Hiw4V1sSyiGbgWL8IyqE3zFi1Pt5o1pdAtYkDAIsF3KKUPjdzaA==", "license": "MIT" }, + "node_modules/@types/bs58": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.4.tgz", + "integrity": "sha512-0IEpMFXXQi2zXaXl9GJ3sRwQo0uEkD+yFOv+FnAU5lkPtcu6h61xb7jc2CFPEZ5BUOaiP13ThuGc9HD4R8lR5g==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "base-x": "^3.0.6" + } + }, + "node_modules/@types/bs58/node_modules/base-x": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -8678,6 +8710,124 @@ } } }, + "node_modules/jito-ts": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jito-ts/-/jito-ts-4.1.1.tgz", + "integrity": "sha512-5a/z7AvtitpExcyxYh1RhPoWRfCA4IPopE5hM5Cxw7/zHnV+VBNZL0m4t3fjfPgMnmPkeoTx2xTw+mSD4PDG7w==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.8.13", + "@noble/ed25519": "^1.7.1", + "@solana/web3.js": "~1.77.3", + "@types/bs58": "^4.0.4", + "agentkeepalive": "^4.3.0", + "bs58": "^6.0.0", + "dotenv": "^16.0.3", + "jayson": "^4.0.0", + "node-fetch": "^2.6.7", + "superstruct": "^1.0.3" + } + }, + "node_modules/jito-ts/node_modules/@solana/web3.js": { + "version": "1.77.4", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.77.4.tgz", + "integrity": "sha512-XdN0Lh4jdY7J8FYMyucxCwzn6Ga2Sr1DHDWRbqVzk7ZPmmpSPOVWHzO67X1cVT+jNi1D6gZi2tgjHgDPuj6e9Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@noble/curves": "^1.0.0", + "@noble/hashes": "^1.3.0", + "@solana/buffer-layout": "^4.0.0", + "agentkeepalive": "^4.2.1", + "bigint-buffer": "^1.1.5", + "bn.js": "^5.0.0", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.0", + "node-fetch": "^2.6.7", + "rpc-websockets": "^7.5.1", + "superstruct": "^0.14.2" + } + }, + "node_modules/jito-ts/node_modules/@solana/web3.js/node_modules/base-x": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jito-ts/node_modules/@solana/web3.js/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/jito-ts/node_modules/@solana/web3.js/node_modules/superstruct": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz", + "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==", + "license": "MIT" + }, + "node_modules/jito-ts/node_modules/base-x": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.0.tgz", + "integrity": "sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==", + "license": "MIT" + }, + "node_modules/jito-ts/node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/jito-ts/node_modules/borsh/node_modules/base-x": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jito-ts/node_modules/borsh/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/jito-ts/node_modules/bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "license": "MIT", + "dependencies": { + "base-x": "^5.0.0" + } + }, + "node_modules/jito-ts/node_modules/superstruct": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz", + "integrity": "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/joi": { "version": "17.13.3", "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", @@ -13550,11 +13700,12 @@ } }, "node_modules/rpc-websockets": { - "version": "7.11.2", - "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.11.2.tgz", - "integrity": "sha512-pL9r5N6AVHlMN/vT98+fcO+5+/UcPLf/4tq+WUaid/PPUGS/ttJ3y8e9IqmaWKtShNAysMSjkczuEA49NuV7UQ==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.10.0.tgz", + "integrity": "sha512-cemZ6RiDtYZpPiBzYijdOrkQQzmBCmug0E9SdRH2gIUNT15ql4mwCYWIp0VnSZq6Qrw/JkGUygp4PrK1y9KfwQ==", "license": "LGPL-3.0-only", "dependencies": { + "@babel/runtime": "^7.17.2", "eventemitter3": "^4.0.7", "uuid": "^8.3.2", "ws": "^8.5.0" @@ -14223,9 +14374,9 @@ } }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 33ac18d..2897a6f 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,12 @@ "pino-pretty": "^10.3.1", "pino-std-serializers": "^6.2.2", "pumpdotfun-sdk": "^1.3.2", - "random-js": "^2.1.0" + "random-js": "^2.1.0", + "rpc-websockets": "7.10.0", + "@triton-one/yellowstone-grpc": "^0.4.0", + "jito-ts": "^4.0.0" + }, + "devDependencies": { + "typescript": "^5.5.4" } -} \ No newline at end of file +} diff --git a/src/Memecoin_dev/bundled_launcher/index.js b/src/Memecoin_dev/bundled_launcher/index.ts similarity index 100% rename from src/Memecoin_dev/bundled_launcher/index.js rename to src/Memecoin_dev/bundled_launcher/index.ts diff --git a/src/Memecoin_dev/market-making_dev/boost_volume.js b/src/Memecoin_dev/market-making_dev/boost_volume.ts similarity index 78% rename from src/Memecoin_dev/market-making_dev/boost_volume.js rename to src/Memecoin_dev/market-making_dev/boost_volume.ts index 751df3a..cfb8362 100644 --- a/src/Memecoin_dev/market-making_dev/boost_volume.js +++ b/src/Memecoin_dev/market-making_dev/boost_volume.ts @@ -1,26 +1,26 @@ -const { connection, wallet } = require("../../helpers/config.js"); -const { +import { connection, wallet } from "../../helpers/config"; +import { simple_executeAndConfirm, -} = require("../../Transactions/simple_tx_executor.js"); -const { +} from "../../Transactions/simple_tx_executor"; +import { jito_executeAndConfirm, -} = require("../../Transactions/jito_tips_tx_executor.js"); -const { program } = require("commander"); -const { +} from "../../Transactions/jito_tips_tx_executor"; +import { program } from "commander"; +import { loadOrCreateKeypair_wallet, checkTx, -} = require("../../helpers/util.js"); -const { +} from "../../helpers/util"; +import { ComputeBudgetProgram, TransactionMessage, VersionedTransaction, -} = require("@solana/web3.js"); -const { swapForVolume } = require("../../raydium/Pool/swap.js"); +} from "@solana/web3.js"; +import { swapForVolume } from "../../raydium/Pool/swap"; let slippage = null, - tokenAddress = null, - payer = null, + tokenAddress:any = null, + payer:any = null, cluster = null, - solPerOrder = null; + solPerOrder:any = null; program .option("--token_address ", "Specify the token address") @@ -31,7 +31,7 @@ program "Specify the number of SOL per order" ) .option("-h, --help", "display help for command") - .action((options) => { + .action((options:any) => { if (options.help) { console.log( "node boost_volume --token_address --payer --cluster --sol_per_order " @@ -61,11 +61,11 @@ async function boost_volume() { `Boosting volume..., buying and selling ${tokenAddress} in one transaction...` ); try { - const { confirmed, signature } = await swapForVolume( + const res:any = await swapForVolume( tokenAddress, solPerOrder ); - await error_handling(signature, confirmed); + await error_handling(res.signature, res.confirmed); } catch (e) { console.log(e); console.log("trying to send the transaction again..."); @@ -81,7 +81,7 @@ async function boost_volume() { * @param {boolean} confirmed - Indicates if the transaction is confirmed. * @returns {Promise} - A promise that resolves when the error handling is complete. */ -async function error_handling(signature, confirmed) { +async function error_handling(signature:any, confirmed:any) { if (confirmed) { console.log(`https://solscan.io/tx/${signature}?cluster=mainnet`); return; diff --git a/src/Memecoin_dev/sniping_dev/index.js b/src/Token/README.md similarity index 100% rename from src/Memecoin_dev/sniping_dev/index.js rename to src/Token/README.md diff --git a/src/Token/burn.js b/src/Token/burn.ts similarity index 85% rename from src/Token/burn.js rename to src/Token/burn.ts index 69d2f4e..0bcc08d 100644 --- a/src/Token/burn.js +++ b/src/Token/burn.ts @@ -1,28 +1,28 @@ -const fs = require("fs"); -const { +import fs from "fs"; +import { Connection, PublicKey, Keypair, TransactionMessage, VersionedTransaction, -} = require("@solana/web3.js"); -const { program } = require("commander"); -const { +} from "@solana/web3.js"; +import { program } from "commander"; +import { getAccount, getMint, getAssociatedTokenAddress, createBurnCheckedInstruction, -} = require("@solana/spl-token"); -const { connection, dev_connection } = require("../helpers/config"); -const { wallet } = require("../helpers/config"); +} from "@solana/spl-token"; +import { connection, dev_connection } from "../helpers/config"; +import { wallet } from "../helpers/config"; let payer_keypair_path = null, - token_address = null, - percentage = null, + token_address:any = null, + percentage:any = null, decimals = null, cluster = null, payerKeypair = null, - newConnection = null; + newConnection:any = null; program .option("--payer ", "Specify the path to the secret key") .option("--token_address ", "Specify the token address") @@ -58,7 +58,7 @@ if (cluster === "devnet") { * @param {string} filepath - The path to the keypair file. * @returns {Uint8Array} - The loaded or created keypair. */ -function loadOrCreateKeypair(filepath) { +export function loadOrCreateKeypair(filepath:string) { try { const keypairStringArr = fs.readFileSync(filepath, { encoding: "utf8", @@ -73,10 +73,10 @@ function loadOrCreateKeypair(filepath) { } /** * Retrieves the token balance for a given token account. - * @param {string} tokenAccount - The token account address. + * @param {PublicKey} tokenAccount - The token account address. * @returns {number} The token balance. */ -async function getTokenBalance(tokenAccount) { +export async function getTokenBalance(tokenAccount:PublicKey) { const info = await getAccount(newConnection, tokenAccount); // token account right here const amount = Number(info.amount); const mint = await getMint(newConnection, info.mint); @@ -87,21 +87,21 @@ async function getTokenBalance(tokenAccount) { /** * Retrieves the decimal value of a token. - * @param {string} tokenAddress - The address of the token. + * @param {PublicKey} tokenAddress - The address of the token. * @returns {Promise} The decimal value of the token. */ -async function getTokenDecimal(tokenAddress) { +export async function getTokenDecimal(tokenAddress:PublicKey) { const mint = await getMint(newConnection, tokenAddress); return mint.decimals; } /** * Burns a specified percentage of tokens from a given token address. - * @param {string} tokenAddress - The address of the token to burn. + * @param {PublicKey} tokenAddress - The address of the token to burn. * @param {object} payer - The payer's public key and associated token address. * @param {number} percentage - The percentage of tokens to burn. * @returns {Promise} - A promise that resolves when the burning process is complete. */ -async function burnToken(tokenAddress, payer, percentage) { +export async function burnToken(tokenAddress:PublicKey, payer:Keypair, percentage:number) { try { decimals = await getTokenDecimal(tokenAddress); console.log("Decimals: ", decimals); diff --git a/src/Token/create.js b/src/Token/create.ts similarity index 87% rename from src/Token/create.js rename to src/Token/create.ts index a777006..8d0255d 100644 --- a/src/Token/create.js +++ b/src/Token/create.ts @@ -1,50 +1,50 @@ -const { +import { percentAmount, generateSigner, signerIdentity, createSignerFromKeypair, Umi, generatedSignerPayer, -} = require("@metaplex-foundation/umi"); -const { +} from "@metaplex-foundation/umi"; +import { TokenStandard, createAndMint, -} = require("@metaplex-foundation/mpl-token-metadata"); -const { +} from "@metaplex-foundation/mpl-token-metadata"; +import { Metaplex, keypairIdentity, toMetaplexFile, irysStorage, -} = require("@metaplex-foundation/js"); -const { createUmi } = require("@metaplex-foundation/umi-bundle-defaults"); -const { mplCandyMachine } = require("@metaplex-foundation/mpl-candy-machine"); -const { AuthorityType, setAuthority } = require("@solana/spl-token"); -const bs58 = require("bs58"); -const fs = require("fs"); -const { PublicKey, Keypair } = require("@solana/web3.js"); -const { program } = require("commander"); -const { +} from "@metaplex-foundation/js"; +import { createUmi } from "@metaplex-foundation/umi-bundle-defaults"; +import { mplCandyMachine } from "@metaplex-foundation/mpl-candy-machine"; +import { AuthorityType, setAuthority } from "@solana/spl-token"; +import bs58 from "bs58"; +import fs from "fs"; +import { PublicKey, Keypair } from "@solana/web3.js"; +import { program } from "commander"; +import { main_endpoint, dev_connection, dev_endpoint, connection, wallet, -} = require("../helpers/config"); +} from "../helpers/config"; // info -let payer_keypair_path = null, - symbol = null, - token_name = null, - mintkeypair_path = null, - supply = null, - decimals = null, - metadata_path = null, - image_path = null, - cluster = null, - priority_fee = null, - file_type = null, - newConnection = null, - endpoint = null; +let payer_keypair_path: any = null, + symbol: any = null, + token_name: any = null, + mintkeypair_path:any = null, + supply:any = null, + decimals:any = null, + metadata_path:any = null, + image_path:any = null, + cluster:any = null, + priority_fee:any = null, + file_type:any = null, + newConnection:any = null, + endpoint:any = null; // handle the input value from the user's command line here program @@ -98,7 +98,6 @@ program supply = options.supply; decimals = options.decimals; metadata_path = options.metadata; - image = options.image; cluster = options.cluster; priority_fee = options.priority; file_type = options.file_type; @@ -134,8 +133,8 @@ if (!mintkeypair_path) { } else { mintSecret = loadOrCreateKeypair(mintkeypair_path); } -let payerSecret = null, - PayerWallet = null; +let payerSecret:any = null, + PayerWallet:any = null; // create the Umi object const umi = createUmi(endpoint); //Replace with your RPC Endpoint @@ -169,7 +168,7 @@ umi.use(mplCandyMachine()); * @returns {Keypair} - The loaded or newly created keypair. * @throws {Error} - If there is an error reading or writing the keypair file. */ -async function loadOrCreateKeypair_wallet(filepath) { +async function loadOrCreateKeypair_wallet(filepath:string) { try { const keypairString = fs.readFileSync(filepath, { encoding: "utf8" }); return Keypair.fromSecretKey(Uint8Array.from(JSON.parse(keypairString))); @@ -188,7 +187,7 @@ async function loadOrCreateKeypair_wallet(filepath) { * @param {string} filepath - The path to the keypair file. * @returns {Uint8Array} - The loaded or created keypair. */ -function loadOrCreateKeypair(filepath) { +function loadOrCreateKeypair(filepath:string) { try { const keypairStringArr = fs.readFileSync(filepath, { encoding: "utf8", @@ -208,7 +207,7 @@ function loadOrCreateKeypair(filepath) { * @param {string} owner - The owner address. * @returns {Promise} - A promise that resolves when the freeze authority is disabled. */ -async function revokeFreeze(mint, payer, owner) { +export async function revokeFreeze(mint:any, payer:any, owner:any) { console.log("Disabling the freeze authority..."); await setAuthority( newConnection, @@ -229,7 +228,7 @@ async function revokeFreeze(mint, payer, owner) { * @param {string} owner - The owner address. * @returns {Promise} - A promise that resolves when the mint authority is revoked. */ -async function revokeMint(mint, payer, owner) { +export async function revokeMint(mint:any, payer:any, owner:any) { console.log("Disabling the mint authority..."); await setAuthority( newConnection, @@ -248,7 +247,7 @@ async function revokeMint(mint, payer, owner) { * @param {string} walletPath - The path to the wallet. * @returns {Promise} The Metaplex instance. */ -async function getMetaplex(walletPath) { +export async function getMetaplex(walletPath:string) { let WALLET = null; if (walletPath === null) WALLET = wallet; else WALLET = await loadOrCreateKeypair_wallet(walletPath); @@ -276,15 +275,15 @@ async function getMetaplex(walletPath) { * @param {Metaplex} METAPLEX - The Metaplex instance used for uploading metadata. * @returns {Promise} - The URI of the uploaded metadata. */ -async function uploadMetadata( - imgUri, - imgType, - nftName, - symbol, - description, - website, - twitter, - telegram, +export async function uploadMetadata( + imgUri:any, + imgType:any, + nftName:any, + symbol:any, + description:any, + website:any, + twitter:any, + telegram:any, METAPLEX = Metaplex.make(newConnection) ) { const uri = await METAPLEX.nfts().uploadMetadata({ @@ -318,9 +317,9 @@ async function uploadMetadata( * @param {Metaplex} METAPLEX - The Metaplex instance. * @returns {Promise} The image URI. */ -async function uploadImage( - filePath, - fileName, +export async function uploadImage( + filePath:any, + fileName:any, METAPLEX = Metaplex.make(newConnection) ) { const imgBuffer = fs.readFileSync(filePath); @@ -346,20 +345,20 @@ async function uploadImage( * @param {object} mintSigner - The mint signer object. * @returns {Promise} A promise that resolves when the meme token is created. */ -async function createMeme( - name, - symbol, - filetype, - description, - website, - twitter, - telegram, - ownerWallet, - max_supply, - decimals, - imgURI, - uri, - mintSigner +export async function createMeme( + name:any, + symbol:any, + filetype:any, + description:any, + website:any, + twitter:any, + telegram:any, + ownerWallet:any, + max_supply:any, + decimals:any, + imgURI:any, + uri:any, + mintSigner:any ) { const CONFIG = { uploadPath: image_path, @@ -448,15 +447,15 @@ async function createMeme( * @param {number} decimals - The number of decimals for the token. * @returns {Promise} - A promise that resolves when the token is successfully minted. */ -async function mint_token( - umi, - mint, - name, - symbol, - uri, - owner, - amount, - decimals +export async function mint_token( + umi:any, + mint:any, + name:any, + symbol:any, + uri:any, + owner:any, + amount:any, + decimals:any ) { try { console.log(`minting token ${name}, CA: ${mint.publicKey}`); @@ -502,4 +501,3 @@ async function main() { } main(); -module.exports = { loadOrCreateKeypair }; diff --git a/src/Token/index.ts b/src/Token/index.ts new file mode 100644 index 0000000..bd81272 --- /dev/null +++ b/src/Token/index.ts @@ -0,0 +1,2 @@ +export * from "./burn"; +export * from "./create"; \ No newline at end of file diff --git a/src/Token/revoke_authority.js b/src/Token/revoke_authority.ts similarity index 82% rename from src/Token/revoke_authority.js rename to src/Token/revoke_authority.ts index 3dab772..5311394 100644 --- a/src/Token/revoke_authority.js +++ b/src/Token/revoke_authority.ts @@ -1,17 +1,18 @@ -const { AuthorityType, setAuthority } = require("@solana/spl-token"); -const bs58 = require("bs58"); -const fs = require("fs"); -const { Connection, PublicKey, Keypair } = require("@solana/web3.js"); -const { program } = require("commander"); -const { connection, dev_connection } = require("../helpers/config"); -const { loadOrCreateKeypair_wallet } = require("../helpers/util"); -const { wallet } = require("../helpers/config"); +import { AuthorityType, setAuthority } from "@solana/spl-token"; +import bs58 from "bs58" ; +import fs from "fs"; +import { Connection, PublicKey, Keypair } from "@solana/web3.js"; +import { program } from "commander"; +import { connection, dev_connection } from "../helpers/config"; +import { loadOrCreateKeypair_wallet } from "../helpers/util"; +import { wallet } from "../helpers/config"; -let newConnection = null; -let payer_keypair_path = null, - token_address = null, +let newConnection:any = null; +let payer_keypair_path:any = null, + token_address:any = null, mint = false, - freeze = false; + freeze = false, + cluster:any = null; program .option("--payer ", "Specify the path to the secret key") .option("--token_address ", "Specify the token address") @@ -59,7 +60,7 @@ program.parse(); * @param {string} owner - The owner address. * @returns {Promise} - A promise that resolves when the mint authority is revoked. */ -async function revokeMint(mint, payer, owner) { +export async function revokeMint(mint:any, payer:any, owner:any) { console.log("Disabling the mint authority..."); await setAuthority( newConnection, @@ -81,7 +82,7 @@ async function revokeMint(mint, payer, owner) { * @param {string} owner - The owner address. * @returns {Promise} - A promise that resolves when the freeze authority is disabled. */ -async function revokeFreeze(mint, payer, owner) { +export async function revokeFreeze(mint:any, payer:any, owner:any) { console.log("Disabling the freeze authority..."); await setAuthority( newConnection, @@ -103,7 +104,7 @@ async function revokeFreeze(mint, payer, owner) { * @function revokeAuthority * @returns {Promise} */ -async function revokeAuthority() { +export async function revokeAuthority() { // let payer_wallet = null; // if (payer_keypair !== null) { // payer_wallet = await loadOrCreateKeypair_wallet(payer_keypair); diff --git a/src/Token/zk-compression/compressed-token/createAndMint.js b/src/Token/zk-compression/compressed-token/createAndMint.ts similarity index 83% rename from src/Token/zk-compression/compressed-token/createAndMint.js rename to src/Token/zk-compression/compressed-token/createAndMint.ts index 8e60457..06e38c3 100644 --- a/src/Token/zk-compression/compressed-token/createAndMint.js +++ b/src/Token/zk-compression/compressed-token/createAndMint.ts @@ -1,24 +1,22 @@ -const { +import { LightSystemProgram, Rpc, confirmTx, createRpc, -} = require("@lightprotocol/stateless.js"); -const { +} from "@lightprotocol/stateless.js"; +import { createMint, mintTo, transfer, - compressToken, -} = require("@lightprotocol/compressed-token"); -const { Keypair } = require("@solana/web3.js"); -const { req } = require("pino-std-serializers"); +} from "@lightprotocol/compressed-token"; +import { Keypair } from "@solana/web3.js"; const payer = Keypair.generate(); const tokenRecipient = Keypair.generate(); const connection = createRpc(); -async function main() { +export async function main() { console.log("Payer: ", payer.publicKey.toBase58()); console.log("Token recipient: ", tokenRecipient.publicKey.toBase58()); await confirmTx( diff --git a/src/Token/zk-compression/connect-testnet.js b/src/Token/zk-compression/connect-testnet.ts similarity index 57% rename from src/Token/zk-compression/connect-testnet.js rename to src/Token/zk-compression/connect-testnet.ts index 510bc9b..8790c72 100644 --- a/src/Token/zk-compression/connect-testnet.js +++ b/src/Token/zk-compression/connect-testnet.ts @@ -1,5 +1,5 @@ -const stateless = require("@lightprotocol/stateless.js"); -const connection = stateless.createRpc( +import stateless from "@lightprotocol/stateless.js"; +const newConnection:any = stateless.createRpc( "https://zk-testnet.helius.dev:8899", // rpc "https://zk-testnet.helius.dev:8784", // zk compression rpc "https://zk-testnet.helius.dev:3001" // prover @@ -9,17 +9,17 @@ const connection = stateless.createRpc( * Main function that retrieves various information from the Solana network. * @returns {Promise} A promise that resolves when the function completes. */ -async function main() { - let slot = await connection.getSlot(); +export async function main() { + let slot = await newConnection.getSlot(); console.log("Slot: ", slot); - let health = await connection.getIndexerHealth(slot); + let health = await newConnection.getIndexerHealth(slot); console.log("health: ", health); - let leaderSchedule = await connection.getLeaderSchedule(); + let leaderSchedule = await newConnection.getLeaderSchedule(); console.log("Current leader schedule: ", leaderSchedule); - let latestNonVotingSig = await connection.getLatestNonVotingSignatures(); + let latestNonVotingSig = await newConnection.getLatestNonVotingSignatures(); console.log(latestNonVotingSig); } main(); diff --git a/src/Trading_dev/ProfitAndLoss/constants.ts b/src/Trading_dev/ProfitAndLoss/constants.ts new file mode 100644 index 0000000..e001b60 --- /dev/null +++ b/src/Trading_dev/ProfitAndLoss/constants.ts @@ -0,0 +1,34 @@ +import { logger, retrieveEnvVariable } from "../../utils"; +import { + Currency, + Token, + TOKEN_PROGRAM_ID, + } from "@raydium-io/raydium-sdk"; +import { PublicKey } from "@solana/web3.js"; +export const tp = retrieveEnvVariable("TAKE_PROFIT", logger); +export const sl = retrieveEnvVariable("STOP_LOSS", logger); +export const wsol = "So11111111111111111111111111111111111111112" +export const usdc = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" +export const quoteToken = [ + usdc, // USDC + "SOL", // SOL + "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", // USDT + wsol, // WSOL +]; +export const DEFAULT_TOKEN = { + SOL: new Currency(9, "SOL", "SOL"), + WSOL: new Token( + TOKEN_PROGRAM_ID, + new PublicKey("So11111111111111111111111111111111111111112"), + 9, + "WSOL", + "WSOL" + ), + USDC: new Token( + TOKEN_PROGRAM_ID, + new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), + 6, + "USDC", + "USDC" + ), +}; \ No newline at end of file diff --git a/src/Trading_dev/ProfitAndLoss/index.ts b/src/Trading_dev/ProfitAndLoss/index.ts new file mode 100644 index 0000000..01238e0 --- /dev/null +++ b/src/Trading_dev/ProfitAndLoss/index.ts @@ -0,0 +1,4 @@ +export * from "./stop-loss"; +export * from "./take-profit"; +export * from "./utils"; +export * from "./constants"; \ No newline at end of file diff --git a/src/Trading_dev/ProfitAndLoss/stop-loss.ts b/src/Trading_dev/ProfitAndLoss/stop-loss.ts new file mode 100644 index 0000000..f9af5fc --- /dev/null +++ b/src/Trading_dev/ProfitAndLoss/stop-loss.ts @@ -0,0 +1,58 @@ +import {sl} from "." +import { readBoughtTokens, writeBoughtTokens, getCurrentPriceRaydium } from "./utils"; +import Decimal from 'decimal.js'; +/** + * Sets the stop loss price for a given token. + * @param {string} tokenAddress - The address of the token. + * @returns {Promise} - A promise that resolves when the stop loss price is set. + */ +export async function setStopLoss_Price(tokenAddress: string, path_To_bought_tokens:string){ + try{ + const tokenObj = await readBoughtTokens(tokenAddress, path_To_bought_tokens); + const our_entry_price = tokenObj.entry_price; + const sl_price = our_entry_price * (1 - parseFloat(sl)); + tokenObj.sl_price = sl_price; + await writeBoughtTokens(tokenAddress, tokenObj, path_To_bought_tokens); + }catch(err){ + console.error("Error setting stop loss: ", err); + } +} +/** + * Retrieves the stop loss price for a given token address. + * @param {string} tokenAddress - The address of the token. + * @returns {number} - The stop loss price of the token. + */ +export async function getStopLoss_Price(tokenAddress: string, path_To_bought_tokens:string){ + try{ + const tokenObj = await readBoughtTokens(tokenAddress, path_To_bought_tokens); + return tokenObj.sl_price; + }catch(err){ + console.error("Error getting stop loss price: ", err); + } +} +/** + * Checks if the current price of a token is below or equal to the stop loss price. + * @param {string} tokenAddress - The address of the token to check. + * @returns {Promise} - A promise that resolves to `true` if the current price is below or equal to the stop loss price, otherwise `false`. + */ +export async function checkStopLoss(tokenAddress: string, path_To_bought_tokens:string): Promise{ + let res = false; + try{ + const tokenObj = await readBoughtTokens(tokenAddress, path_To_bought_tokens); + const current_price = new Decimal(await getCurrentPriceRaydium(tokenAddress, path_To_bought_tokens)); + const stop_loss_price = new Decimal(tokenObj.sl_price); + if (stop_loss_price.greaterThanOrEqualTo(current_price)) { + res = true; + } + }catch(e:any){ + console.error("Error checking stop loss: ", e); + if (e.response && e.response.status === 502) { + console.error('Bad Gateway: The server received an invalid response from the upstream server.'); + } + if (e.response && e.response.status === 504) { + console.error('Gateway Timeout: The server did not receive a timely response.'); + } + } + return res; +} + diff --git a/src/Trading_dev/ProfitAndLoss/take-profit.ts b/src/Trading_dev/ProfitAndLoss/take-profit.ts new file mode 100644 index 0000000..ff99e2e --- /dev/null +++ b/src/Trading_dev/ProfitAndLoss/take-profit.ts @@ -0,0 +1,63 @@ +import {tp} from "." +import { readBoughtTokens, writeBoughtTokens, getCurrentPriceRaydium } from "./utils"; +import Decimal from 'decimal.js'; +/** + * Sets the take profit price for a given token address. + * @param {string} tokenAddress - The address of the token. + * @returns {Promise} - A promise that resolves when the take profit price is set. + */ +export async function setTakeProfit_Price(tokenAddress: string, path_To_bought_tokens:string){ + try{ + const tokenObj = await readBoughtTokens(tokenAddress, path_To_bought_tokens); + const our_entry_price = tokenObj.entry_price; + const tp_price = our_entry_price * (1 + parseFloat(tp)); + tokenObj.tp_price = tp_price; + await writeBoughtTokens(tokenAddress, tokenObj, path_To_bought_tokens); + }catch(err){ + console.error("Error setting take profit: ", err); + } +} + +/** + * Retrieves the take profit price for a given token address. + * + * @param {string} tokenAddress - The address of the token. + * @returns {Promise} - The take profit price of the token. + * @throws {Error} - If there is an error retrieving the take profit price. + */ +export async function getTakeProfit_Price(tokenAddress: string, path_To_bought_tokens:string){ + try{ + const tokenObj = await readBoughtTokens(tokenAddress, path_To_bought_tokens); + return tokenObj.tp_price; + }catch(err){ + console.error("Error getting take profit price: ", err); + } +} + +/** + * Checks if the current price of a token is greater than or equal to the take profit price. + * @param {string} tokenAddress - The address of the token to check. + * @returns {Promise} - A promise that resolves to true if the current price is greater than or equal to the take profit price, false otherwise. + */ +export async function checkTakeProfit(tokenAddress: string, path_To_bought_tokens:string): Promise{ + let res = false; + try{ + const tokenObj = await readBoughtTokens(tokenAddress, path_To_bought_tokens); + const current_price = new Decimal(await getCurrentPriceRaydium(tokenAddress, path_To_bought_tokens)).toFixed(20); + const take_profit_price = new Decimal(tokenObj.tp_price).toFixed(20); + + if(current_price > take_profit_price){ + console.log(`Take profit price reached for token ${tokenAddress}`); + res = true; + } + }catch(e:any){ + console.error("Error checking take profit: ", e); + if (e.response && e.response.status === 502) { + console.error('Bad Gateway: The server received an invalid response from the upstream server.'); + } + if (e.response && e.response.status === 504) { + console.error('Gateway Timeout: The server did not receive a timely response.'); + } + } + return res; +} diff --git a/src/Trading_dev/ProfitAndLoss/utils.ts b/src/Trading_dev/ProfitAndLoss/utils.ts new file mode 100644 index 0000000..b77a2f1 --- /dev/null +++ b/src/Trading_dev/ProfitAndLoss/utils.ts @@ -0,0 +1,209 @@ +import * as fs from 'fs/promises'; +import fetch from 'cross-fetch'; +import {sl, tp, wsol} from "." +import Decimal from 'decimal.js'; +import {getCurrentMarketCap, getDayVolume, getCurrentSolInPool, initSdk } from "../../raydium"; +import {fetchAMMPoolId} from "../../raydium/Pool/fetch_pool" +import {logger} from "../../utils" +let sdkCache = {sdk: null, expiry: 0} +export async function loadBoughtTokens(path_To_bought_tokens:string) { + try { + let boughtTokens:any = []; + const data = await fs.readFile(path_To_bought_tokens, 'utf8'); + const jsonData = JSON.parse(data); + // the JSON structure is something like { "tokenA": {...}, "tokenB": {...} } + boughtTokens = Object.keys(jsonData); + return boughtTokens; + } catch (err) { + console.error('Error reading or parsing file:', err); + } + } +/** + * Reads the bought tokens from a JSON file and returns the token object for the given token address. + * @param {string} tokenAddress - The address of the token to read. + * @returns {Object} - The token object containing entry price, take profit price, and stop loss price. + */ +export async function readBoughtTokens(tokenAddress:string, path_To_bought_tokens:string) { + try { + // Read the JSON file asynchronously + const data = await fs.readFile(path_To_bought_tokens, { encoding: 'utf8' }); + // Parse the JSON data + const jsonData = JSON.parse(data); + // Access the data + if(!(tokenAddress in jsonData)){ + return null; + } + + const tokenObj = jsonData[tokenAddress]; + + return tokenObj; + } catch (err) { + console.error('Error reading file:', err); + } +} +/** + * Writes the bought tokens to a JSON file. + * @param {string} tokenAddress - The address of the token. + * @param {object} tokenObj - The token object to be written. + * @returns {Promise} - A promise that resolves when the tokens are written successfully, or rejects with an error. + */ +export async function writeBoughtTokens(tokenAddress:string, tokenObj:object, path_To_bought_tokens:string) { + try { + // Read the JSON file asynchronously + const data = await fs.readFile(path_To_bought_tokens, { encoding: 'utf8' }); + // Parse the JSON data + const jsonData = JSON.parse(data); + // Update the JSON data + jsonData[tokenAddress] = tokenObj; + // Write the updated JSON data back to the file + await fs.writeFile(path_To_bought_tokens, JSON.stringify(jsonData, null, 2)); + } catch (err) { + console.error('Error writing bought tokens file:', err); + } +} +/** + * Deletes the bought tokens after selling it from the JSON file. + * @param {string} tokenAddress - The address of the token to be deleted. + * @returns {Promise} - A promise that resolves when the tokens are deleted successfully. + */ +export async function deleteBoughtTokens(tokenAddress:string, path_To_bought_tokens:string) { + try { + // Read the JSON file asynchronously + const data = await fs.readFile(path_To_bought_tokens, { encoding: 'utf8' }); + // Parse the JSON data + const jsonData = JSON.parse(data); + if (tokenAddress in jsonData) delete jsonData[tokenAddress]; + // Write the updated JSON data back to the file + await fs.writeFile(path_To_bought_tokens, JSON.stringify(jsonData, null, 2)); + } catch (err) { + console.error('Error deleting bought tokens file:', err); + } +} + +export async function getCurrentPriceJUP(tokenAddress:string){ + // api: https://price.jup.ag/v6/price?ids=tokenAddress&vsToken=So11111111111111111111111111111111111111112 + try{ + const response = await( await fetch(`https://price.jup.ag/v6/price?ids=${tokenAddress}&vsToken=${wsol}`)).json(); + //const response = await( await fetch(`https://quote-api.jup.ag/v6/quote?inputMint=${wsol}&outputMint=${tokenAddress}&amount=1000000&slippageBps=50`) ).json() + console.log(response) + }catch(e){ + console.log(`Error when getting current price of ${tokenAddress} `, e) + } +} +export async function logExitPrice(tokenAddress: string, exitPrice:number, path_To_bought_tokens:string){ + let tokenObj = await readBoughtTokens(tokenAddress, path_To_bought_tokens); + tokenObj.exit_price = exitPrice; + await writeBoughtTokens(tokenAddress, tokenObj, path_To_bought_tokens); +} +export async function logTraderEntryPrice(tokenAddress:string, entryPrice:number, path_To_bought_tokens:string){ + const tokenObj = await readBoughtTokens(tokenAddress, path_To_bought_tokens); + tokenObj.trader_entry_price = entryPrice; + await writeBoughtTokens(tokenAddress, tokenObj, path_To_bought_tokens); +} +// export async function setEntryPrice(tokenAddress){ +// const tokenObj = await readBoughtTokens(tokenAddress); +// const trader_entry_price = tokenObj.trader_entry_price; +// tokenObj.entry_price = trader_entry_price * (1 - entry_percentage); +// await writeBoughtTokens(tokenAddress, tokenObj); +// } +export async function setInitTokenObj(tokenAddress: string, ourEntryPrice: number, path_To_bought_tokens:string, poolId:string){ + // if day volume < 100k, + // we don't trade it + let ourEntryPriceDec = new Decimal(ourEntryPrice); + let tpPriceDec = ourEntryPriceDec.mul(new Decimal(1).plus(tp)); + let slPriceDec = ourEntryPriceDec.mul(new Decimal(1).minus(sl)); + const mc = await getCurrentMarketCap(tokenAddress); + const noOfSolInPool = await getCurrentSolInPool(tokenAddress); + let solPerOrder = 0; + + if((mc||0) >= 10000000){ + solPerOrder = 2; + tpPriceDec = ourEntryPriceDec.mul(new Decimal(1).plus(new Decimal(0.05))); + } + if((mc||0) >= 5000000){ + solPerOrder = 1.5 + tpPriceDec = ourEntryPriceDec.mul(new Decimal(1).plus(new Decimal(0.05))); + } + else if((mc||0) >= 1000000){ + solPerOrder = 1; + tpPriceDec = ourEntryPriceDec.mul(new Decimal(1).plus(new Decimal(0.05))); + }else{ + solPerOrder = 0.5; + tpPriceDec = ourEntryPriceDec.mul(new Decimal(1).plus(new Decimal(0.05))); + } + + const tokenObj = { + "entry_price": ourEntryPriceDec, + "tp_price": tpPriceDec, + "sl_price": slPriceDec, + "exit_price": 0, + "poolId": poolId, + "number_of_sol_in_pool": noOfSolInPool, + "market_cap": mc, + "sol_per_order": solPerOrder, + } + console.log("Init our trade successfully!", tokenObj) + await writeBoughtTokens(tokenAddress, tokenObj, path_To_bought_tokens); +} +export async function getCurrentPriceRaydium(tokenAddress:string, path_To_bought_tokens:string){ + try{ + // Check if poolId is already set + let raydium:any = null + if(sdkCache.sdk){ + raydium = sdkCache.sdk; + } + else { + raydium = await initSdk(); + sdkCache.sdk = raydium; + } + const tokenObj = await readBoughtTokens(tokenAddress, path_To_bought_tokens); + let poolId:any = null; + if (tokenObj === null) { + poolId = ""; + } else { + poolId = tokenObj.poolId; + } + if (poolId === "") { + poolId = await fetchAMMPoolId(tokenAddress); + if(tokenObj){ + tokenObj.poolId = poolId; + await writeBoughtTokens(tokenAddress, tokenObj, path_To_bought_tokens); + } + } + const res = await raydium.liquidity.getRpcPoolInfos([poolId]); + const poolInfo = res[poolId]; + const baseMint = poolInfo.baseMint.toString(); + const quoteMint = poolInfo.quoteMint.toString(); + const baseDecimals = new Decimal(poolInfo.baseDecimal.toString()); + const quoteDecimals = new Decimal(poolInfo.quoteDecimal.toString()); + const solMintAddress = wsol; + //const solPrice = await getCurrentSolPrice(); + let solReserve:any = null; + let tokenReserve:any = null; + let priceInSOL; + + if (baseMint === solMintAddress) { + // baseMint is SOL, (this is pump token) + solReserve = new Decimal(poolInfo.baseReserve.toString()).div(new Decimal(10).pow(baseDecimals)); + tokenReserve = new Decimal(poolInfo.quoteReserve.toString()).div(new Decimal(10).pow(quoteDecimals)); + priceInSOL = solReserve.div(tokenReserve); + } else { + // Neither baseMint nor quoteMint is SOL, use the pool price directly + solReserve = new Decimal(poolInfo.quoteReserve.toString()).div(new Decimal(10).pow(quoteDecimals)); + tokenReserve = new Decimal(poolInfo.baseReserve.toString()).div(new Decimal(10).pow(baseDecimals)); + priceInSOL = poolInfo.poolPrice; + } + //console.log(`Current price of ${tokenAddress} in SOL: ${priceInSOL}`); + return priceInSOL; + }catch(e){ + logger.error(`Error when getting current price of ${tokenAddress} `, e) + } +} + //"tokenA": { + // "trader_entry_price": 0.5312, + // "entry_price": 0.5152, + // "actual_entry_price": 0.5152, + // "tp_price": 0.58432, + // "sl_price": 0.42496, + // "exit_price": 0.5312 + //} diff --git a/src/Trading_dev/memecoin_trading_strategies/copy_trading/bought-tokens.json b/src/Trading_dev/copy-bot/bought-tokens.json similarity index 100% rename from src/Trading_dev/memecoin_trading_strategies/copy_trading/bought-tokens.json rename to src/Trading_dev/copy-bot/bought-tokens.json diff --git a/src/Trading_dev/memecoin_trading_strategies/copy_trading/copy-buy.js b/src/Trading_dev/copy-bot/copy-buy.ts similarity index 88% rename from src/Trading_dev/memecoin_trading_strategies/copy_trading/copy-buy.js rename to src/Trading_dev/copy-bot/copy-buy.ts index 54efd05..1ddda78 100644 --- a/src/Trading_dev/memecoin_trading_strategies/copy_trading/copy-buy.js +++ b/src/Trading_dev/copy-bot/copy-buy.ts @@ -1,22 +1,15 @@ -const { PublicKey } = require("@solana/web3.js"); -const { TOKEN_PROGRAM_ID, AccountLayout } = require("@solana/spl-token"); -const { - connection, - wallet, - smart_money_wallet, -} = require("../../../helpers/config"); -//const { buy } = require("../../dex/jupiter/swap/buy-helper"); -//const { sell } = require("../../dex/jupiter/swap/sell-helper"); -const path = require("path"); -const { swap } = require("../../../jupiter/swap/swap-helper"); -const { buy } = require("../../../raydium/buy_helper"); -const { sell } = require("../../../raydium/sell_helper"); -const fs = require("fs"); +import { PublicKey } from "@solana/web3.js"; +import { TOKEN_PROGRAM_ID, AccountLayout } from "@solana/spl-token"; +import { connection, wallet, smart_money_wallet } from "../../helpers/config"; +import path from "path"; +import { swap } from "../../jupiter/swap/swap-helper"; +import { buy } from "../../raydium/buy_helper"; +import { sell } from "../../raydium/sell_helper"; +import fs from "fs"; const boughtTokensPath = path.join(__dirname, "bought-tokens.json"); -//const {swap} = require("../../../Pool/swap") let walletsToListen = []; -var previous_trader_wallet_state = {}; -var previous_our_wallet_state = {}; +var previous_trader_wallet_state: any = {}; +var previous_our_wallet_state: any = {}; // [usdc, sol, usdt, wsol] const wsol = "So11111111111111111111111111111111111111112"; const quoteToken = [ @@ -27,7 +20,7 @@ const quoteToken = [ ]; let boughtTokens = JSON.parse(fs.readFileSync(boughtTokensPath, "utf8")); -async function saveToJson(token) { +export async function saveToJson(token: string) { boughtTokens.push(token); fs.writeFileSync(boughtTokensPath, JSON.stringify(boughtTokens, null, 2)); } @@ -36,7 +29,7 @@ async function saveToJson(token) { * Listens to changes in multiple wallets and performs trading actions based on the changes. * @returns {Promise} A promise that resolves once the wallet listening is set up. */ -async function listenToWallets(address) { +export async function listenToWallets(address: PublicKey) { try { connection.onProgramAccountChange( TOKEN_PROGRAM_ID, @@ -48,10 +41,10 @@ async function listenToWallets(address) { // realize in smart money wallet there is a token's balance changed // then we look at trader's portfolio console.log("Wallet state changed"); - const current_trader_wallet_state = await retriveWalletState( + const current_trader_wallet_state: any = await retriveWalletState( address.toBase58() ); - const current_our_wallet_state = await retriveWalletState( + const current_our_wallet_state: any = await retriveWalletState( wallet.publicKey.toBase58() ); if ( @@ -93,7 +86,7 @@ async function listenToWallets(address) { console.log("We don't have enough SOL to swap"); throw new Error("We don't have enough SOL to swap"); } - if ((!changedMint) in current_trader_wallet_state) { + if (!(changedMint in current_trader_wallet_state)) { current_trader_wallet_state[changedMint] = 0; } const sell_percentage = Math.abs( @@ -215,7 +208,7 @@ async function listenToWallets(address) { * @param {string} wallet_address - The address of the wallet to retrieve the state for. * @returns {Object} - An object containing the token balances of the wallet and the SOL balance. */ -async function retriveWalletState(wallet_address) { +async function retriveWalletState(wallet_address: string) { try { const filters = [ { @@ -232,13 +225,13 @@ async function retriveWalletState(wallet_address) { TOKEN_PROGRAM_ID, //new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") { filters: filters } ); - let results = {}; + let results: any = {}; const solBalance = await connection.getBalance( new PublicKey(wallet_address) ); accounts.forEach((account, i) => { //Parse the account data - const parsedAccountInfo = account.account.data; + const parsedAccountInfo: any = account.account.data; const mintAddress = parsedAccountInfo["parsed"]["info"]["mint"]; const tokenBalance = parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"]; @@ -256,9 +249,9 @@ async function retriveWalletState(wallet_address) { * Copies trades based on predefined parameters. * @returns {Promise} A promise that resolves when the trade copying is complete. */ -async function copy_buy() { +export async function copy_buy() { // smart money wallet address - let smart_money_address = smart_money_wallet; + let smart_money_address: any = smart_money_wallet; // our wallet address let our_wallet_address = wallet.publicKey.toBase58(); previous_trader_wallet_state = await retriveWalletState(smart_money_address); @@ -271,8 +264,3 @@ async function copy_buy() { } copy_buy(); -module.exports = { - copy_buy, - listenToWallets, - retriveWalletState, -}; diff --git a/src/Trading_dev/copy-bot/copy-sell.ts b/src/Trading_dev/copy-bot/copy-sell.ts new file mode 100644 index 0000000..6ffd37d --- /dev/null +++ b/src/Trading_dev/copy-bot/copy-sell.ts @@ -0,0 +1,104 @@ +import { PublicKey } from "@solana/web3.js"; +import { TOKEN_PROGRAM_ID, AccountLayout } from "@solana/spl-token"; +import fs from "fs"; +import path from "path"; +import { wallet, connection, smart_money_wallet } from "../../helpers/config"; +//import { buy } from("../../dex/jupiter/swap/buy-helper"); +//import { sell } from("../../dex/jupiter/swap/sell-helper"); +import { sell } from "../../raydium/sell_helper"; + +//const {swap} from("../../../Pool/swap") +var current_trader_wallet_state: any = {}; +var current_our_wallet_state: any = {}; +// [usdc, sol, usdt, wsol] +const wsol = "So11111111111111111111111111111111111111112"; +const quoteToken = [ + "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "SOL", + "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", + wsol, +]; +const boughtTokensPath = path.join(__dirname, "bought-tokens.json"); +let boughtTokens = JSON.parse(fs.readFileSync(boughtTokensPath, "utf8")); +function saveToJson() { + fs.writeFileSync(boughtTokensPath, JSON.stringify(boughtTokens, null, 2)); +} +/** + * Retrieves the state of a wallet by querying the Solana blockchain. + * @param {string} wallet_address - The address of the wallet to retrieve the state for. + * @returns {Object} - An object containing the token balances of the wallet and the SOL balance. + */ +async function retriveWalletState(wallet_address: string) { + const filters = [ + { + dataSize: 165, //size of account (bytes) + }, + { + memcmp: { + offset: 32, //location of our query in the account (bytes) + bytes: wallet_address, //our search criteria, a base58 encoded string + }, + }, + ]; + const accounts = await connection.getParsedProgramAccounts( + TOKEN_PROGRAM_ID, //new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") + { filters: filters } + ); + let results: any = {}; + const solBalance = await connection.getBalance(new PublicKey(wallet_address)); + accounts.forEach((account, i) => { + //Parse the account data + const parsedAccountInfo: any = account.account.data; + const mintAddress = parsedAccountInfo["parsed"]["info"]["mint"]; + const tokenBalance = + parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"]; + + results[mintAddress] = tokenBalance; + results["SOL"] = solBalance / 10 ** 9; + }); + return results; +} +export async function copy_sell(address: string) { + // 400 ms to check the wallet state + // if token we have but trader doesn't have, sell it + // that's it + let soldTokens: string[] = []; + let flag = false; + let possible_cant_sell_token = null; + try { + if (boughtTokens.length > 0) { + for (let i = 0; i < boughtTokens.length; i++) { + let token = boughtTokens[i]; + current_trader_wallet_state = await retriveWalletState(address); + if ( + !(token in current_trader_wallet_state) || + current_trader_wallet_state[token] == 0 + ) { + console.log(`Selling ${token}...`); + soldTokens.push(token); + flag = true; + sell("sell", token, 100, wallet); + } + } + } + } catch (err) { + console.log(err); + } + if (flag) { + // Update the list with the remaining unsold tokens + boughtTokens = boughtTokens.filter( + (token: any) => !soldTokens.includes(token) + ); + // Save the updated list back to the JSON file + saveToJson(); + } +} +async function main() { + while (true) { + boughtTokens = JSON.parse(fs.readFileSync(boughtTokensPath, "utf8")); + await copy_sell(smart_money_wallet || ""); + + await new Promise((resolve) => setTimeout(resolve, 2500)); + } +} +main(); diff --git a/src/Trading_dev/memecoin_trading_strategies/copy_trading/copy-trade.js b/src/Trading_dev/copy-bot/copy-trade.ts similarity index 86% rename from src/Trading_dev/memecoin_trading_strategies/copy_trading/copy-trade.js rename to src/Trading_dev/copy-bot/copy-trade.ts index b12869e..2d68130 100644 --- a/src/Trading_dev/memecoin_trading_strategies/copy_trading/copy-trade.js +++ b/src/Trading_dev/copy-bot/copy-trade.ts @@ -2,8 +2,8 @@ // use two cores to run the two functions // 1. copy_sell // 2. copy_buy -const { fork } = require('child_process'); -const path = require('path'); +import { fork } from 'child_process'; +import path from 'path'; const copySellPath = path.join(__dirname, 'copy-sell.js'); const copyBuyPath = path.join(__dirname, 'copy-buy.js'); // Run copy_sell in a separate process diff --git a/src/Trading_dev/dex/meteora/constants.js b/src/Trading_dev/dex/meteora/constants.js deleted file mode 100644 index 818f309..0000000 --- a/src/Trading_dev/dex/meteora/constants.js +++ /dev/null @@ -1,6 +0,0 @@ -const PROGRAM_ID = "Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB"; -const wsol = "So11111111111111111111111111111111111111112"; -const usdc = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; -const usdt = "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"; // USDT - -module.exports = {PROGRAM_ID, wsol, usdc, usdt}; \ No newline at end of file diff --git a/src/Trading_dev/dex/meteora/fetch-pool.js b/src/Trading_dev/dex/meteora/fetch-pool.js deleted file mode 100644 index 28ebf90..0000000 --- a/src/Trading_dev/dex/meteora/fetch-pool.js +++ /dev/null @@ -1,25 +0,0 @@ -async function fetchDLMMPoolId(tokenAddress) { - const url = `https://dlmm-api.meteora.ag/pair/all_by_groups?sort_key=tvl&order_by=desc&search_term=${tokenAddress}&include_unknown=false`; - const response = await (await fetch(url)).json(); - // check if the string start with "SOL" or end with "SOL" - - const listOfGroups = response.groups; - for (const group of listOfGroups) { - const name = group.name; - if(name.startsWith("SOL") || name.endsWith("SOL")){ - return group.pairs[0].address; - } - } - console.log("No DLMM Pool ID found for the given token address: ", tokenAddress); - return ""; // return empty string if no DLMMPool ID is found -} - -async function main() { - const tokenAddress = "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"; - const poolId = await fetchDLMMPoolId(tokenAddress); - console.log(poolId); -} - -//main(); - -module.exports = { fetchDLMMPoolId }; \ No newline at end of file diff --git a/src/Trading_dev/dex/meteora/fetch-price.js b/src/Trading_dev/dex/meteora/fetch-price.js deleted file mode 100644 index 13df08a..0000000 --- a/src/Trading_dev/dex/meteora/fetch-price.js +++ /dev/null @@ -1,33 +0,0 @@ -const { fetchDLMMPoolId } = require("./fetch-pool"); -const {usdc} = require("./constants"); - -async function getCurrentPriceInSOL(tokenAddress) { - const poolId = await fetchDLMMPoolId(tokenAddress); - const response = await ( - await fetch(`https://dlmm-api.meteora.ag/pair/${poolId}`) - ).json(); - return response.current_price; -} -async function getCurrentSolPrice() { - const poolId = await fetchDLMMPoolId(usdc); - const response = await ( - await fetch(`https://dlmm-api.meteora.ag/pair/${poolId}`) - ).json(); - return response.current_price; -} -async function getCurrentPriceInUSD(tokenAddress) { - const poolId = await fetchDLMMPoolId(tokenAddress); - const response = await ( - await fetch(`https://dlmm-api.meteora.ag/pair/${poolId}`) - ).json(); - return response.current_price*(await getCurrentSolPrice()); -} - -async function main(){ - console.log(await getCurrentPriceInSOL("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr")); - console.log(await getCurrentPriceInUSD("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr")); -} - -//main(); - -module.exports = { getCurrentPriceInUSD, getCurrentPriceInSOL, getCurrentSolPrice }; \ No newline at end of file diff --git a/src/Trading_dev/dex/meteora/idl.js b/src/Trading_dev/dex/meteora/idl.js deleted file mode 100644 index e1c5dc3..0000000 --- a/src/Trading_dev/dex/meteora/idl.js +++ /dev/null @@ -1,6501 +0,0 @@ -const Amm = { - version: "0.4.12", - name: "amm", - docs: ["Program for AMM"], - instructions: [ - { - name: "initializePermissionedPool", - docs: ["Initialize a new permissioned pool."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: true, - docs: ["Pool account (arbitrary address)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "tokenAMint", - isMut: false, - isSigner: false, - docs: ["Token A mint of the pool. Eg: USDT"], - }, - { - name: "tokenBMint", - isMut: false, - isSigner: false, - docs: ["Token B mint of the pool. Eg: USDC"], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault A"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault B"], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "adminTokenA", - isMut: true, - isSigner: false, - docs: [ - "Admin token account for pool token A mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "adminTokenB", - isMut: true, - isSigner: false, - docs: [ - "Admin token account for pool token B mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "adminPoolLp", - isMut: true, - isSigner: false, - docs: [ - "Admin pool LP token account. Used to receive LP during first deposit (initialize pool)", - "Admin pool LP token account. Used to receive LP during first deposit (initialize pool)", - ], - }, - { - name: "protocolTokenAFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token A. Used to receive trading fee.", - ], - }, - { - name: "protocolTokenBFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token B. Used to receive trading fee.", - ], - }, - { - name: "admin", - isMut: true, - isSigner: true, - docs: [ - "Admin account. This account will be the admin of the pool, and the payer for PDA during initialize pool.", - ], - }, - { - name: "feeOwner", - isMut: false, - isSigner: false, - }, - { - name: "rent", - isMut: false, - isSigner: false, - docs: ["Rent account."], - }, - { - name: "mintMetadata", - isMut: true, - isSigner: false, - }, - { - name: "metadataProgram", - isMut: false, - isSigner: false, - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. The pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "associatedTokenProgram", - isMut: false, - isSigner: false, - docs: ["Associated token program."], - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - ], - args: [ - { - name: "curveType", - type: { - defined: "CurveType", - }, - }, - ], - }, - { - name: "initializePermissionlessPool", - docs: ["Initialize a new permissionless pool."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA address)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "tokenAMint", - isMut: false, - isSigner: false, - docs: ["Token A mint of the pool. Eg: USDT"], - }, - { - name: "tokenBMint", - isMut: false, - isSigner: false, - docs: ["Token B mint of the pool. Eg: USDC"], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault A"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault B"], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "payerTokenA", - isMut: true, - isSigner: false, - docs: [ - "Payer token account for pool token A mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerTokenB", - isMut: true, - isSigner: false, - docs: [ - "Admin token account for pool token B mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerPoolLp", - isMut: true, - isSigner: false, - }, - { - name: "protocolTokenAFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token A. Used to receive trading fee.", - ], - }, - { - name: "protocolTokenBFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token B. Used to receive trading fee.", - ], - }, - { - name: "payer", - isMut: true, - isSigner: true, - docs: [ - "Admin account. This account will be the admin of the pool, and the payer for PDA during initialize pool.", - ], - }, - { - name: "feeOwner", - isMut: false, - isSigner: false, - }, - { - name: "rent", - isMut: false, - isSigner: false, - docs: ["Rent account."], - }, - { - name: "mintMetadata", - isMut: true, - isSigner: false, - }, - { - name: "metadataProgram", - isMut: false, - isSigner: false, - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. The pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "associatedTokenProgram", - isMut: false, - isSigner: false, - docs: ["Associated token program."], - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - ], - args: [ - { - name: "curveType", - type: { - defined: "CurveType", - }, - }, - { - name: "tokenAAmount", - type: "u64", - }, - { - name: "tokenBAmount", - type: "u64", - }, - ], - }, - { - name: "initializePermissionlessPoolWithFeeTier", - docs: ["Initialize a new permissionless pool with customized fee tier"], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA address)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "tokenAMint", - isMut: false, - isSigner: false, - docs: ["Token A mint of the pool. Eg: USDT"], - }, - { - name: "tokenBMint", - isMut: false, - isSigner: false, - docs: ["Token B mint of the pool. Eg: USDC"], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault A"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault B"], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "payerTokenA", - isMut: true, - isSigner: false, - docs: [ - "Payer token account for pool token A mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerTokenB", - isMut: true, - isSigner: false, - docs: [ - "Admin token account for pool token B mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerPoolLp", - isMut: true, - isSigner: false, - }, - { - name: "protocolTokenAFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token A. Used to receive trading fee.", - ], - }, - { - name: "protocolTokenBFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token B. Used to receive trading fee.", - ], - }, - { - name: "payer", - isMut: true, - isSigner: true, - docs: [ - "Admin account. This account will be the admin of the pool, and the payer for PDA during initialize pool.", - ], - }, - { - name: "feeOwner", - isMut: false, - isSigner: false, - }, - { - name: "rent", - isMut: false, - isSigner: false, - docs: ["Rent account."], - }, - { - name: "mintMetadata", - isMut: true, - isSigner: false, - }, - { - name: "metadataProgram", - isMut: false, - isSigner: false, - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. The pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "associatedTokenProgram", - isMut: false, - isSigner: false, - docs: ["Associated token program."], - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - ], - args: [ - { - name: "curveType", - type: { - defined: "CurveType", - }, - }, - { - name: "tradeFeeBps", - type: "u64", - }, - { - name: "tokenAAmount", - type: "u64", - }, - { - name: "tokenBAmount", - type: "u64", - }, - ], - }, - { - name: "enableOrDisablePool", - docs: [ - "Enable or disable a pool. A disabled pool allow only remove balanced liquidity operation.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "admin", - isMut: false, - isSigner: true, - docs: ["Admin account. Must be owner of the pool."], - }, - ], - args: [ - { - name: "enable", - type: "bool", - }, - ], - }, - { - name: "swap", - docs: [ - "Swap token A to B, or vice versa. An amount of trading fee will be charged for liquidity provider, and the admin of the pool.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "userSourceToken", - isMut: true, - isSigner: false, - docs: [ - "User token account. Token from this account will be transfer into the vault by the pool in exchange for another token of the pool.", - ], - }, - { - name: "userDestinationToken", - isMut: true, - isSigner: false, - docs: [ - "User token account. The exchanged token will be transfer into this account from the pool.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["Lp token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["Lp token mint of vault b"], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "protocolTokenFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account. Used to receive trading fee. It's mint field must matched with user_source_token mint field.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: ["User account. Must be owner of user_source_token."], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "inAmount", - type: "u64", - }, - { - name: "minimumOutAmount", - type: "u64", - }, - ], - }, - { - name: "removeLiquiditySingleSide", - docs: [ - "Withdraw only single token from the pool. Only supported by pool with stable swap curve.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "userPoolLp", - isMut: true, - isSigner: false, - docs: [ - "User pool lp token account. LP will be burned from this account upon success liquidity removal.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault A"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault B"], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "userDestinationToken", - isMut: true, - isSigner: false, - docs: [ - "User token account to receive token upon success liquidity removal.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: ["User account. Must be owner of the user_pool_lp account."], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. The pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "poolTokenAmount", - type: "u64", - }, - { - name: "minimumOutAmount", - type: "u64", - }, - ], - }, - { - name: "addImbalanceLiquidity", - docs: [ - "Deposit tokens to the pool in an imbalance ratio. Only supported by pool with stable swap curve.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "userPoolLp", - isMut: true, - isSigner: false, - docs: [ - "user pool lp token account. lp will be burned from this account upon success liquidity removal.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "userAToken", - isMut: true, - isSigner: false, - docs: [ - "User token A account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "userBToken", - isMut: true, - isSigner: false, - docs: [ - "User token B account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: [ - "User account. Must be owner of user_a_token, and user_b_token.", - ], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "minimumPoolTokenAmount", - type: "u64", - }, - { - name: "tokenAAmount", - type: "u64", - }, - { - name: "tokenBAmount", - type: "u64", - }, - ], - }, - { - name: "removeBalanceLiquidity", - docs: [ - "Withdraw tokens from the pool in a balanced ratio. User will still able to withdraw from pool even the pool is disabled. This allow user to exit their liquidity when there's some unforeseen event happen.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "userPoolLp", - isMut: true, - isSigner: false, - docs: [ - "user pool lp token account. lp will be burned from this account upon success liquidity removal.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "userAToken", - isMut: true, - isSigner: false, - docs: [ - "User token A account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "userBToken", - isMut: true, - isSigner: false, - docs: [ - "User token B account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: [ - "User account. Must be owner of user_a_token, and user_b_token.", - ], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "poolTokenAmount", - type: "u64", - }, - { - name: "minimumATokenOut", - type: "u64", - }, - { - name: "minimumBTokenOut", - type: "u64", - }, - ], - }, - { - name: "addBalanceLiquidity", - docs: ["Deposit tokens to the pool in a balanced ratio."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "userPoolLp", - isMut: true, - isSigner: false, - docs: [ - "user pool lp token account. lp will be burned from this account upon success liquidity removal.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "userAToken", - isMut: true, - isSigner: false, - docs: [ - "User token A account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "userBToken", - isMut: true, - isSigner: false, - docs: [ - "User token B account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: [ - "User account. Must be owner of user_a_token, and user_b_token.", - ], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "poolTokenAmount", - type: "u64", - }, - { - name: "maximumTokenAAmount", - type: "u64", - }, - { - name: "maximumTokenBAmount", - type: "u64", - }, - ], - }, - { - name: "setPoolFees", - docs: ["Update trading fee charged for liquidity provider, and admin."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "admin", - isMut: false, - isSigner: true, - docs: ["Admin account. Must be owner of the pool."], - }, - ], - args: [ - { - name: "fees", - type: { - defined: "PoolFees", - }, - }, - ], - }, - { - name: "overrideCurveParam", - docs: [ - "Update swap curve parameters. This function do not allow update of curve type. For example: stable swap curve to constant product curve. Only supported by pool with stable swap curve.", - "Only amp is allowed to be override. The other attributes of stable swap curve will be ignored.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "admin", - isMut: false, - isSigner: true, - docs: ["Admin account. Must be owner of the pool."], - }, - ], - args: [ - { - name: "curveType", - type: { - defined: "CurveType", - }, - }, - ], - }, - { - name: "transferAdmin", - docs: ["Transfer the admin of the pool to new admin."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "admin", - isMut: false, - isSigner: true, - docs: ["Admin account. Must be owner of the pool."], - }, - { - name: "newAdmin", - isMut: false, - isSigner: true, - docs: ["New admin account."], - }, - ], - args: [], - }, - { - name: "getPoolInfo", - docs: ["Get the general information of the pool."], - accounts: [ - { - name: "pool", - isMut: false, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "aVaultLp", - isMut: false, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: false, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: false, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: false, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - ], - args: [], - }, - { - name: "bootstrapLiquidity", - docs: ["Bootstrap the pool when liquidity is depleted."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "userPoolLp", - isMut: true, - isSigner: false, - docs: [ - "user pool lp token account. lp will be burned from this account upon success liquidity removal.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "userAToken", - isMut: true, - isSigner: false, - docs: [ - "User token A account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "userBToken", - isMut: true, - isSigner: false, - docs: [ - "User token B account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: [ - "User account. Must be owner of user_a_token, and user_b_token.", - ], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "tokenAAmount", - type: "u64", - }, - { - name: "tokenBAmount", - type: "u64", - }, - ], - }, - { - name: "createMintMetadata", - docs: ["Create mint metadata account for old pools"], - accounts: [ - { - name: "pool", - isMut: false, - isSigner: false, - docs: ["Pool account"], - }, - { - name: "lpMint", - isMut: false, - isSigner: false, - docs: ["LP mint account of the pool"], - }, - { - name: "aVaultLp", - isMut: false, - isSigner: false, - docs: ["Vault A LP account of the pool"], - }, - { - name: "mintMetadata", - isMut: true, - isSigner: false, - }, - { - name: "metadataProgram", - isMut: false, - isSigner: false, - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - { - name: "payer", - isMut: true, - isSigner: true, - docs: ["Payer"], - }, - ], - args: [], - }, - { - name: "createLockEscrow", - docs: ["Create lock account"], - accounts: [ - { - name: "pool", - isMut: false, - isSigner: false, - docs: ["Pool account"], - }, - { - name: "lockEscrow", - isMut: true, - isSigner: false, - docs: ["Lock account"], - }, - { - name: "owner", - isMut: false, - isSigner: false, - }, - { - name: "lpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "payer", - isMut: true, - isSigner: true, - docs: ["Payer account"], - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - ], - args: [], - }, - { - name: "lock", - docs: ["Lock Lp token"], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account"], - }, - { - name: "lpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "lockEscrow", - isMut: true, - isSigner: false, - docs: ["Lock account"], - }, - { - name: "owner", - isMut: true, - isSigner: true, - docs: ["Owner of lock account"], - }, - { - name: "sourceTokens", - isMut: true, - isSigner: false, - docs: ["owner lp token account"], - }, - { - name: "escrowVault", - isMut: true, - isSigner: false, - docs: ["Escrow vault"], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "aVault", - isMut: false, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: false, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLp", - isMut: false, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: false, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVaultLpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - ], - args: [ - { - name: "maxAmount", - type: "u64", - }, - ], - }, - { - name: "claimFee", - docs: ["Claim fee"], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "lockEscrow", - isMut: true, - isSigner: false, - docs: ["Lock account"], - }, - { - name: "owner", - isMut: true, - isSigner: true, - docs: ["Owner of lock account"], - }, - { - name: "sourceTokens", - isMut: true, - isSigner: false, - docs: ["owner lp token account"], - }, - { - name: "escrowVault", - isMut: true, - isSigner: false, - docs: ["Escrow vault"], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - { - name: "userAToken", - isMut: true, - isSigner: false, - docs: [ - "User token A account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "userBToken", - isMut: true, - isSigner: false, - docs: [ - "User token B account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - ], - args: [ - { - name: "maxAmount", - type: "u64", - }, - ], - }, - { - name: "createConfig", - docs: ["Create config"], - accounts: [ - { - name: "config", - isMut: true, - isSigner: false, - }, - { - name: "admin", - isMut: true, - isSigner: true, - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - }, - ], - args: [ - { - name: "configParameters", - type: { - defined: "ConfigParameters", - }, - }, - ], - }, - { - name: "closeConfig", - docs: ["Close config"], - accounts: [ - { - name: "config", - isMut: true, - isSigner: false, - }, - { - name: "admin", - isMut: true, - isSigner: true, - }, - { - name: "rentReceiver", - isMut: true, - isSigner: false, - }, - ], - args: [], - }, - { - name: "initializePermissionlessConstantProductPoolWithConfig", - docs: ["Initialize permissionless pool with config"], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA address)"], - }, - { - name: "config", - isMut: false, - isSigner: false, - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "tokenAMint", - isMut: false, - isSigner: false, - docs: ["Token A mint of the pool. Eg: USDT"], - }, - { - name: "tokenBMint", - isMut: false, - isSigner: false, - docs: ["Token B mint of the pool. Eg: USDC"], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault A"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault B"], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "payerTokenA", - isMut: true, - isSigner: false, - docs: [ - "Payer token account for pool token A mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerTokenB", - isMut: true, - isSigner: false, - docs: [ - "Admin token account for pool token B mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerPoolLp", - isMut: true, - isSigner: false, - }, - { - name: "protocolTokenAFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token A. Used to receive trading fee.", - ], - }, - { - name: "protocolTokenBFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token B. Used to receive trading fee.", - ], - }, - { - name: "payer", - isMut: true, - isSigner: true, - docs: [ - "Admin account. This account will be the admin of the pool, and the payer for PDA during initialize pool.", - ], - }, - { - name: "rent", - isMut: false, - isSigner: false, - docs: ["Rent account."], - }, - { - name: "mintMetadata", - isMut: true, - isSigner: false, - }, - { - name: "metadataProgram", - isMut: false, - isSigner: false, - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. The pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "associatedTokenProgram", - isMut: false, - isSigner: false, - docs: ["Associated token program."], - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - ], - args: [ - { - name: "tokenAAmount", - type: "u64", - }, - { - name: "tokenBAmount", - type: "u64", - }, - ], - }, - ], - accounts: [ - { - name: "config", - type: { - kind: "struct", - fields: [ - { - name: "poolFees", - type: { - defined: "PoolFees", - }, - }, - { - name: "activationDurationInSlot", - type: "u64", - }, - { - name: "vaultConfigKey", - type: "publicKey", - }, - { - name: "padding", - type: { - array: ["u8", 260], - }, - }, - ], - }, - }, - { - name: "lockEscrow", - docs: ["State of lock escrow account"], - type: { - kind: "struct", - fields: [ - { - name: "pool", - docs: ["Pool address"], - type: "publicKey", - }, - { - name: "owner", - docs: ["Owner address"], - type: "publicKey", - }, - { - name: "escrowVault", - docs: ["Vault address, store the lock user lock"], - type: "publicKey", - }, - { - name: "bump", - docs: ["bump, used to sign"], - type: "u8", - }, - { - name: "totalLockedAmount", - docs: ["Total locked amount"], - type: "u64", - }, - { - name: "lpPerToken", - docs: ["Lp per token, virtual price of lp token"], - type: "u128", - }, - { - name: "unclaimedFeePending", - docs: ["Unclaimed fee pending"], - type: "u64", - }, - { - name: "aFee", - docs: ["Total a fee claimed so far"], - type: "u64", - }, - { - name: "bFee", - docs: ["Total b fee claimed so far"], - type: "u64", - }, - ], - }, - }, - { - name: "pool", - docs: ["State of pool account"], - type: { - kind: "struct", - fields: [ - { - name: "lpMint", - docs: ["LP token mint of the pool"], - type: "publicKey", - }, - { - name: "tokenAMint", - docs: ["Token A mint of the pool. Eg: USDT"], - type: "publicKey", - }, - { - name: "tokenBMint", - docs: ["Token B mint of the pool. Eg: USDC"], - type: "publicKey", - }, - { - name: "aVault", - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - type: "publicKey", - }, - { - name: "bVault", - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - type: "publicKey", - }, - { - name: "aVaultLp", - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - type: "publicKey", - }, - { - name: "bVaultLp", - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - type: "publicKey", - }, - { - name: "aVaultLpBump", - docs: ['"A" vault lp bump. Used to create signer seeds.'], - type: "u8", - }, - { - name: "enabled", - docs: [ - "Flag to determine whether the pool is enabled, or disabled.", - ], - type: "bool", - }, - { - name: "protocolTokenAFee", - docs: [ - "Protocol fee token account for token A. Used to receive trading fee.", - ], - type: "publicKey", - }, - { - name: "protocolTokenBFee", - docs: [ - "Protocol fee token account for token B. Used to receive trading fee.", - ], - type: "publicKey", - }, - { - name: "admin", - docs: ["Owner of the pool."], - type: "publicKey", - }, - { - name: "fees", - docs: ["Store the fee charges setting."], - type: { - defined: "PoolFees", - }, - }, - { - name: "poolType", - docs: ["Pool type"], - type: { - defined: "PoolType", - }, - }, - { - name: "stake", - docs: ["Stake pubkey of SPL stake pool"], - type: "publicKey", - }, - { - name: "totalLockedLp", - docs: ["Total locked lp token"], - type: "u64", - }, - { - name: "alphaVault", - docs: ["Alpha vault config"], - type: { - defined: "AlphaVault", - }, - }, - { - name: "padding", - docs: ["Padding for future pool field"], - type: { - defined: "Padding", - }, - }, - { - name: "curveType", - docs: ["The type of the swap curve supported by the pool."], - type: { - defined: "CurveType", - }, - }, - ], - }, - }, - ], - types: [ - { - name: "TokenMultiplier", - docs: [ - "Multiplier for the pool token. Used to normalized token with different decimal into the same precision.", - ], - type: { - kind: "struct", - fields: [ - { - name: "tokenAMultiplier", - docs: ["Multiplier for token A of the pool."], - type: "u64", - }, - { - name: "tokenBMultiplier", - docs: ["Multiplier for token B of the pool."], - type: "u64", - }, - { - name: "precisionFactor", - docs: [ - "Record the highest token decimal in the pool. For example, Token A is 6 decimal, token B is 9 decimal. This will save value of 9.", - ], - type: "u8", - }, - ], - }, - }, - { - name: "PoolFees", - docs: ["Information regarding fee charges"], - type: { - kind: "struct", - fields: [ - { - name: "tradeFeeNumerator", - docs: [ - "Trade fees are extra token amounts that are held inside the token", - "accounts during a trade, making the value of liquidity tokens rise.", - "Trade fee numerator", - ], - type: "u64", - }, - { - name: "tradeFeeDenominator", - docs: ["Trade fee denominator"], - type: "u64", - }, - { - name: "protocolTradeFeeNumerator", - docs: [ - "Protocol trading fees are extra token amounts that are held inside the token", - "accounts during a trade, with the equivalent in pool tokens minted to", - "the protocol of the program.", - "Protocol trade fee numerator", - ], - type: "u64", - }, - { - name: "protocolTradeFeeDenominator", - docs: ["Protocol trade fee denominator"], - type: "u64", - }, - ], - }, - }, - { - name: "Depeg", - docs: ["Contains information for depeg pool"], - type: { - kind: "struct", - fields: [ - { - name: "baseVirtualPrice", - docs: ["The virtual price of staking / interest bearing token"], - type: "u64", - }, - { - name: "baseCacheUpdated", - docs: ["The virtual price of staking / interest bearing token"], - type: "u64", - }, - { - name: "depegType", - docs: ["Type of the depeg pool"], - type: { - defined: "DepegType", - }, - }, - ], - }, - }, - { - name: "ConfigParameters", - type: { - kind: "struct", - fields: [ - { - name: "tradeFeeNumerator", - type: "u64", - }, - { - name: "protocolTradeFeeNumerator", - type: "u64", - }, - { - name: "activationDurationInSlot", - type: "u64", - }, - { - name: "vaultConfigKey", - type: "publicKey", - }, - { - name: "index", - type: "u64", - }, - ], - }, - }, - { - name: "Padding", - docs: ["Padding for future pool fields"], - type: { - kind: "struct", - fields: [ - { - name: "padding0", - docs: ["Padding 0"], - type: { - array: ["u8", 15], - }, - }, - { - name: "padding", - docs: ["Padding 1"], - type: { - array: ["u128", 24], - }, - }, - ], - }, - }, - { - name: "AlphaVault", - type: { - kind: "struct", - fields: [ - { - name: "activationSlot", - docs: ["Activation slot"], - type: "u64", - }, - { - name: "whitelistedVault", - docs: ["Whitelisted vault to be able to buy pool before open slot"], - type: "publicKey", - }, - { - name: "poolCreator", - docs: [ - "Need to store pool creator in lauch pool, so they can modify liquidity before activation slot", - ], - type: "publicKey", - }, - ], - }, - }, - { - name: "RoundDirection", - docs: ["Rounding direction"], - type: { - kind: "enum", - variants: [ - { - name: "Floor", - }, - { - name: "Ceiling", - }, - ], - }, - }, - { - name: "TradeDirection", - docs: ["Trade (swap) direction"], - type: { - kind: "enum", - variants: [ - { - name: "AtoB", - }, - { - name: "BtoA", - }, - ], - }, - }, - { - name: "NewCurveType", - docs: ["Type of the swap curve"], - type: { - kind: "enum", - variants: [ - { - name: "ConstantProduct", - }, - { - name: "Stable", - fields: [ - { - name: "amp", - docs: ["Amplification coefficient"], - type: "u64", - }, - { - name: "token_multiplier", - docs: [ - "Multiplier for the pool token. Used to normalized token with different decimal into the same precision.", - ], - type: { - defined: "TokenMultiplier", - }, - }, - { - name: "depeg", - docs: [ - "Depeg pool information. Contains functions to allow token amount to be repeg using stake / interest bearing token virtual price", - ], - type: { - defined: "Depeg", - }, - }, - { - name: "last_amp_updated_timestamp", - docs: [ - "The last amp updated timestamp. Used to prevent update_curve_info called infinitely many times within a short period", - ], - type: "u64", - }, - ], - }, - { - name: "NewCurve", - fields: [ - { - name: "field_one", - type: "u64", - }, - { - name: "field_two", - type: "u64", - }, - ], - }, - ], - }, - }, - { - name: "CurveType", - docs: ["Type of the swap curve"], - type: { - kind: "enum", - variants: [ - { - name: "ConstantProduct", - }, - { - name: "Stable", - fields: [ - { - name: "amp", - docs: ["Amplification coefficient"], - type: "u64", - }, - { - name: "token_multiplier", - docs: [ - "Multiplier for the pool token. Used to normalized token with different decimal into the same precision.", - ], - type: { - defined: "TokenMultiplier", - }, - }, - { - name: "depeg", - docs: [ - "Depeg pool information. Contains functions to allow token amount to be repeg using stake / interest bearing token virtual price", - ], - type: { - defined: "Depeg", - }, - }, - { - name: "last_amp_updated_timestamp", - docs: [ - "The last amp updated timestamp. Used to prevent update_curve_info called infinitely many times within a short period", - ], - type: "u64", - }, - ], - }, - ], - }, - }, - { - name: "DepegType", - docs: ["Type of depeg pool"], - type: { - kind: "enum", - variants: [ - { - name: "None", - }, - { - name: "Marinade", - }, - { - name: "Lido", - }, - { - name: "SplStake", - }, - ], - }, - }, - { - name: "Rounding", - docs: ["Round up, down"], - type: { - kind: "enum", - variants: [ - { - name: "Up", - }, - { - name: "Down", - }, - ], - }, - }, - { - name: "PoolType", - docs: ["Pool type"], - type: { - kind: "enum", - variants: [ - { - name: "Permissioned", - }, - { - name: "Permissionless", - }, - ], - }, - }, - ], - events: [ - { - name: "AddLiquidity", - fields: [ - { - name: "lpMintAmount", - type: "u64", - index: false, - }, - { - name: "tokenAAmount", - type: "u64", - index: false, - }, - { - name: "tokenBAmount", - type: "u64", - index: false, - }, - ], - }, - { - name: "RemoveLiquidity", - fields: [ - { - name: "lpUnmintAmount", - type: "u64", - index: false, - }, - { - name: "tokenAOutAmount", - type: "u64", - index: false, - }, - { - name: "tokenBOutAmount", - type: "u64", - index: false, - }, - ], - }, - { - name: "BootstrapLiquidity", - fields: [ - { - name: "lpMintAmount", - type: "u64", - index: false, - }, - { - name: "tokenAAmount", - type: "u64", - index: false, - }, - { - name: "tokenBAmount", - type: "u64", - index: false, - }, - { - name: "pool", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "Swap", - fields: [ - { - name: "inAmount", - type: "u64", - index: false, - }, - { - name: "outAmount", - type: "u64", - index: false, - }, - { - name: "tradeFee", - type: "u64", - index: false, - }, - { - name: "protocolFee", - type: "u64", - index: false, - }, - { - name: "hostFee", - type: "u64", - index: false, - }, - ], - }, - { - name: "SetPoolFees", - fields: [ - { - name: "tradeFeeNumerator", - type: "u64", - index: false, - }, - { - name: "tradeFeeDenominator", - type: "u64", - index: false, - }, - { - name: "protocolTradeFeeNumerator", - type: "u64", - index: false, - }, - { - name: "protocolTradeFeeDenominator", - type: "u64", - index: false, - }, - { - name: "pool", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "PoolInfo", - fields: [ - { - name: "tokenAAmount", - type: "u64", - index: false, - }, - { - name: "tokenBAmount", - type: "u64", - index: false, - }, - { - name: "virtualPrice", - type: "f64", - index: false, - }, - { - name: "currentTimestamp", - type: "u64", - index: false, - }, - ], - }, - { - name: "TransferAdmin", - fields: [ - { - name: "admin", - type: "publicKey", - index: false, - }, - { - name: "newAdmin", - type: "publicKey", - index: false, - }, - { - name: "pool", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "OverrideCurveParam", - fields: [ - { - name: "newAmp", - type: "u64", - index: false, - }, - { - name: "updatedTimestamp", - type: "u64", - index: false, - }, - { - name: "pool", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "PoolCreated", - fields: [ - { - name: "lpMint", - type: "publicKey", - index: false, - }, - { - name: "tokenAMint", - type: "publicKey", - index: false, - }, - { - name: "tokenBMint", - type: "publicKey", - index: false, - }, - { - name: "poolType", - type: { - defined: "PoolType", - }, - index: false, - }, - { - name: "pool", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "PoolEnabled", - fields: [ - { - name: "pool", - type: "publicKey", - index: false, - }, - { - name: "enabled", - type: "bool", - index: false, - }, - ], - }, - { - name: "MigrateFeeAccount", - fields: [ - { - name: "pool", - type: "publicKey", - index: false, - }, - { - name: "newAdminTokenAFee", - type: "publicKey", - index: false, - }, - { - name: "newAdminTokenBFee", - type: "publicKey", - index: false, - }, - { - name: "tokenAAmount", - type: "u64", - index: false, - }, - { - name: "tokenBAmount", - type: "u64", - index: false, - }, - ], - }, - { - name: "CreateLockEscrow", - fields: [ - { - name: "pool", - type: "publicKey", - index: false, - }, - { - name: "owner", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "Lock", - fields: [ - { - name: "pool", - type: "publicKey", - index: false, - }, - { - name: "owner", - type: "publicKey", - index: false, - }, - { - name: "amount", - type: "u64", - index: false, - }, - ], - }, - { - name: "ClaimFee", - fields: [ - { - name: "pool", - type: "publicKey", - index: false, - }, - { - name: "owner", - type: "publicKey", - index: false, - }, - { - name: "amount", - type: "u64", - index: false, - }, - { - name: "aFee", - type: "u64", - index: false, - }, - { - name: "bFee", - type: "u64", - index: false, - }, - ], - }, - { - name: "CreateConfig", - fields: [ - { - name: "tradeFeeNumerator", - type: "u64", - index: false, - }, - { - name: "protocolTradeFeeNumerator", - type: "u64", - index: false, - }, - { - name: "config", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "CloseConfig", - fields: [ - { - name: "config", - type: "publicKey", - index: false, - }, - ], - }, - ], - errors: [ - { - code: 6000, - name: "MathOverflow", - msg: "Math operation overflow", - }, - { - code: 6001, - name: "InvalidFee", - msg: "Invalid fee setup", - }, - { - code: 6002, - name: "InvalidInvariant", - msg: "Invalid invariant d", - }, - { - code: 6003, - name: "FeeCalculationFailure", - msg: "Fee calculation failure", - }, - { - code: 6004, - name: "ExceededSlippage", - msg: "Exceeded slippage tolerance", - }, - { - code: 6005, - name: "InvalidCalculation", - msg: "Invalid curve calculation", - }, - { - code: 6006, - name: "ZeroTradingTokens", - msg: "Given pool token amount results in zero trading tokens", - }, - { - code: 6007, - name: "ConversionError", - msg: "Math conversion overflow", - }, - { - code: 6008, - name: "FaultyLpMint", - msg: "LP mint authority must be 'A' vault lp, without freeze authority, and 0 supply", - }, - { - code: 6009, - name: "MismatchedTokenMint", - msg: "Token mint mismatched", - }, - { - code: 6010, - name: "MismatchedLpMint", - msg: "LP mint mismatched", - }, - { - code: 6011, - name: "MismatchedOwner", - msg: "Invalid lp token owner", - }, - { - code: 6012, - name: "InvalidVaultAccount", - msg: "Invalid vault account", - }, - { - code: 6013, - name: "InvalidVaultLpAccount", - msg: "Invalid vault lp account", - }, - { - code: 6014, - name: "InvalidPoolLpMintAccount", - msg: "Invalid pool lp mint account", - }, - { - code: 6015, - name: "PoolDisabled", - msg: "Pool disabled", - }, - { - code: 6016, - name: "InvalidAdminAccount", - msg: "Invalid admin account", - }, - { - code: 6017, - name: "InvalidProtocolFeeAccount", - msg: "Invalid protocol fee account", - }, - { - code: 6018, - name: "SameAdminAccount", - msg: "Same admin account", - }, - { - code: 6019, - name: "IdenticalSourceDestination", - msg: "Identical user source and destination token account", - }, - { - code: 6020, - name: "ApyCalculationError", - msg: "Apy calculation error", - }, - { - code: 6021, - name: "InsufficientSnapshot", - msg: "Insufficient virtual price snapshot", - }, - { - code: 6022, - name: "NonUpdatableCurve", - msg: "Current curve is non-updatable", - }, - { - code: 6023, - name: "MisMatchedCurve", - msg: "New curve is mismatched with old curve", - }, - { - code: 6024, - name: "InvalidAmplification", - msg: "Amplification is invalid", - }, - { - code: 6025, - name: "UnsupportedOperation", - msg: "Operation is not supported", - }, - { - code: 6026, - name: "ExceedMaxAChanges", - msg: "Exceed max amplification changes", - }, - { - code: 6027, - name: "InvalidRemainingAccountsLen", - msg: "Invalid remaining accounts length", - }, - { - code: 6028, - name: "InvalidRemainingAccounts", - msg: "Invalid remaining account", - }, - { - code: 6029, - name: "MismatchedDepegMint", - msg: "Token mint B doesn't matches depeg type token mint", - }, - { - code: 6030, - name: "InvalidApyAccount", - msg: "Invalid APY account", - }, - { - code: 6031, - name: "InvalidTokenMultiplier", - msg: "Invalid token multiplier", - }, - { - code: 6032, - name: "InvalidDepegInformation", - msg: "Invalid depeg information", - }, - { - code: 6033, - name: "UpdateTimeConstraint", - msg: "Update time constraint violated", - }, - { - code: 6034, - name: "ExceedMaxFeeBps", - msg: "Exceeded max fee bps", - }, - { - code: 6035, - name: "InvalidAdmin", - msg: "Invalid admin", - }, - { - code: 6036, - name: "PoolIsNotPermissioned", - msg: "Pool is not permissioned", - }, - { - code: 6037, - name: "InvalidDepositAmount", - msg: "Invalid deposit amount", - }, - { - code: 6038, - name: "InvalidFeeOwner", - msg: "Invalid fee owner", - }, - { - code: 6039, - name: "NonDepletedPool", - msg: "Pool is not depleted", - }, - { - code: 6040, - name: "AmountNotPeg", - msg: "Token amount is not 1:1", - }, - { - code: 6041, - name: "AmountIsZero", - msg: "Amount is zero", - }, - { - code: 6042, - name: "TypeCastFailed", - msg: "Type cast error", - }, - { - code: 6043, - name: "AmountIsNotEnough", - msg: "Amount is not enough", - }, - { - code: 6044, - name: "InvalidActivationSlotInDuration", - msg: "Invalid activation slot in duration", - }, - ], -}; - -const IDL = { - version: "0.4.12", - name: "amm", - docs: ["Program for AMM"], - instructions: [ - { - name: "initializePermissionedPool", - docs: ["Initialize a new permissioned pool."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: true, - docs: ["Pool account (arbitrary address)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "tokenAMint", - isMut: false, - isSigner: false, - docs: ["Token A mint of the pool. Eg: USDT"], - }, - { - name: "tokenBMint", - isMut: false, - isSigner: false, - docs: ["Token B mint of the pool. Eg: USDC"], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault A"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault B"], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "adminTokenA", - isMut: true, - isSigner: false, - docs: [ - "Admin token account for pool token A mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "adminTokenB", - isMut: true, - isSigner: false, - docs: [ - "Admin token account for pool token B mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "adminPoolLp", - isMut: true, - isSigner: false, - docs: [ - "Admin pool LP token account. Used to receive LP during first deposit (initialize pool)", - "Admin pool LP token account. Used to receive LP during first deposit (initialize pool)", - ], - }, - { - name: "protocolTokenAFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token A. Used to receive trading fee.", - ], - }, - { - name: "protocolTokenBFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token B. Used to receive trading fee.", - ], - }, - { - name: "admin", - isMut: true, - isSigner: true, - docs: [ - "Admin account. This account will be the admin of the pool, and the payer for PDA during initialize pool.", - ], - }, - { - name: "feeOwner", - isMut: false, - isSigner: false, - }, - { - name: "rent", - isMut: false, - isSigner: false, - docs: ["Rent account."], - }, - { - name: "mintMetadata", - isMut: true, - isSigner: false, - }, - { - name: "metadataProgram", - isMut: false, - isSigner: false, - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. The pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "associatedTokenProgram", - isMut: false, - isSigner: false, - docs: ["Associated token program."], - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - ], - args: [ - { - name: "curveType", - type: { - defined: "CurveType", - }, - }, - ], - }, - { - name: "initializePermissionlessPool", - docs: ["Initialize a new permissionless pool."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA address)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "tokenAMint", - isMut: false, - isSigner: false, - docs: ["Token A mint of the pool. Eg: USDT"], - }, - { - name: "tokenBMint", - isMut: false, - isSigner: false, - docs: ["Token B mint of the pool. Eg: USDC"], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault A"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault B"], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "payerTokenA", - isMut: true, - isSigner: false, - docs: [ - "Payer token account for pool token A mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerTokenB", - isMut: true, - isSigner: false, - docs: [ - "Admin token account for pool token B mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerPoolLp", - isMut: true, - isSigner: false, - }, - { - name: "protocolTokenAFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token A. Used to receive trading fee.", - ], - }, - { - name: "protocolTokenBFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token B. Used to receive trading fee.", - ], - }, - { - name: "payer", - isMut: true, - isSigner: true, - docs: [ - "Admin account. This account will be the admin of the pool, and the payer for PDA during initialize pool.", - ], - }, - { - name: "feeOwner", - isMut: false, - isSigner: false, - }, - { - name: "rent", - isMut: false, - isSigner: false, - docs: ["Rent account."], - }, - { - name: "mintMetadata", - isMut: true, - isSigner: false, - }, - { - name: "metadataProgram", - isMut: false, - isSigner: false, - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. The pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "associatedTokenProgram", - isMut: false, - isSigner: false, - docs: ["Associated token program."], - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - ], - args: [ - { - name: "curveType", - type: { - defined: "CurveType", - }, - }, - { - name: "tokenAAmount", - type: "u64", - }, - { - name: "tokenBAmount", - type: "u64", - }, - ], - }, - { - name: "initializePermissionlessPoolWithFeeTier", - docs: ["Initialize a new permissionless pool with customized fee tier"], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA address)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "tokenAMint", - isMut: false, - isSigner: false, - docs: ["Token A mint of the pool. Eg: USDT"], - }, - { - name: "tokenBMint", - isMut: false, - isSigner: false, - docs: ["Token B mint of the pool. Eg: USDC"], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault A"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault B"], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "payerTokenA", - isMut: true, - isSigner: false, - docs: [ - "Payer token account for pool token A mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerTokenB", - isMut: true, - isSigner: false, - docs: [ - "Admin token account for pool token B mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerPoolLp", - isMut: true, - isSigner: false, - }, - { - name: "protocolTokenAFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token A. Used to receive trading fee.", - ], - }, - { - name: "protocolTokenBFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token B. Used to receive trading fee.", - ], - }, - { - name: "payer", - isMut: true, - isSigner: true, - docs: [ - "Admin account. This account will be the admin of the pool, and the payer for PDA during initialize pool.", - ], - }, - { - name: "feeOwner", - isMut: false, - isSigner: false, - }, - { - name: "rent", - isMut: false, - isSigner: false, - docs: ["Rent account."], - }, - { - name: "mintMetadata", - isMut: true, - isSigner: false, - }, - { - name: "metadataProgram", - isMut: false, - isSigner: false, - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. The pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "associatedTokenProgram", - isMut: false, - isSigner: false, - docs: ["Associated token program."], - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - ], - args: [ - { - name: "curveType", - type: { - defined: "CurveType", - }, - }, - { - name: "tradeFeeBps", - type: "u64", - }, - { - name: "tokenAAmount", - type: "u64", - }, - { - name: "tokenBAmount", - type: "u64", - }, - ], - }, - { - name: "enableOrDisablePool", - docs: [ - "Enable or disable a pool. A disabled pool allow only remove balanced liquidity operation.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "admin", - isMut: false, - isSigner: true, - docs: ["Admin account. Must be owner of the pool."], - }, - ], - args: [ - { - name: "enable", - type: "bool", - }, - ], - }, - { - name: "swap", - docs: [ - "Swap token A to B, or vice versa. An amount of trading fee will be charged for liquidity provider, and the admin of the pool.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "userSourceToken", - isMut: true, - isSigner: false, - docs: [ - "User token account. Token from this account will be transfer into the vault by the pool in exchange for another token of the pool.", - ], - }, - { - name: "userDestinationToken", - isMut: true, - isSigner: false, - docs: [ - "User token account. The exchanged token will be transfer into this account from the pool.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["Lp token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["Lp token mint of vault b"], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "protocolTokenFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account. Used to receive trading fee. It's mint field must matched with user_source_token mint field.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: ["User account. Must be owner of user_source_token."], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "inAmount", - type: "u64", - }, - { - name: "minimumOutAmount", - type: "u64", - }, - ], - }, - { - name: "removeLiquiditySingleSide", - docs: [ - "Withdraw only single token from the pool. Only supported by pool with stable swap curve.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "userPoolLp", - isMut: true, - isSigner: false, - docs: [ - "User pool lp token account. LP will be burned from this account upon success liquidity removal.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault A"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault B"], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "userDestinationToken", - isMut: true, - isSigner: false, - docs: [ - "User token account to receive token upon success liquidity removal.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: ["User account. Must be owner of the user_pool_lp account."], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. The pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "poolTokenAmount", - type: "u64", - }, - { - name: "minimumOutAmount", - type: "u64", - }, - ], - }, - { - name: "addImbalanceLiquidity", - docs: [ - "Deposit tokens to the pool in an imbalance ratio. Only supported by pool with stable swap curve.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "userPoolLp", - isMut: true, - isSigner: false, - docs: [ - "user pool lp token account. lp will be burned from this account upon success liquidity removal.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "userAToken", - isMut: true, - isSigner: false, - docs: [ - "User token A account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "userBToken", - isMut: true, - isSigner: false, - docs: [ - "User token B account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: [ - "User account. Must be owner of user_a_token, and user_b_token.", - ], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "minimumPoolTokenAmount", - type: "u64", - }, - { - name: "tokenAAmount", - type: "u64", - }, - { - name: "tokenBAmount", - type: "u64", - }, - ], - }, - { - name: "removeBalanceLiquidity", - docs: [ - "Withdraw tokens from the pool in a balanced ratio. User will still able to withdraw from pool even the pool is disabled. This allow user to exit their liquidity when there's some unforeseen event happen.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "userPoolLp", - isMut: true, - isSigner: false, - docs: [ - "user pool lp token account. lp will be burned from this account upon success liquidity removal.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "userAToken", - isMut: true, - isSigner: false, - docs: [ - "User token A account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "userBToken", - isMut: true, - isSigner: false, - docs: [ - "User token B account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: [ - "User account. Must be owner of user_a_token, and user_b_token.", - ], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "poolTokenAmount", - type: "u64", - }, - { - name: "minimumATokenOut", - type: "u64", - }, - { - name: "minimumBTokenOut", - type: "u64", - }, - ], - }, - { - name: "addBalanceLiquidity", - docs: ["Deposit tokens to the pool in a balanced ratio."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "userPoolLp", - isMut: true, - isSigner: false, - docs: [ - "user pool lp token account. lp will be burned from this account upon success liquidity removal.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "userAToken", - isMut: true, - isSigner: false, - docs: [ - "User token A account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "userBToken", - isMut: true, - isSigner: false, - docs: [ - "User token B account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: [ - "User account. Must be owner of user_a_token, and user_b_token.", - ], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "poolTokenAmount", - type: "u64", - }, - { - name: "maximumTokenAAmount", - type: "u64", - }, - { - name: "maximumTokenBAmount", - type: "u64", - }, - ], - }, - { - name: "setPoolFees", - docs: ["Update trading fee charged for liquidity provider, and admin."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "admin", - isMut: false, - isSigner: true, - docs: ["Admin account. Must be owner of the pool."], - }, - ], - args: [ - { - name: "fees", - type: { - defined: "PoolFees", - }, - }, - ], - }, - { - name: "overrideCurveParam", - docs: [ - "Update swap curve parameters. This function do not allow update of curve type. For example: stable swap curve to constant product curve. Only supported by pool with stable swap curve.", - "Only amp is allowed to be override. The other attributes of stable swap curve will be ignored.", - ], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "admin", - isMut: false, - isSigner: true, - docs: ["Admin account. Must be owner of the pool."], - }, - ], - args: [ - { - name: "curveType", - type: { - defined: "CurveType", - }, - }, - ], - }, - { - name: "transferAdmin", - docs: ["Transfer the admin of the pool to new admin."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "admin", - isMut: false, - isSigner: true, - docs: ["Admin account. Must be owner of the pool."], - }, - { - name: "newAdmin", - isMut: false, - isSigner: true, - docs: ["New admin account."], - }, - ], - args: [], - }, - { - name: "getPoolInfo", - docs: ["Get the general information of the pool."], - accounts: [ - { - name: "pool", - isMut: false, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "aVaultLp", - isMut: false, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: false, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: false, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: false, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - ], - args: [], - }, - { - name: "bootstrapLiquidity", - docs: ["Bootstrap the pool when liquidity is depleted."], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA)"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "userPoolLp", - isMut: true, - isSigner: false, - docs: [ - "user pool lp token account. lp will be burned from this account upon success liquidity removal.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "userAToken", - isMut: true, - isSigner: false, - docs: [ - "User token A account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "userBToken", - isMut: true, - isSigner: false, - docs: [ - "User token B account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "user", - isMut: false, - isSigner: true, - docs: [ - "User account. Must be owner of user_a_token, and user_b_token.", - ], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - ], - args: [ - { - name: "tokenAAmount", - type: "u64", - }, - { - name: "tokenBAmount", - type: "u64", - }, - ], - }, - { - name: "createMintMetadata", - docs: ["Create mint metadata account for old pools"], - accounts: [ - { - name: "pool", - isMut: false, - isSigner: false, - docs: ["Pool account"], - }, - { - name: "lpMint", - isMut: false, - isSigner: false, - docs: ["LP mint account of the pool"], - }, - { - name: "aVaultLp", - isMut: false, - isSigner: false, - docs: ["Vault A LP account of the pool"], - }, - { - name: "mintMetadata", - isMut: true, - isSigner: false, - }, - { - name: "metadataProgram", - isMut: false, - isSigner: false, - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - { - name: "payer", - isMut: true, - isSigner: true, - docs: ["Payer"], - }, - ], - args: [], - }, - { - name: "createLockEscrow", - docs: ["Create lock account"], - accounts: [ - { - name: "pool", - isMut: false, - isSigner: false, - docs: ["Pool account"], - }, - { - name: "lockEscrow", - isMut: true, - isSigner: false, - docs: ["Lock account"], - }, - { - name: "owner", - isMut: false, - isSigner: false, - }, - { - name: "lpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "payer", - isMut: true, - isSigner: true, - docs: ["Payer account"], - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - ], - args: [], - }, - { - name: "lock", - docs: ["Lock Lp token"], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account"], - }, - { - name: "lpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "lockEscrow", - isMut: true, - isSigner: false, - docs: ["Lock account"], - }, - { - name: "owner", - isMut: true, - isSigner: true, - docs: ["Owner of lock account"], - }, - { - name: "sourceTokens", - isMut: true, - isSigner: false, - docs: ["owner lp token account"], - }, - { - name: "escrowVault", - isMut: true, - isSigner: false, - docs: ["Escrow vault"], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "aVault", - isMut: false, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: false, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLp", - isMut: false, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: false, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVaultLpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: false, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - ], - args: [ - { - name: "maxAmount", - type: "u64", - }, - ], - }, - { - name: "claimFee", - docs: ["Claim fee"], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account"], - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "lockEscrow", - isMut: true, - isSigner: false, - docs: ["Lock account"], - }, - { - name: "owner", - isMut: true, - isSigner: true, - docs: ["Owner of lock account"], - }, - { - name: "sourceTokens", - isMut: true, - isSigner: false, - docs: ["owner lp token account"], - }, - { - name: "escrowVault", - isMut: true, - isSigner: false, - docs: ["Escrow vault"], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token a. token a of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token b. token b of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault a"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault b"], - }, - { - name: "userAToken", - isMut: true, - isSigner: false, - docs: [ - "User token A account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "userBToken", - isMut: true, - isSigner: false, - docs: [ - "User token B account. Token will be transfer from this account if it is add liquidity operation. Else, token will be transfer into this account.", - ], - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. the pool will deposit/withdraw liquidity from the vault.", - ], - }, - ], - args: [ - { - name: "maxAmount", - type: "u64", - }, - ], - }, - { - name: "createConfig", - docs: ["Create config"], - accounts: [ - { - name: "config", - isMut: true, - isSigner: false, - }, - { - name: "admin", - isMut: true, - isSigner: true, - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - }, - ], - args: [ - { - name: "configParameters", - type: { - defined: "ConfigParameters", - }, - }, - ], - }, - { - name: "closeConfig", - docs: ["Close config"], - accounts: [ - { - name: "config", - isMut: true, - isSigner: false, - }, - { - name: "admin", - isMut: true, - isSigner: true, - }, - { - name: "rentReceiver", - isMut: true, - isSigner: false, - }, - ], - args: [], - }, - { - name: "initializePermissionlessConstantProductPoolWithConfig", - docs: ["Initialize permissionless pool with config"], - accounts: [ - { - name: "pool", - isMut: true, - isSigner: false, - docs: ["Pool account (PDA address)"], - }, - { - name: "config", - isMut: false, - isSigner: false, - }, - { - name: "lpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of the pool"], - }, - { - name: "tokenAMint", - isMut: false, - isSigner: false, - docs: ["Token A mint of the pool. Eg: USDT"], - }, - { - name: "tokenBMint", - isMut: false, - isSigner: false, - docs: ["Token B mint of the pool. Eg: USDC"], - }, - { - name: "aVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "bVault", - isMut: true, - isSigner: false, - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - }, - { - name: "aTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault A"], - }, - { - name: "bTokenVault", - isMut: true, - isSigner: false, - docs: ["Token vault account of vault B"], - }, - { - name: "aVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault A"], - }, - { - name: "bVaultLpMint", - isMut: true, - isSigner: false, - docs: ["LP token mint of vault B"], - }, - { - name: "aVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "bVaultLp", - isMut: true, - isSigner: false, - docs: [ - "LP token account of vault B. Used to receive/burn vault LP upon deposit/withdraw from the vault.", - ], - }, - { - name: "payerTokenA", - isMut: true, - isSigner: false, - docs: [ - "Payer token account for pool token A mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerTokenB", - isMut: true, - isSigner: false, - docs: [ - "Admin token account for pool token B mint. Used to bootstrap the pool with initial liquidity.", - ], - }, - { - name: "payerPoolLp", - isMut: true, - isSigner: false, - }, - { - name: "protocolTokenAFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token A. Used to receive trading fee.", - ], - }, - { - name: "protocolTokenBFee", - isMut: true, - isSigner: false, - docs: [ - "Protocol fee token account for token B. Used to receive trading fee.", - ], - }, - { - name: "payer", - isMut: true, - isSigner: true, - docs: [ - "Admin account. This account will be the admin of the pool, and the payer for PDA during initialize pool.", - ], - }, - { - name: "rent", - isMut: false, - isSigner: false, - docs: ["Rent account."], - }, - { - name: "mintMetadata", - isMut: true, - isSigner: false, - }, - { - name: "metadataProgram", - isMut: false, - isSigner: false, - }, - { - name: "vaultProgram", - isMut: false, - isSigner: false, - docs: [ - "Vault program. The pool will deposit/withdraw liquidity from the vault.", - ], - }, - { - name: "tokenProgram", - isMut: false, - isSigner: false, - docs: ["Token program."], - }, - { - name: "associatedTokenProgram", - isMut: false, - isSigner: false, - docs: ["Associated token program."], - }, - { - name: "systemProgram", - isMut: false, - isSigner: false, - docs: ["System program."], - }, - ], - args: [ - { - name: "tokenAAmount", - type: "u64", - }, - { - name: "tokenBAmount", - type: "u64", - }, - ], - }, - ], - accounts: [ - { - name: "config", - type: { - kind: "struct", - fields: [ - { - name: "poolFees", - type: { - defined: "PoolFees", - }, - }, - { - name: "activationDurationInSlot", - type: "u64", - }, - { - name: "vaultConfigKey", - type: "publicKey", - }, - { - name: "padding", - type: { - array: ["u8", 260], - }, - }, - ], - }, - }, - { - name: "lockEscrow", - docs: ["State of lock escrow account"], - type: { - kind: "struct", - fields: [ - { - name: "pool", - docs: ["Pool address"], - type: "publicKey", - }, - { - name: "owner", - docs: ["Owner address"], - type: "publicKey", - }, - { - name: "escrowVault", - docs: ["Vault address, store the lock user lock"], - type: "publicKey", - }, - { - name: "bump", - docs: ["bump, used to sign"], - type: "u8", - }, - { - name: "totalLockedAmount", - docs: ["Total locked amount"], - type: "u64", - }, - { - name: "lpPerToken", - docs: ["Lp per token, virtual price of lp token"], - type: "u128", - }, - { - name: "unclaimedFeePending", - docs: ["Unclaimed fee pending"], - type: "u64", - }, - { - name: "aFee", - docs: ["Total a fee claimed so far"], - type: "u64", - }, - { - name: "bFee", - docs: ["Total b fee claimed so far"], - type: "u64", - }, - ], - }, - }, - { - name: "pool", - docs: ["State of pool account"], - type: { - kind: "struct", - fields: [ - { - name: "lpMint", - docs: ["LP token mint of the pool"], - type: "publicKey", - }, - { - name: "tokenAMint", - docs: ["Token A mint of the pool. Eg: USDT"], - type: "publicKey", - }, - { - name: "tokenBMint", - docs: ["Token B mint of the pool. Eg: USDC"], - type: "publicKey", - }, - { - name: "aVault", - docs: [ - "Vault account for token A. Token A of the pool will be deposit / withdraw from this vault account.", - ], - type: "publicKey", - }, - { - name: "bVault", - docs: [ - "Vault account for token B. Token B of the pool will be deposit / withdraw from this vault account.", - ], - type: "publicKey", - }, - { - name: "aVaultLp", - docs: [ - "LP token account of vault A. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - type: "publicKey", - }, - { - name: "bVaultLp", - docs: [ - "LP token account of vault B. Used to receive/burn the vault LP upon deposit/withdraw from the vault.", - ], - type: "publicKey", - }, - { - name: "aVaultLpBump", - docs: ['"A" vault lp bump. Used to create signer seeds.'], - type: "u8", - }, - { - name: "enabled", - docs: [ - "Flag to determine whether the pool is enabled, or disabled.", - ], - type: "bool", - }, - { - name: "protocolTokenAFee", - docs: [ - "Protocol fee token account for token A. Used to receive trading fee.", - ], - type: "publicKey", - }, - { - name: "protocolTokenBFee", - docs: [ - "Protocol fee token account for token B. Used to receive trading fee.", - ], - type: "publicKey", - }, - { - name: "admin", - docs: ["Owner of the pool."], - type: "publicKey", - }, - { - name: "fees", - docs: ["Store the fee charges setting."], - type: { - defined: "PoolFees", - }, - }, - { - name: "poolType", - docs: ["Pool type"], - type: { - defined: "PoolType", - }, - }, - { - name: "stake", - docs: ["Stake pubkey of SPL stake pool"], - type: "publicKey", - }, - { - name: "totalLockedLp", - docs: ["Total locked lp token"], - type: "u64", - }, - { - name: "alphaVault", - docs: ["Alpha vault config"], - type: { - defined: "AlphaVault", - }, - }, - { - name: "padding", - docs: ["Padding for future pool field"], - type: { - defined: "Padding", - }, - }, - { - name: "curveType", - docs: ["The type of the swap curve supported by the pool."], - type: { - defined: "CurveType", - }, - }, - ], - }, - }, - ], - types: [ - { - name: "TokenMultiplier", - docs: [ - "Multiplier for the pool token. Used to normalized token with different decimal into the same precision.", - ], - type: { - kind: "struct", - fields: [ - { - name: "tokenAMultiplier", - docs: ["Multiplier for token A of the pool."], - type: "u64", - }, - { - name: "tokenBMultiplier", - docs: ["Multiplier for token B of the pool."], - type: "u64", - }, - { - name: "precisionFactor", - docs: [ - "Record the highest token decimal in the pool. For example, Token A is 6 decimal, token B is 9 decimal. This will save value of 9.", - ], - type: "u8", - }, - ], - }, - }, - { - name: "PoolFees", - docs: ["Information regarding fee charges"], - type: { - kind: "struct", - fields: [ - { - name: "tradeFeeNumerator", - docs: [ - "Trade fees are extra token amounts that are held inside the token", - "accounts during a trade, making the value of liquidity tokens rise.", - "Trade fee numerator", - ], - type: "u64", - }, - { - name: "tradeFeeDenominator", - docs: ["Trade fee denominator"], - type: "u64", - }, - { - name: "protocolTradeFeeNumerator", - docs: [ - "Protocol trading fees are extra token amounts that are held inside the token", - "accounts during a trade, with the equivalent in pool tokens minted to", - "the protocol of the program.", - "Protocol trade fee numerator", - ], - type: "u64", - }, - { - name: "protocolTradeFeeDenominator", - docs: ["Protocol trade fee denominator"], - type: "u64", - }, - ], - }, - }, - { - name: "Depeg", - docs: ["Contains information for depeg pool"], - type: { - kind: "struct", - fields: [ - { - name: "baseVirtualPrice", - docs: ["The virtual price of staking / interest bearing token"], - type: "u64", - }, - { - name: "baseCacheUpdated", - docs: ["The virtual price of staking / interest bearing token"], - type: "u64", - }, - { - name: "depegType", - docs: ["Type of the depeg pool"], - type: { - defined: "DepegType", - }, - }, - ], - }, - }, - { - name: "ConfigParameters", - type: { - kind: "struct", - fields: [ - { - name: "tradeFeeNumerator", - type: "u64", - }, - { - name: "protocolTradeFeeNumerator", - type: "u64", - }, - { - name: "activationDurationInSlot", - type: "u64", - }, - { - name: "vaultConfigKey", - type: "publicKey", - }, - { - name: "index", - type: "u64", - }, - ], - }, - }, - { - name: "Padding", - docs: ["Padding for future pool fields"], - type: { - kind: "struct", - fields: [ - { - name: "padding0", - docs: ["Padding 0"], - type: { - array: ["u8", 15], - }, - }, - { - name: "padding", - docs: ["Padding 1"], - type: { - array: ["u128", 24], - }, - }, - ], - }, - }, - { - name: "AlphaVault", - type: { - kind: "struct", - fields: [ - { - name: "activationSlot", - docs: ["Activation slot"], - type: "u64", - }, - { - name: "whitelistedVault", - docs: ["Whitelisted vault to be able to buy pool before open slot"], - type: "publicKey", - }, - { - name: "poolCreator", - docs: [ - "Need to store pool creator in lauch pool, so they can modify liquidity before activation slot", - ], - type: "publicKey", - }, - ], - }, - }, - { - name: "RoundDirection", - docs: ["Rounding direction"], - type: { - kind: "enum", - variants: [ - { - name: "Floor", - }, - { - name: "Ceiling", - }, - ], - }, - }, - { - name: "TradeDirection", - docs: ["Trade (swap) direction"], - type: { - kind: "enum", - variants: [ - { - name: "AtoB", - }, - { - name: "BtoA", - }, - ], - }, - }, - { - name: "NewCurveType", - docs: ["Type of the swap curve"], - type: { - kind: "enum", - variants: [ - { - name: "ConstantProduct", - }, - { - name: "Stable", - fields: [ - { - name: "amp", - docs: ["Amplification coefficient"], - type: "u64", - }, - { - name: "token_multiplier", - docs: [ - "Multiplier for the pool token. Used to normalized token with different decimal into the same precision.", - ], - type: { - defined: "TokenMultiplier", - }, - }, - { - name: "depeg", - docs: [ - "Depeg pool information. Contains functions to allow token amount to be repeg using stake / interest bearing token virtual price", - ], - type: { - defined: "Depeg", - }, - }, - { - name: "last_amp_updated_timestamp", - docs: [ - "The last amp updated timestamp. Used to prevent update_curve_info called infinitely many times within a short period", - ], - type: "u64", - }, - ], - }, - { - name: "NewCurve", - fields: [ - { - name: "field_one", - type: "u64", - }, - { - name: "field_two", - type: "u64", - }, - ], - }, - ], - }, - }, - { - name: "CurveType", - docs: ["Type of the swap curve"], - type: { - kind: "enum", - variants: [ - { - name: "ConstantProduct", - }, - { - name: "Stable", - fields: [ - { - name: "amp", - docs: ["Amplification coefficient"], - type: "u64", - }, - { - name: "token_multiplier", - docs: [ - "Multiplier for the pool token. Used to normalized token with different decimal into the same precision.", - ], - type: { - defined: "TokenMultiplier", - }, - }, - { - name: "depeg", - docs: [ - "Depeg pool information. Contains functions to allow token amount to be repeg using stake / interest bearing token virtual price", - ], - type: { - defined: "Depeg", - }, - }, - { - name: "last_amp_updated_timestamp", - docs: [ - "The last amp updated timestamp. Used to prevent update_curve_info called infinitely many times within a short period", - ], - type: "u64", - }, - ], - }, - ], - }, - }, - { - name: "DepegType", - docs: ["Type of depeg pool"], - type: { - kind: "enum", - variants: [ - { - name: "None", - }, - { - name: "Marinade", - }, - { - name: "Lido", - }, - { - name: "SplStake", - }, - ], - }, - }, - { - name: "Rounding", - docs: ["Round up, down"], - type: { - kind: "enum", - variants: [ - { - name: "Up", - }, - { - name: "Down", - }, - ], - }, - }, - { - name: "PoolType", - docs: ["Pool type"], - type: { - kind: "enum", - variants: [ - { - name: "Permissioned", - }, - { - name: "Permissionless", - }, - ], - }, - }, - ], - events: [ - { - name: "AddLiquidity", - fields: [ - { - name: "lpMintAmount", - type: "u64", - index: false, - }, - { - name: "tokenAAmount", - type: "u64", - index: false, - }, - { - name: "tokenBAmount", - type: "u64", - index: false, - }, - ], - }, - { - name: "RemoveLiquidity", - fields: [ - { - name: "lpUnmintAmount", - type: "u64", - index: false, - }, - { - name: "tokenAOutAmount", - type: "u64", - index: false, - }, - { - name: "tokenBOutAmount", - type: "u64", - index: false, - }, - ], - }, - { - name: "BootstrapLiquidity", - fields: [ - { - name: "lpMintAmount", - type: "u64", - index: false, - }, - { - name: "tokenAAmount", - type: "u64", - index: false, - }, - { - name: "tokenBAmount", - type: "u64", - index: false, - }, - { - name: "pool", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "Swap", - fields: [ - { - name: "inAmount", - type: "u64", - index: false, - }, - { - name: "outAmount", - type: "u64", - index: false, - }, - { - name: "tradeFee", - type: "u64", - index: false, - }, - { - name: "protocolFee", - type: "u64", - index: false, - }, - { - name: "hostFee", - type: "u64", - index: false, - }, - ], - }, - { - name: "SetPoolFees", - fields: [ - { - name: "tradeFeeNumerator", - type: "u64", - index: false, - }, - { - name: "tradeFeeDenominator", - type: "u64", - index: false, - }, - { - name: "protocolTradeFeeNumerator", - type: "u64", - index: false, - }, - { - name: "protocolTradeFeeDenominator", - type: "u64", - index: false, - }, - { - name: "pool", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "PoolInfo", - fields: [ - { - name: "tokenAAmount", - type: "u64", - index: false, - }, - { - name: "tokenBAmount", - type: "u64", - index: false, - }, - { - name: "virtualPrice", - type: "f64", - index: false, - }, - { - name: "currentTimestamp", - type: "u64", - index: false, - }, - ], - }, - { - name: "TransferAdmin", - fields: [ - { - name: "admin", - type: "publicKey", - index: false, - }, - { - name: "newAdmin", - type: "publicKey", - index: false, - }, - { - name: "pool", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "OverrideCurveParam", - fields: [ - { - name: "newAmp", - type: "u64", - index: false, - }, - { - name: "updatedTimestamp", - type: "u64", - index: false, - }, - { - name: "pool", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "PoolCreated", - fields: [ - { - name: "lpMint", - type: "publicKey", - index: false, - }, - { - name: "tokenAMint", - type: "publicKey", - index: false, - }, - { - name: "tokenBMint", - type: "publicKey", - index: false, - }, - { - name: "poolType", - type: { - defined: "PoolType", - }, - index: false, - }, - { - name: "pool", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "PoolEnabled", - fields: [ - { - name: "pool", - type: "publicKey", - index: false, - }, - { - name: "enabled", - type: "bool", - index: false, - }, - ], - }, - { - name: "MigrateFeeAccount", - fields: [ - { - name: "pool", - type: "publicKey", - index: false, - }, - { - name: "newAdminTokenAFee", - type: "publicKey", - index: false, - }, - { - name: "newAdminTokenBFee", - type: "publicKey", - index: false, - }, - { - name: "tokenAAmount", - type: "u64", - index: false, - }, - { - name: "tokenBAmount", - type: "u64", - index: false, - }, - ], - }, - { - name: "CreateLockEscrow", - fields: [ - { - name: "pool", - type: "publicKey", - index: false, - }, - { - name: "owner", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "Lock", - fields: [ - { - name: "pool", - type: "publicKey", - index: false, - }, - { - name: "owner", - type: "publicKey", - index: false, - }, - { - name: "amount", - type: "u64", - index: false, - }, - ], - }, - { - name: "ClaimFee", - fields: [ - { - name: "pool", - type: "publicKey", - index: false, - }, - { - name: "owner", - type: "publicKey", - index: false, - }, - { - name: "amount", - type: "u64", - index: false, - }, - { - name: "aFee", - type: "u64", - index: false, - }, - { - name: "bFee", - type: "u64", - index: false, - }, - ], - }, - { - name: "CreateConfig", - fields: [ - { - name: "tradeFeeNumerator", - type: "u64", - index: false, - }, - { - name: "protocolTradeFeeNumerator", - type: "u64", - index: false, - }, - { - name: "config", - type: "publicKey", - index: false, - }, - ], - }, - { - name: "CloseConfig", - fields: [ - { - name: "config", - type: "publicKey", - index: false, - }, - ], - }, - ], - errors: [ - { - code: 6000, - name: "MathOverflow", - msg: "Math operation overflow", - }, - { - code: 6001, - name: "InvalidFee", - msg: "Invalid fee setup", - }, - { - code: 6002, - name: "InvalidInvariant", - msg: "Invalid invariant d", - }, - { - code: 6003, - name: "FeeCalculationFailure", - msg: "Fee calculation failure", - }, - { - code: 6004, - name: "ExceededSlippage", - msg: "Exceeded slippage tolerance", - }, - { - code: 6005, - name: "InvalidCalculation", - msg: "Invalid curve calculation", - }, - { - code: 6006, - name: "ZeroTradingTokens", - msg: "Given pool token amount results in zero trading tokens", - }, - { - code: 6007, - name: "ConversionError", - msg: "Math conversion overflow", - }, - { - code: 6008, - name: "FaultyLpMint", - msg: "LP mint authority must be 'A' vault lp, without freeze authority, and 0 supply", - }, - { - code: 6009, - name: "MismatchedTokenMint", - msg: "Token mint mismatched", - }, - { - code: 6010, - name: "MismatchedLpMint", - msg: "LP mint mismatched", - }, - { - code: 6011, - name: "MismatchedOwner", - msg: "Invalid lp token owner", - }, - { - code: 6012, - name: "InvalidVaultAccount", - msg: "Invalid vault account", - }, - { - code: 6013, - name: "InvalidVaultLpAccount", - msg: "Invalid vault lp account", - }, - { - code: 6014, - name: "InvalidPoolLpMintAccount", - msg: "Invalid pool lp mint account", - }, - { - code: 6015, - name: "PoolDisabled", - msg: "Pool disabled", - }, - { - code: 6016, - name: "InvalidAdminAccount", - msg: "Invalid admin account", - }, - { - code: 6017, - name: "InvalidProtocolFeeAccount", - msg: "Invalid protocol fee account", - }, - { - code: 6018, - name: "SameAdminAccount", - msg: "Same admin account", - }, - { - code: 6019, - name: "IdenticalSourceDestination", - msg: "Identical user source and destination token account", - }, - { - code: 6020, - name: "ApyCalculationError", - msg: "Apy calculation error", - }, - { - code: 6021, - name: "InsufficientSnapshot", - msg: "Insufficient virtual price snapshot", - }, - { - code: 6022, - name: "NonUpdatableCurve", - msg: "Current curve is non-updatable", - }, - { - code: 6023, - name: "MisMatchedCurve", - msg: "New curve is mismatched with old curve", - }, - { - code: 6024, - name: "InvalidAmplification", - msg: "Amplification is invalid", - }, - { - code: 6025, - name: "UnsupportedOperation", - msg: "Operation is not supported", - }, - { - code: 6026, - name: "ExceedMaxAChanges", - msg: "Exceed max amplification changes", - }, - { - code: 6027, - name: "InvalidRemainingAccountsLen", - msg: "Invalid remaining accounts length", - }, - { - code: 6028, - name: "InvalidRemainingAccounts", - msg: "Invalid remaining account", - }, - { - code: 6029, - name: "MismatchedDepegMint", - msg: "Token mint B doesn't matches depeg type token mint", - }, - { - code: 6030, - name: "InvalidApyAccount", - msg: "Invalid APY account", - }, - { - code: 6031, - name: "InvalidTokenMultiplier", - msg: "Invalid token multiplier", - }, - { - code: 6032, - name: "InvalidDepegInformation", - msg: "Invalid depeg information", - }, - { - code: 6033, - name: "UpdateTimeConstraint", - msg: "Update time constraint violated", - }, - { - code: 6034, - name: "ExceedMaxFeeBps", - msg: "Exceeded max fee bps", - }, - { - code: 6035, - name: "InvalidAdmin", - msg: "Invalid admin", - }, - { - code: 6036, - name: "PoolIsNotPermissioned", - msg: "Pool is not permissioned", - }, - { - code: 6037, - name: "InvalidDepositAmount", - msg: "Invalid deposit amount", - }, - { - code: 6038, - name: "InvalidFeeOwner", - msg: "Invalid fee owner", - }, - { - code: 6039, - name: "NonDepletedPool", - msg: "Pool is not depleted", - }, - { - code: 6040, - name: "AmountNotPeg", - msg: "Token amount is not 1:1", - }, - { - code: 6041, - name: "AmountIsZero", - msg: "Amount is zero", - }, - { - code: 6042, - name: "TypeCastFailed", - msg: "Type cast error", - }, - { - code: 6043, - name: "AmountIsNotEnough", - msg: "Amount is not enough", - }, - { - code: 6044, - name: "InvalidActivationSlotInDuration", - msg: "Invalid activation slot in duration", - }, - ], -}; - -module.exports = { Amm, IDL }; diff --git a/src/Trading_dev/dex/meteora/swap.js b/src/Trading_dev/dex/meteora/swap.js deleted file mode 100644 index 317142d..0000000 --- a/src/Trading_dev/dex/meteora/swap.js +++ /dev/null @@ -1,26 +0,0 @@ -const DLMM = require('@meteora-ag/dlmm'); -const { PublicKey, Keypair } = require("@solana/web3.js"); -const BN = require("bn.js"); -const { Wallet, AnchorProvider, Program } = require("@project-serum/anchor"); -const { connection, wallet } = require("../../../helpers/config.js"); -const {PROGRAM_ID} = require("./constants.js") -const {fetchDLMMPoolId} = require("./fetch-pool.js") - -console.log("PROGRAM_ID", PROGRAM_ID); -const ourWallet = new Wallet(wallet); -const provider = new AnchorProvider(connection, Wallet, { - commitment: "confirmed", -}); - -async function swap(tokenAddress){ - const poolId = await fetchDLMMPoolId(tokenAddress); - const dlmmPool = await DLMM.create(connection, new PublicKey(poolId)); - console.log(dlmmPool); - - -} -async function main(){ - const tokenAddress = "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"; - await swap(tokenAddress); -} -main(); \ No newline at end of file diff --git a/src/Trading_dev/dex/orca/index.js b/src/Trading_dev/dex/orca/index.js deleted file mode 100644 index f23e23e..0000000 --- a/src/Trading_dev/dex/orca/index.js +++ /dev/null @@ -1,32 +0,0 @@ -const { PublicKey } = require("@solana/web3.js"); -const { AnchorProvider } = require("@coral-xyz/anchor"); -const { DecimalUtil, Percentage } = require("@orca-so/common-sdk"); -const { - WhirlpoolContext, - buildWhirlpoolClient, - ORCA_WHIRLPOOL_PROGRAM_ID, - PDAUtil, - swapQuoteByInputToken, - IGNORE_CACHE, -} = require("@orca-so/whirlpools-sdk"); -const Decimal = require("decimal.js"); -const { - connection, - dev_connection, - wallet, -} = require("../../../helpers/config"); - -async function main() { - const provider = new AnchorProvider(connection, wallet, { - commitment: "confirmed", - }); - const ctx = WhirlpoolContext.withProvider( - provider, - ORCA_WHIRLPOOL_PROGRAM_ID - ); - const client = buildWhirlpoolClient(ctx); - console.log("RPC endpoint: ", ctx.connection.rpcEndpoint); - console.log("Wallet public key: ", ctx.wallet.publicKey.toString()); -} - -main(); diff --git a/src/Trading_dev/grpc-copy-bot/README.md b/src/Trading_dev/grpc-copy-bot/README.md new file mode 100644 index 0000000..55acb60 --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/README.md @@ -0,0 +1,34 @@ +# *Geyser grpc copy Bot (Beta)* + +## How it works + +- It uses the geyser grpc plugin that subscribe all the latest slot that receive from the grpc server. +- It basically only consider the slot or block in "processed" commitment level to make sure the request can land in the next block or next few block(what we expected). + +- Use a grpc subscription to subscribe the transactions that including the target smart wallet address and listen for the swap transactions. +- Once the swap event is detected, it calculate the how much token the trader bought or how much token the trader sold by considering the number of token and sol changes in the liquidity pool, and it follows the exact swapped token amount of the trader. +- The entry/exit price is calculated by the formula: entry/exit price = post SOL in Pool / post token in Pool. + +## Limitations +- It only works on raydium swap transactions now. +- It uses WSOL for settlement, buy using WSOL and sell for WSOL. + +## Prerequisites + +- run `ts-node src/streaming/copy-trade.ts -h` to test the copy-trade command and see the available options +- to change the parameters, you can modify the .env file +- to have a try, run ```ts-node /Users/{your_path_to_this_dir}/src/streaming/copy-trade.ts --trader your_target_trader_address``` + +## Code usage + +- constants/constants.ts: retriving the variable in .env + +- src/streaming/copy-trade.ts: a cli interface to interact the whole dir + +- streaming/stream-trader.ts: subscribing any trader's swap txns of newest block in processed level + +- src/jito/bundle.ts: sending the bundle with tips to jito + +- src/streaming/grpc-requests-type.ts: different grpc request types for monitoring the target trader + +- src/raydium/*.ts: constructing the proper instructions of buy and sell on raydium diff --git a/src/Trading_dev/grpc-copy-bot/command.sh b/src/Trading_dev/grpc-copy-bot/command.sh new file mode 100644 index 0000000..276895c --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/command.sh @@ -0,0 +1 @@ +ts-node /Users/{your_path_to_this_dir}/src/stream/copy-trade.ts --trader your_target_trader_address diff --git a/src/Trading_dev/grpc-copy-bot/main.ts b/src/Trading_dev/grpc-copy-bot/main.ts new file mode 100644 index 0000000..d5d79d7 --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/main.ts @@ -0,0 +1,24 @@ +import { spawn } from 'child_process'; +import path from 'path'; + +const scriptPath = path.join(__dirname, 'command.sh'); + +function runScript() { + const child = spawn('sh', [scriptPath], { + stdio: 'inherit', + shell: true, + }); + + child.on('close', (code) => { + console.log(`child process exited with code ${code}`); + console.error('copy-trade.ts script closed or encountered an error, restarting...'); + runScript(); + + }); + + child.on('error', (err) => { + console.error('Error running script.sh:', err); + runScript(); + }); +} +runScript(); \ No newline at end of file diff --git a/src/Trading_dev/grpc-copy-bot/src/.DS_Store b/src/Trading_dev/grpc-copy-bot/src/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/src/Trading_dev/grpc-copy-bot/src/.DS_Store differ diff --git a/src/Trading_dev/grpc-copy-bot/src/constants/constants.ts b/src/Trading_dev/grpc-copy-bot/src/constants/constants.ts new file mode 100644 index 0000000..9e410b9 --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/constants/constants.ts @@ -0,0 +1,49 @@ +import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; +import { logger, retrieveEnvVariable } from "../../../../utils"; +import { + Currency, + Token, + TOKEN_PROGRAM_ID, +} from "@raydium-io/raydium-sdk"; +import { Commitment, Connection, Keypair, PublicKey } from "@solana/web3.js"; +export const NETWORK = "mainnet-beta"; +export const COMMITMENT_LEVEL: Commitment = retrieveEnvVariable( + "COMMITMENT_LEVEL", + logger +) as Commitment; +export const RPC_ENDPOINT = retrieveEnvVariable("MAINNET_ENDPOINT", logger); +export const RPC_WEBSOCKET_ENDPOINT = retrieveEnvVariable( + "WS_MAINNET_ENDPOINT", + logger +); +export const GRPC_XTOKEN = retrieveEnvVariable("GRPC_XTOKEN", logger); +export const LOG_LEVEL = retrieveEnvVariable("LOG_LEVEL", logger); +export const PRIVATE_KEY = retrieveEnvVariable("PRIVATE_KEY", logger); +export const JITO_TIPS = retrieveEnvVariable("JITO_FEE", logger); +export const connection = new Connection(RPC_ENDPOINT, "processed"); +export const wallet = Keypair.fromSecretKey(bs58.decode(PRIVATE_KEY)); +export const wsol = "So11111111111111111111111111111111111111112"; +const usdc = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; +export const quoteToken = [ + usdc, // USDC + "SOL", // SOL + "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", // USDT + wsol, // WSOL +]; +export const DEFAULT_TOKEN = { + SOL: new Currency(9, "SOL", "SOL"), + WSOL: new Token( + TOKEN_PROGRAM_ID, + new PublicKey("So11111111111111111111111111111111111111112"), + 9, + "WSOL", + "WSOL" + ), + USDC: new Token( + TOKEN_PROGRAM_ID, + new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), + 6, + "USDC", + "USDC" + ), +}; diff --git a/src/Trading_dev/grpc-copy-bot/src/constants/index.ts b/src/Trading_dev/grpc-copy-bot/src/constants/index.ts new file mode 100644 index 0000000..c7582ff --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/constants/index.ts @@ -0,0 +1 @@ +export * from "./constants" \ No newline at end of file diff --git a/src/Trading_dev/grpc-copy-bot/src/jito/bundle.ts b/src/Trading_dev/grpc-copy-bot/src/jito/bundle.ts new file mode 100644 index 0000000..e825c1d --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/jito/bundle.ts @@ -0,0 +1,127 @@ +import { + Connection, + PublicKey, + Keypair, + VersionedTransaction, + MessageV0, + LAMPORTS_PER_SOL, +} from "@solana/web3.js"; +import { Bundle } from "jito-ts/dist/sdk/block-engine/types"; +import * as Fs from "fs"; +require("dotenv").config(); +import { searcherClient } from "jito-ts/dist/sdk/block-engine/searcher"; +import { + ChannelCredentials, + ChannelOptions, + ClientReadableStream, + ServiceError, +} from "@grpc/grpc-js"; +import { SearcherServiceClient } from "jito-ts/dist/gen/block-engine/searcher"; +import { + PRIVATE_KEY, + RPC_ENDPOINT, + RPC_WEBSOCKET_ENDPOINT, + JITO_TIPS, +} from "../constants"; + +import bs58 from "bs58"; +import { logger } from "../../../../helpers/logger"; +import { bundle } from "jito-ts"; +const blockEngineUrl = process.env.BLOCK_ENGINE_URL || ""; +logger.info(`BLOCK_ENGINE_URL: ${blockEngineUrl}`); +const c = searcherClient(blockEngineUrl, undefined); +export const searcherClientAdv = ( + url: string, + authKeypair: Keypair | undefined, + grpcOptions?: Partial +): SearcherServiceClient => { + const client: SearcherServiceClient = new SearcherServiceClient( + url, + ChannelCredentials.createSsl(), + { ...grpcOptions } + ); + + return client; +}; + +// Get Tip Accounts + +let tipAccounts: string[] = []; +(async () => { + try { + tipAccounts = await c.getTipAccounts(); + // console.log('Result:', tipAccounts); + } catch (error) { + console.error("Error:", error); + } +})(); + +export async function sendBundle( + latestBlockhash: string, + transaction: VersionedTransaction, + poolId: PublicKey, + masterKeypair: Keypair +) { + try { + const _tipAccount = tipAccounts[Math.floor(Math.random() * 6)]; + const tipAccount = new PublicKey(_tipAccount); + const b = new Bundle([transaction], 4); + const jito_tips = parseFloat(JITO_TIPS); + b.addTipTx( + masterKeypair, + jito_tips * LAMPORTS_PER_SOL, // Adjust Jito tip amount here + tipAccount, + latestBlockhash + ); + logger.info(`Sending bundle`); + const bundleResult = await c.sendBundle(b); + logger.info(`Sent trade tx to jito!`); + logger.info({ + dexscreener: `https://dexscreener.com/solana/${poolId.toBase58()}?maker=${masterKeypair.publicKey.toBase58()}`, + }); + } catch (error) { + logger.error(error); + } +} + +// Get leader schedule + +// This was when I was experimenting with only sending the buy tx when a Jito leader was up or going to be up in the next slot so that I wouldn't +// have to wait multiple slots for the tx to be processed. I ended up not using this feature as it couldn't get it working correctly before I moved on. + +export async function storeJitoLeaderSchedule() { + const cs = searcherClientAdv(blockEngineUrl, undefined); + + const leaderSchedule = new Set(); + + cs.getConnectedLeadersRegioned( + { regions: ["tokyo", "amsterdam", "ny", "frankfurt"] }, + (error, response) => { + for (let key in response) { + if (key === "connectedValidators") { + let validators = response[key]; + for (let validatorKey in validators) { + // Each validator object + let validator = validators[validatorKey]; + // Assuming `slots` is an array inside each validator object + Object.keys(validator.connectedValidators).forEach( + (key: string) => { + const slotsArray: number[][] = Object.values( + validator.connectedValidators[key] + ); // Assume SlotList is an array of arrays + const flattenedSlotsArray: number[] = slotsArray.flat(); // Flatten the array + flattenedSlotsArray.forEach((slot: number) => { + leaderSchedule.add(slot); + }); + } + ); + } + } + } + + //console.log(leaderSchedule); + } + ); + + return leaderSchedule; +} diff --git a/src/Trading_dev/grpc-copy-bot/src/jito/index.ts b/src/Trading_dev/grpc-copy-bot/src/jito/index.ts new file mode 100644 index 0000000..cf76714 --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/jito/index.ts @@ -0,0 +1 @@ +export * from "./bundle"; \ No newline at end of file diff --git a/src/Trading_dev/grpc-copy-bot/src/raydium/buy-helper.ts b/src/Trading_dev/grpc-copy-bot/src/raydium/buy-helper.ts new file mode 100644 index 0000000..2e206f8 --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/raydium/buy-helper.ts @@ -0,0 +1,10 @@ +import { Keypair } from "@solana/web3.js"; +import {swap} from "./swap"; +import {connection} from "../constants" +import { VersionedTransaction } from "@solana/web3.js"; + + +export async function buy(side = "buy", address: string, no_of_sol: number, payer: Keypair): Promise { + return await swap(side, address, no_of_sol, -1, payer, "trade", connection); +} + \ No newline at end of file diff --git a/src/Trading_dev/grpc-copy-bot/src/raydium/formatAmmKeys.ts b/src/Trading_dev/grpc-copy-bot/src/raydium/formatAmmKeys.ts new file mode 100644 index 0000000..330ef1a --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/raydium/formatAmmKeys.ts @@ -0,0 +1,82 @@ +import { + LIQUIDITY_STATE_LAYOUT_V4, + MARKET_STATE_LAYOUT_V3, + SPL_MINT_LAYOUT, + Liquidity, + Market, + MAINNET_PROGRAM_ID, + LiquidityStateV4, + publicKey, + struct, + } from "@raydium-io/raydium-sdk"; + import { PublicKey } from "@solana/web3.js"; + const MINIMAL_MARKET_STATE_LAYOUT_V3 = struct([ + publicKey("eventQueue"), + publicKey("bids"), + publicKey("asks"), + ]); + import { connection } from "../constants"; + + // Promise + /** + * Formats AMM keys by ID. + * @param {string} id - The ID of the AMM. + * @returns {Object} - The formatted AMM keys. + * @throws {Error} - If there is an error retrieving the account information. + */ +export async function formatAmmKeysById_swap(id: PublicKey):Promise { + const account = await connection.getAccountInfo(id); + if (account === null) throw Error(" get id info error "); + const info = LIQUIDITY_STATE_LAYOUT_V4.decode(account.data); + + const marketId = info.marketId; + const marketAccount_minimal = await connection.getAccountInfo(marketId, { + commitment: "processed", + dataSlice: { + offset: MARKET_STATE_LAYOUT_V3.offsetOf("eventQueue"), + length: 32 * 3, + }, + }); + const marketAccount = await connection.getAccountInfo(marketId); + if (marketAccount === null || marketAccount_minimal === null) + throw Error(" get market info error"); + const marketInfo_minimal = MINIMAL_MARKET_STATE_LAYOUT_V3.decode( + marketAccount_minimal.data + ); + const marketInfo = MARKET_STATE_LAYOUT_V3.decode(marketAccount.data); + + return { + id, + baseMint: info.baseMint, + quoteMint: info.quoteMint, + lpMint: info.lpMint, + baseDecimals: info.baseDecimal.toNumber(), + quoteDecimals: info.quoteDecimal.toNumber(), + lpDecimals: 5, + version: 4, + programId: MAINNET_PROGRAM_ID.AmmV4, + authority: Liquidity.getAssociatedAuthority({ + programId: MAINNET_PROGRAM_ID.AmmV4, + }).publicKey, + openOrders: info.openOrders, + targetOrders: info.targetOrders, + baseVault: info.baseVault, + quoteVault: info.quoteVault, + marketVersion: 3, + marketProgramId: info.marketProgramId, + marketId: info.marketId, + marketAuthority: Market.getAssociatedAuthority({ + programId: info.marketProgramId, + marketId: info.marketId, + }).publicKey, + marketBaseVault: marketInfo.baseVault, + marketQuoteVault: marketInfo.quoteVault, + marketBids: marketInfo_minimal.bids, + marketAsks: marketInfo_minimal.asks, + marketEventQueue: marketInfo_minimal.eventQueue, + withdrawQueue: info.withdrawQueue, + lpVault: info.lpVault, + lookupTableAccount: PublicKey.default, + }; + } + \ No newline at end of file diff --git a/src/Trading_dev/grpc-copy-bot/src/raydium/index.ts b/src/Trading_dev/grpc-copy-bot/src/raydium/index.ts new file mode 100644 index 0000000..09eb9b9 --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/raydium/index.ts @@ -0,0 +1,5 @@ +export * from "./utils"; +export * from "./buy-helper"; +export * from "./sell-helper"; +export * from "./swap"; +export * from "./formatAmmKeys"; \ No newline at end of file diff --git a/src/Trading_dev/grpc-copy-bot/src/raydium/sell-helper.ts b/src/Trading_dev/grpc-copy-bot/src/raydium/sell-helper.ts new file mode 100644 index 0000000..9194903 --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/raydium/sell-helper.ts @@ -0,0 +1,9 @@ +import { Keypair } from "@solana/web3.js"; +import {swap} from "./swap"; +import {connection} from "../constants" +import { VersionedTransaction } from "@solana/web3.js"; + + +export async function sell(side = "sell", address: string, sell_amount: number, payer: Keypair): Promise { + return await swap(side, address, -1, sell_amount, payer, "trade", connection); +} diff --git a/src/Trading_dev/grpc-copy-bot/src/raydium/swap.ts b/src/Trading_dev/grpc-copy-bot/src/raydium/swap.ts new file mode 100644 index 0000000..6868c28 --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/raydium/swap.ts @@ -0,0 +1,245 @@ +import { + Liquidity, + Percent, + Token, + TOKEN_PROGRAM_ID, + TokenAmount, +} from "@raydium-io/raydium-sdk"; +import { + PublicKey, + TransactionMessage, + ComputeBudgetProgram, + VersionedTransaction, +} from "@solana/web3.js"; +import { Decimal } from "decimal.js"; +import { BN } from "@project-serum/anchor"; +import { getSPLBalance, getDecimals } from "../../../../helpers/utils"; +import { DEFAULT_TOKEN } from "../constants"; +import { fetchAMMPoolId } from "./utils"; +import { + getAssociatedTokenAddress, + getAssociatedTokenAddressSync, + createAssociatedTokenAccountIdempotentInstruction, + createCloseAccountInstruction, +} from "@solana/spl-token"; +import { formatAmmKeysById_swap } from "./formatAmmKeys"; +import { Keypair } from "@solana/web3.js"; +import { Connection } from "@solana/web3.js"; + +let tokenToPoolId:any = {}; +let walletPublicKeyToWSOLAta:any = {}; +let walletPublicKeyToTokenAta:any = {}; +let tokenToDecimal:any = {}; +/** + * Performs a swap operation using an Automated Market Maker (AMM) pool in Raydium. + * @param {Object} input - The input parameters for the swap operation. + * @returns {Object} - The transaction IDs of the executed swap operation. + */ +async function swapOnlyAmm(input: any): Promise { + // -------- pre-action: get pool info --------\ + const poolKeys = await formatAmmKeysById_swap( + new PublicKey(input.targetPool) + ); + const poolInfo = await Liquidity.fetchInfo({ + connection: input.connection_obj, + poolKeys: poolKeys, + }); + // -------- step 1: coumpute amount out -------- + const { amountOut, minAmountOut } = Liquidity.computeAmountOut({ + poolKeys: poolKeys, + poolInfo: poolInfo, + amountIn: input.inputTokenAmount, + currencyOut: input.outputToken, + slippage: input.slippage, + }); + // -------- step 2: create instructions by SDK function -------- + const { innerTransaction } = await Liquidity.makeSwapFixedInInstruction( + { + poolKeys: poolKeys, + userKeys: { + tokenAccountIn: input.ataIn, + tokenAccountOut: input.ataOut, + owner: input.master_wallet.publicKey, + }, + amountIn: input.inputTokenAmount.raw, + minAmountOut: minAmountOut.raw, + }, + poolKeys.version + ); + + let latestBlockhash = await input.connection_obj.getLatestBlockhash(); + const messageV0 = new TransactionMessage({ + payerKey: input.master_wallet.publicKey, + recentBlockhash: latestBlockhash.blockhash, + instructions: [ + ...[ + ComputeBudgetProgram.setComputeUnitLimit({ + units: 70000, + }), + ], + ...(input.side === "buy" + ? [ + createAssociatedTokenAccountIdempotentInstruction( + input.master_wallet.publicKey, + input.ataOut, + input.master_wallet.publicKey, + input.outputToken.mint + ), + ] + : []), + ...innerTransaction.instructions, + ], + }).compileToV0Message(); + + const transaction = new VersionedTransaction(messageV0); + transaction.sign([input.master_wallet, ...innerTransaction.signers]); + return transaction; +} + +/** + * Performs a swap operation. + * + * @param {string} side - The side of the swap operation ("buy" or "sell"). + * @param {string} tokenAddr - The address of the token involved in the swap. + * @param {number} buy_AmountOfSol - The amount of SOL to buy (only applicable for "buy" side). + * @param {number} sell_AmountOfToken - The amount of Token to sell (only applicable for "sell" side). + * @param {object} payer_wallet - The payer's wallet object. + * @param {string} usage - The usage of the swap operation. + * @param {object} connection_obj - The connection object. + * @returns {Promise} - A promise that resolves when the swap operation is completed. + */ +export async function swap( + side: string, + tokenAddr: string, + buy_AmountOfSol: number, + sell_AmountOfToken: number, + payer_wallet: Keypair, + usage: string, + connection_obj: Connection +): Promise { + const tokenAddress: string = tokenAddr; + const tokenAccount: PublicKey = new PublicKey(tokenAddress); + let mintAta: any = null, + quoteAta: any = null, + targetPool: string = ""; + + // to avoid creating associated token account multiple times + if (!(payer_wallet.publicKey.toBase58() in walletPublicKeyToTokenAta)) { + walletPublicKeyToTokenAta[payer_wallet.publicKey.toBase58()] = {}; + walletPublicKeyToTokenAta[payer_wallet.publicKey.toBase58()][tokenAddress] = + await getAssociatedTokenAddress(tokenAccount, payer_wallet.publicKey); + mintAta = + walletPublicKeyToTokenAta[payer_wallet.publicKey.toBase58()][ + tokenAddress + ]; + } else { + if ( + !( + tokenAddress in + walletPublicKeyToTokenAta[payer_wallet.publicKey.toBase58()] + ) + ) { + walletPublicKeyToTokenAta[payer_wallet.publicKey.toBase58()][ + tokenAddress + ] = await getAssociatedTokenAddress(tokenAccount, payer_wallet.publicKey); + } + mintAta = + walletPublicKeyToTokenAta[payer_wallet.publicKey.toBase58()][ + tokenAddress + ]; + } + // to avoid creating associated WSOL account multiple times + if (!(payer_wallet.publicKey.toBase58() in walletPublicKeyToWSOLAta)) { + quoteAta = await getAssociatedTokenAddressSync( + Token.WSOL.mint, + payer_wallet.publicKey + ); + walletPublicKeyToWSOLAta[payer_wallet.publicKey.toBase58()] = quoteAta; + } else { + quoteAta = walletPublicKeyToWSOLAta[payer_wallet.publicKey.toBase58()]; + } + // to avoid getting the same pool id multiple times + if (!(tokenAddress in tokenToPoolId)) { + targetPool = await fetchAMMPoolId(tokenAddress); + tokenToPoolId[tokenAddress] = targetPool; + } else { + targetPool = tokenToPoolId[tokenAddress]; + } + // to avoid getting the same decimal multiple times + if (!(tokenAddress in tokenToDecimal)) { + tokenToDecimal[tokenAddress] = await getDecimals(tokenAccount); + } + if (side === "buy") { + // buy - use sol to swap to the token + //const { tokenName, tokenSymbol } = await getTokenMetadata(tokenAddress); + const outputToken = new Token( + TOKEN_PROGRAM_ID, + tokenAccount, + tokenToDecimal[tokenAddress] + ); + const inputToken = DEFAULT_TOKEN.WSOL; // SOL + if (targetPool === null) { + console.log( + "Pool not found or raydium is not supported for this token. Exiting..." + ); + return Object.create(null); + } + const amountOfSol = new Decimal(buy_AmountOfSol); + const inputTokenAmount = new TokenAmount( + inputToken, + new BN(amountOfSol.mul(10 ** inputToken.decimals).toFixed(0)) + ); + const slippage = new Percent(3, 100); + const input = { + outputToken, + targetPool, + inputTokenAmount, + slippage, + ataIn: quoteAta, + ataOut: mintAta, + side, + usage, + connection_obj: connection_obj, + master_wallet: payer_wallet, + }; + + return { pool: new PublicKey(targetPool), txn: await swapOnlyAmm(input) }; + } else { + // sell + const inputToken = new Token( + TOKEN_PROGRAM_ID, + tokenAccount, + tokenToDecimal[tokenAddress], + "", + "" + ); + const outputToken = DEFAULT_TOKEN.WSOL; // WSOL + + if (targetPool === null) { + console.log( + "Pool not found or raydium is not supported for this token. Exiting..." + ); + return Object.create(null); + } + const amount = new Decimal(sell_AmountOfToken); + const slippage = new Percent(5, 100); + const inputTokenAmount = new TokenAmount( + inputToken, + new BN(amount.mul(10 ** inputToken.decimals).toFixed(0)) + ); + const input = { + outputToken, + targetPool, + inputTokenAmount, + slippage, + ataIn: mintAta, + ataOut: quoteAta, + side, + usage, + tokenAddress: tokenAddress, + connection_obj: connection_obj, + master_wallet: payer_wallet, + }; + return { pool: new PublicKey(targetPool), txn: await swapOnlyAmm(input) }; + } +} diff --git a/src/Trading_dev/grpc-copy-bot/src/raydium/utils.ts b/src/Trading_dev/grpc-copy-bot/src/raydium/utils.ts new file mode 100644 index 0000000..3bd48f8 --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/raydium/utils.ts @@ -0,0 +1,43 @@ +import { Raydium } from "@raydium-io/raydium-sdk-v2"; +import { connection, wallet, wsol } from "../constants"; +import { formatAmmKeysById_swap } from "./formatAmmKeys"; +import { PublicKey } from "@solana/web3.js"; +import { logger } from "../../../../utils"; + +export const initSdk = async () => { + const raydium = await Raydium.load({ + owner: wallet, + connection: connection, + cluster: "mainnet", + disableFeatureCheck: true, + disableLoadToken: true, + blockhashCommitment: "confirmed", + }); + return raydium; +}; + +export async function fetchAMMPoolId(tokenAddress: string): Promise { + const raydium = await initSdk(); + const data:any = await raydium.api.fetchPoolByMints({ + mint1: wsol, + mint2: tokenAddress, + }); + const listOfPools = data.data; + for (const obj of listOfPools) { + if (obj.type === "Standard") { + // return the first AMM pool ID + console.log("AMM Pool ID: ", obj.id); + return obj.id; + } + } + logger.error("No AMM pool ID found for the given token address"); + return ""; // return empty string if no AMM pool ID is found +} +// async function main() { +// const tokenAddress = "3B5wuUrMEi5yATD7on46hKfej3pfmd7t1RKgrsN3pump"; // billy +// const poolId = await fetchAMMPoolId(tokenAddress); +// console.log(await formatAmmKeysById_swap(new PublicKey(poolId))); + +// } + +// main(); diff --git a/src/Trading_dev/grpc-copy-bot/src/streaming/copy-trade.ts b/src/Trading_dev/grpc-copy-bot/src/streaming/copy-trade.ts new file mode 100644 index 0000000..647a03d --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/streaming/copy-trade.ts @@ -0,0 +1,44 @@ +import { streamTargetTrader } from "./stream-trader"; +import { init } from "../transaction/transaction"; +import { logger } from "../../../../helpers/logger"; +import { fork } from "child_process"; +import bs58 from "bs58"; +import path from "path"; +export const stream_trader_path = path.join(__dirname, "stream-trader.ts"); +import { program } from "commander"; +let targetTraderToCopy: string = ""; + +program + .option("--trader ", "Specify the trader you want to copy") + .option("-h, --help", "display help for command") + .action((options: any) => { + if (options.help) { + logger.info("ts-node copy-trade.ts --trader "); + process.exit(0); + } + if (options.trader) { + targetTraderToCopy = options.trader; + } + }); +program.parse(); + +async function snipe() { + // show the options + logger.info(`Trader: ${targetTraderToCopy}`); + // show the target token + logger.info(`bot will copy the trades from ${targetTraderToCopy}.`); + + // initialize the bot + await init(); + try { + // Start copy_buy in a separate process + await streamTargetTrader(targetTraderToCopy); + } catch (e) { + logger.error(`error when streaming ${e}`); + logger.info("Retrying in 1 second"); + await new Promise((resolve) => setTimeout(resolve, 1000)); + await snipe(); + } +} + +snipe(); diff --git a/src/Trading_dev/grpc-copy-bot/src/streaming/grpc-requests-type.ts b/src/Trading_dev/grpc-copy-bot/src/streaming/grpc-requests-type.ts new file mode 100644 index 0000000..703b30d --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/streaming/grpc-requests-type.ts @@ -0,0 +1,46 @@ +import { + CommitmentLevel, + SubscribeRequest, + } from "@triton-one/yellowstone-grpc"; +import { req } from "pino-std-serializers"; +const RaydiumProgram = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8" +const RaydiumRoute = "routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS" +const RaydiumCAMM = "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK" +const tokenAccountProgram = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" +export async function createSubscribeTraderRequest(traderAddress: string) { + let request: any = null; + request = { + slots: {}, + accounts: {}, + transactions: { + pumpdotfun: { + vote: false, + failed: false, + signature: undefined, + accountInclude: [traderAddress], + accountExclude: [], + accountRequired: [traderAddress], + }, + }, + transactionsStatus: {}, + blocks: {}, + blocksMeta: {}, + accountsDataSlice: [], + commitment: CommitmentLevel.PROCESSED, // Subscribe to processed blocks for the fastest updates + entry: {}, + }; + return request; +} +export async function createClearAllSubscriptionsRequest() { + const request = { + "slots": {}, + "accounts": {}, + "transactions": {}, + "blocks": {}, + "blocksMeta": {}, + "accountsDataSlice": [] + }; + return request; +} + + diff --git a/src/Trading_dev/grpc-copy-bot/src/streaming/stream-trader.ts b/src/Trading_dev/grpc-copy-bot/src/streaming/stream-trader.ts new file mode 100644 index 0000000..107dd9b --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/streaming/stream-trader.ts @@ -0,0 +1,133 @@ +import pino from "pino"; +import Client from "@triton-one/yellowstone-grpc"; +import { PublicKey } from "@solana/web3.js"; +import { storeJitoLeaderSchedule, sendBundle } from "../jito/bundle"; +import bs58 from "bs58"; +import { + createClearAllSubscriptionsRequest, + createSubscribeTraderRequest, +} from "./grpc-requests-type"; +import { handleSubscribe, wsol } from "./utils"; +import { getSPLBalance, retriveWalletState } from "../../../../utils"; +import { connection, quoteToken, wallet, GRPC_XTOKEN } from "../constants/constants"; +import { sell, buy } from "../raydium"; +let trader_balance_wallet:any = {}; +let targetTrader = ""; +export const raydium_authority = "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1"; // ***it represent the person who extract/put the sol/token to the pool for every raydium swap txn*** +const client = new Client( + "https://grpc.fra.shyft.to", + GRPC_XTOKEN, + { + "grpc.max_receive_message_length": 64 * 1024 * 1024, // 64MiB + } +); //grpc endpoint +const transport = pino.transport({ + target: "pino-pretty", +}); + +export const logger = pino( + { + level: "info", + serializers: { + error: pino.stdSerializers.err, + }, + base: undefined, + }, + transport +); +// Array to store Jito leaders for current epoch +let leaderSchedule = new Set(); +export async function populateJitoLeaderArray() { + leaderSchedule = await storeJitoLeaderSchedule(); +} + +(async () => { + const version = await client.getVersion(); // gets the version information + logger.info(version); +})(); + +export async function checkTraderBuyOrSell(data: any, traderAddress: string) { + const preTokenBalances = data.transaction.transaction.meta.preTokenBalances; + const postTokenBalances = data.transaction.transaction.meta.postTokenBalances; + const latestBlockhash = await connection.getLatestBlockhash("processed"); + let targetToken = "", postPoolSOL=0, postPoolToken=0, prePoolSOL=0, prePoolToken=0, side = ""; + // look for the token that the trader is buying or selling + for (const account of preTokenBalances) { + if (targetToken !== "" && prePoolSOL !== 0 && prePoolToken!==0) break; // make sure we get the target token and pool sol balances and trader address only + if (account.owner === raydium_authority && account.mint !== wsol) targetToken = account.mint; + if (account.owner === raydium_authority && account.mint === wsol) { + prePoolSOL = account.uiTokenAmount.uiAmount; + } + if (account.owner === raydium_authority && account.mint !== wsol) { + prePoolToken = account.uiTokenAmount.uiAmount; + } + } + for (const account of postTokenBalances) { + if (postPoolSOL !== 0 && postPoolToken!==0) break; // make sure we get the target token and pool sol balances and trader address only + if (account.owner === raydium_authority && account.mint !== wsol ) targetToken = account.mint; + if (account.owner === raydium_authority && account.mint === wsol) { + postPoolSOL = account.uiTokenAmount.uiAmount; + } + if (account.owner === raydium_authority && account.mint !== wsol) { + postPoolToken = account.uiTokenAmount.uiAmount; + } + } + if (targetToken === "") return; + let swappedSOLAmount = 0, swappedTokenAmount = 0; + if(postPoolSOL > prePoolSOL){ + side = "buy"; + swappedSOLAmount = postPoolSOL - prePoolSOL; + swappedTokenAmount = prePoolToken - postPoolToken; + } + else { + side = "sell"; + swappedSOLAmount = prePoolSOL - postPoolSOL; + swappedTokenAmount = postPoolToken - prePoolToken; + } + if(side==="buy") { + logger.info(`Trader ${traderAddress} is ${side}ing ${swappedTokenAmount} of ${targetToken} using ${swappedSOLAmount}SOL in price of ${postPoolSOL/postPoolToken}`); + const { pool, txn } = await buy( + "buy", + targetToken, + swappedSOLAmount, + wallet + ); + sendBundle(latestBlockhash.blockhash, txn, pool, wallet); + }else{ + logger.info(`Trader ${traderAddress} is ${side}ing ${swappedTokenAmount} of ${targetToken} for ${swappedSOLAmount}SOL in price of ${postPoolSOL/postPoolToken}`); + const { pool, txn } = await sell( + "sell", + targetToken, + swappedTokenAmount, + wallet + ); + sendBundle(latestBlockhash.blockhash, txn, pool, wallet); + } + + +} + +export async function streamTargetTrader(traderAddress: string) { + try { + console.log("Target trader: ", traderAddress); + trader_balance_wallet = await retriveWalletState(traderAddress); + console.log(trader_balance_wallet); + + const stream = await client.subscribe(); + // throw new Error("test"); // test if it restarts when error occurs + // process.exit(1); // test if it restart when process exit + // Create `error` / `end` handler + const r1 = await createSubscribeTraderRequest(traderAddress); + handleSubscribe(stream, r1); + stream.on("data", (data) => { + // receive an update when trader makes a transaction + if (data.transaction !== undefined) { + logger.info(`Current slot: ${data.transaction.slot}`); + checkTraderBuyOrSell(data, traderAddress); + } + }); + } catch (e) { + logger.error(e); + throw e; + } +} diff --git a/src/Trading_dev/grpc-copy-bot/src/streaming/utils.ts b/src/Trading_dev/grpc-copy-bot/src/streaming/utils.ts new file mode 100644 index 0000000..fe474f5 --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/streaming/utils.ts @@ -0,0 +1,73 @@ +import { + CommitmentLevel, + SubscribeRequest, +} from "@triton-one/yellowstone-grpc"; +import Client from "@triton-one/yellowstone-grpc"; +import { logger } from "../../../../utils"; +const PING_INTERVAL_MS = 100_000; +export const wsol = "So11111111111111111111111111111111111111112"; +export async function handleSubscribe( + client_stream: any, + args: SubscribeRequest +) { + try { + const streamClosed = new Promise((resolve, reject) => { + client_stream.on("error", (error:any) => { + console.log("ERROR", error); + reject(error); + client_stream.end(); + }); + client_stream.on("end", () => { + resolve(); + }); + client_stream.on("close", () => { + resolve(); + }); + }); + + // Send subscribe request + await new Promise((resolve, reject) => { + client_stream.write(args, (err: any) => { + if (err === null || err === undefined) { + resolve(); + } else { + reject(err); + } + }); + }).catch((reason) => { + console.error(reason); + throw reason; + }); + // Send pings every 5s to keep the connection open + const pingRequest: SubscribeRequest = { + ping: { id: 1 }, + // Required, but unused arguments + accounts: {}, + accountsDataSlice: [], + transactions: {}, + blocks: {}, + blocksMeta: {}, + entry: {}, + slots: {}, + }; + setInterval(async () => { + await new Promise((resolve, reject) => { + client_stream.write(pingRequest, (err:any) => { + if (err === null || err === undefined) { + resolve(); + } else { + reject(err); + } + }); + }).catch((reason) => { + console.error(reason); + throw reason; + }); + }, PING_INTERVAL_MS); + + await streamClosed; + } catch (e) { + logger.error(e); + throw e; + } +} diff --git a/src/Trading_dev/grpc-copy-bot/src/transaction/transaction.ts b/src/Trading_dev/grpc-copy-bot/src/transaction/transaction.ts new file mode 100644 index 0000000..58a7bc2 --- /dev/null +++ b/src/Trading_dev/grpc-copy-bot/src/transaction/transaction.ts @@ -0,0 +1,73 @@ +import { + Liquidity, + LiquidityPoolKeys, + LiquidityStateV4, + Token, + TokenAmount, +} from "@raydium-io/raydium-sdk"; +import { + Commitment, + ComputeBudgetProgram, + Connection, + Keypair, + LAMPORTS_PER_SOL, + PublicKey, + SystemProgram, + TransactionMessage, + VersionedTransaction, + Transaction, +} from "@solana/web3.js"; +import fs from "fs"; +import bs58 from "bs58"; +import { + COMMITMENT_LEVEL, + LOG_LEVEL, + PRIVATE_KEY, + RPC_ENDPOINT, + RPC_WEBSOCKET_ENDPOINT, +} from "../constants"; +import { + AccountLayout, + createAssociatedTokenAccountIdempotentInstruction, + createCloseAccountInstruction, + getAssociatedTokenAddress, + getAssociatedTokenAddressSync, + TOKEN_PROGRAM_ID, +} from "@solana/spl-token"; +import { TokenInstructions } from "@project-serum/serum"; +import { logger } from "../../../../helpers/logger"; +import { + retrieveEnvVariable, + getKeypairByJsonPath, + printSOLBalance, + getSPLBalance, +} from "../../../../utils"; +import { populateJitoLeaderArray } from "../streaming/stream-trader"; +import { sendBundle } from "../jito/bundle"; +import { AnchorProvider } from "@coral-xyz/anchor"; +import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; +let wallet: Keypair; +let quoteAmount: TokenAmount; +export const solanaConnection = new Connection(RPC_ENDPOINT, { + wsEndpoint: RPC_WEBSOCKET_ENDPOINT, +}); + +// Init funtions right here + +export async function init(): Promise { + logger.level = LOG_LEVEL; + + // get wallet + wallet = Keypair.fromSecretKey(bs58.decode(PRIVATE_KEY)); + logger.info(`Wallet Address: ${wallet.publicKey}`); + + logger.info(`Any Buys using WSOL`); + + // check existing wallet for associated token account of quote mint + const SOLBalance = await solanaConnection.getBalance(wallet.publicKey); + if (SOLBalance === 0) { + throw new Error(`No SOL balance left in wallet: ${wallet.publicKey}`); + } + + await populateJitoLeaderArray(); +} diff --git a/src/Trading_dev/grpc-pf-sniper/.DS_Store b/src/Trading_dev/grpc-pf-sniper/.DS_Store new file mode 100644 index 0000000..f7f871e Binary files /dev/null and b/src/Trading_dev/grpc-pf-sniper/.DS_Store differ diff --git a/src/Trading_dev/grpc-pf-sniper/README.md b/src/Trading_dev/grpc-pf-sniper/README.md new file mode 100644 index 0000000..4f594d4 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/README.md @@ -0,0 +1,32 @@ +# *Geyser grpc Pump.fun Sniper Bot (Beta)* + +## How it works + +- It uses the geyser grpc plugin that subscribe all the latest slot that receive from the grpc server. +- It basically only consider the slot or block in "processed" commitment level to make sure the request can land in the next block or next few block(what we expected). + +- Use a grpc subscription to subscribe the transactions that including the solana account of the Pump.fun Token Mint Authority and listen for the mint event (https://solscan.io/account/TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM). +- Once the mint event is detected, it will send a snipe transaction to snipe the token! +- it uses SOL for settlement, buy using SOL, sell for SOL. + +## Prerequisites + +- run `ts-node src/streaming/snipe-create.ts -h` to test the snipe-create command and see the available options +- to change the parameters, you can modify the .env file +- to have a try, run ```ts-node src/streaming/snipe-create.ts --auto-sell --jito --n 3``` + +## Code usage + +- constants/constants.ts: retriving the variable in .env + +- streaming/pump.fun.ts: subscribing any pump.fun create token's txns of newest block in processed level + +- src/jito/bundle.ts: sending the bundle with tips to jito + +- src/transaction/transaction.ts: main functions of createAndBuy, buy, and sell + +- src/pumpdotfun-sdk/*: constructing the proper instructions of create, buy, and sell + +- src/streaming/snipe-create.ts: a cli interface to interact the whole dir + +- src/streaming/grpc-requests-type.ts: different grpc request types for sniping on pump.fun diff --git a/src/Trading_dev/grpc-pf-sniper/command.sh b/src/Trading_dev/grpc-pf-sniper/command.sh new file mode 100644 index 0000000..7e81208 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/command.sh @@ -0,0 +1 @@ +ts-node src/streaming/snipe-create.ts --auto-sell --jito --n 3 \ No newline at end of file diff --git a/src/Trading_dev/grpc-pf-sniper/src/.DS_Store b/src/Trading_dev/grpc-pf-sniper/src/.DS_Store new file mode 100644 index 0000000..2ae1ed0 Binary files /dev/null and b/src/Trading_dev/grpc-pf-sniper/src/.DS_Store differ diff --git a/src/Trading_dev/grpc-pf-sniper/src/constants/constants.ts b/src/Trading_dev/grpc-pf-sniper/src/constants/constants.ts new file mode 100644 index 0000000..acf7600 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/constants/constants.ts @@ -0,0 +1,19 @@ +import { logger, retrieveEnvVariable } from "../../../../utils"; +import { + Commitment + } from "@solana/web3.js"; +export const NETWORK = 'mainnet-beta'; +export const COMMITMENT_LEVEL: Commitment = retrieveEnvVariable('COMMITMENT_LEVEL', logger) as Commitment; +export const RPC_ENDPOINT = retrieveEnvVariable('MAINNET_ENDPOINT', logger); +export const RPC_WEBSOCKET_ENDPOINT = retrieveEnvVariable('WS_MAINNET_ENDPOINT', logger); +export const GRPC_XTOKEN = retrieveEnvVariable('GRPC_XTOKEN', logger); +export const LOG_LEVEL = retrieveEnvVariable('LOG_LEVEL', logger); +export const PRIVATE_KEY = retrieveEnvVariable('PRIVATE_KEY', logger); +export const QUOTE_AMOUNT = retrieveEnvVariable('QUOTE_AMOUNT', logger); +export const JITO_TIPS = retrieveEnvVariable('JITO_FEE', logger); +export const AUTO_SELL = retrieveEnvVariable('AUTO_SELL', logger) === 'true'; +export const AUTO_SELL_TIMEOUT = retrieveEnvVariable('AUTO_SELL_TIMEOUT', logger); +export {ComputeBudgetProgram, Connection, + Keypair, LAMPORTS_PER_SOL, PublicKey, SystemProgram, + TransactionMessage, VersionedTransaction, Transaction, + Commitment} from "@solana/web3.js"; \ No newline at end of file diff --git a/src/Trading_dev/grpc-pf-sniper/src/constants/index.ts b/src/Trading_dev/grpc-pf-sniper/src/constants/index.ts new file mode 100644 index 0000000..c7582ff --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/constants/index.ts @@ -0,0 +1 @@ +export * from "./constants" \ No newline at end of file diff --git a/src/Trading_dev/grpc-pf-sniper/src/jito/bundle.ts b/src/Trading_dev/grpc-pf-sniper/src/jito/bundle.ts new file mode 100644 index 0000000..3fdd55e --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/jito/bundle.ts @@ -0,0 +1,133 @@ +import { + Connection, + PublicKey, + Keypair, + VersionedTransaction, + MessageV0, + LAMPORTS_PER_SOL + } + from '@solana/web3.js'; + import { Bundle } from 'jito-ts/dist/sdk/block-engine/types'; + import * as Fs from 'fs'; + require('dotenv').config(); + import { searcherClient } from 'jito-ts/dist/sdk/block-engine/searcher'; + import { + ChannelCredentials, + ChannelOptions, + ClientReadableStream, + ServiceError, + } from '@grpc/grpc-js'; + import { SearcherServiceClient } from 'jito-ts/dist/gen/block-engine/searcher' + import { + PRIVATE_KEY, + RPC_ENDPOINT, + RPC_WEBSOCKET_ENDPOINT, + JITO_TIPS + } from '../constants'; + + import bs58 from 'bs58'; + import { logger } from '../utils/logger'; + import { bundle } from 'jito-ts'; + const blockEngineUrl = process.env.BLOCK_ENGINE_URL || ''; + logger.info(`BLOCK_ENGINE_URL: ${blockEngineUrl}`); + const c = searcherClient(blockEngineUrl, undefined); + export const searcherClientAdv = ( + url: string, + authKeypair: Keypair | undefined, + grpcOptions?: Partial + ): SearcherServiceClient => { + const client: SearcherServiceClient = new SearcherServiceClient( + url, + ChannelCredentials.createSsl(), + { ...grpcOptions } + ); + + return client; + } + + + // Get Tip Accounts + + let tipAccounts: string[] = []; + (async () => { + try { + tipAccounts = await c.getTipAccounts(); + // console.log('Result:', tipAccounts); + } catch (error) { + console.error('Error:', error); + } + })(); + + + + export async function sendBundle(latestBlockhash: string, transaction: VersionedTransaction, mint: PublicKey, masterKeypair: Keypair) { + + try { + logger.info(`Fetching and adding tip`); + const _tipAccount = tipAccounts[Math.floor(Math.random() * 6)]; + const tipAccount = new PublicKey(_tipAccount); + const b = new Bundle([transaction], 3); + const jito_tips = parseFloat(JITO_TIPS); + b.addTipTx( + masterKeypair, + jito_tips*LAMPORTS_PER_SOL, // Adjust Jito tip amount here + tipAccount, + latestBlockhash + ); + logger.info(`Sending bundle`); + const bundleResult = await c.sendBundle(b); + logger.info(`Sent bundle! bundleResult = ${bundleResult}`); + logger.info( + { + Pumpfun:`https://pump.fun/${mint.toBase58()}` + }, + ); + + + } + + catch (error) { + logger.error(error); + + } + + } + + // Get leader schedule + + // This was when I was experimenting with only sending the buy tx when a Jito leader was up or going to be up in the next slot so that I wouldn't + // have to wait multiple slots for the tx to be processed. I ended up not using this feature as it couldn't get it working correctly before I moved on. + + export async function storeJitoLeaderSchedule() { + + const cs = searcherClientAdv(blockEngineUrl, undefined); + + + const leaderSchedule = new Set(); + + cs.getConnectedLeadersRegioned({ regions: ["tokyo", "amsterdam", "ny", "frankfurt"] }, (error, response) => { + + + for (let key in response) { + if (key === 'connectedValidators') { + let validators = response[key]; + for (let validatorKey in validators) { + // Each validator object + let validator = validators[validatorKey]; + // Assuming `slots` is an array inside each validator object + Object.keys(validator.connectedValidators).forEach((key: string) => { + const slotsArray: number[][] = Object.values(validator.connectedValidators[key]); // Assume SlotList is an array of arrays + const flattenedSlotsArray: number[] = slotsArray.flat(); // Flatten the array + flattenedSlotsArray.forEach((slot: number) => { + leaderSchedule.add(slot); + }); + }); + } + } + } + + //console.log(leaderSchedule); + }); + + return leaderSchedule; + } \ No newline at end of file diff --git a/src/Trading_dev/grpc-pf-sniper/src/jito/index.ts b/src/Trading_dev/grpc-pf-sniper/src/jito/index.ts new file mode 100644 index 0000000..cf76714 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/jito/index.ts @@ -0,0 +1 @@ +export * from "./bundle"; \ No newline at end of file diff --git a/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/basic/index.ts b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/basic/index.ts new file mode 100644 index 0000000..8b65d5d --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/basic/index.ts @@ -0,0 +1,165 @@ +// import dotenv from "dotenv"; +// import fs from "fs"; +// import { Connection, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js"; +// import { DEFAULT_DECIMALS, PumpFunSDK } from "../../src"; +// import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; +// import { AnchorProvider } from "@coral-xyz/anchor"; +// import { +// getOrCreateKeypair, +// getSPLBalance, +// printSOLBalance, +// printSPLBalance, +// } from "../util"; + +// const KEYS_FOLDER = __dirname + "/.keys"; +// const SLIPPAGE_BASIS_POINTS = 100n; + +// //create token example: +// //https://solscan.io/tx/bok9NgPeoJPtYQHoDqJZyRDmY88tHbPcAk1CJJsKV3XEhHpaTZhUCG3mA9EQNXcaUfNSgfPkuVbEsKMp6H7D9NY +// //devnet faucet +// //https://faucet.solana.com/ + +// const main = async () => { +// dotenv.config(); + +// if (!process.env.HELIUS_RPC_URL) { +// console.error("Please set HELIUS_RPC_URL in .env file"); +// console.error( +// "Example: HELIUS_RPC_URL=https://mainnet.helius-rpc.com/?api-key=" +// ); +// console.error("Get one at: https://www.helius.dev"); +// return; +// } + +// let connection = new Connection(process.env.HELIUS_RPC_URL || ""); + +// let wallet = new NodeWallet(new Keypair()); //note this is not used +// const provider = new AnchorProvider(connection, wallet, { +// commitment: "finalized", +// }); + +// const testAccount = getOrCreateKeypair(KEYS_FOLDER, "test-account"); +// const mint = getOrCreateKeypair(KEYS_FOLDER, "mint"); + +// await printSOLBalance( +// connection, +// testAccount.publicKey, +// "Test Account keypair" +// ); + +// let sdk = new PumpFunSDK(provider); + +// let globalAccount = await sdk.getGlobalAccount(); +// console.log(globalAccount); + +// let currentSolBalance = await connection.getBalance(testAccount.publicKey); +// if (currentSolBalance == 0) { +// console.log( +// "Please send some SOL to the test-account:", +// testAccount.publicKey.toBase58() +// ); +// return; +// } + +// console.log(await sdk.getGlobalAccount()); + +// //Check if mint already exists +// let boundingCurveAccount = await sdk.getBondingCurveAccount(mint.publicKey); +// if (!boundingCurveAccount) { +// let tokenMetadata = { +// name: "TST-7", +// symbol: "TST-7", +// description: "TST-7: This is a test token", +// file: await fs.openAsBlob("example/basic/random.png"), +// }; + +// let createResults = await sdk.createAndBuy( +// testAccount, +// mint, +// tokenMetadata, +// BigInt(0.0001 * LAMPORTS_PER_SOL), +// SLIPPAGE_BASIS_POINTS, +// { +// unitLimit: 250000, +// unitPrice: 250000, +// } +// ); + +// if (createResults.success) { +// console.log("Success:", `https://pump.fun/${mint.publicKey.toBase58()}`); +// boundingCurveAccount = await sdk.getBondingCurveAccount(mint.publicKey); +// console.log("Bonding curve after create and buy", boundingCurveAccount); +// printSPLBalance(connection, mint.publicKey, testAccount.publicKey); +// } +// } else { +// console.log("boundingCurveAccount", boundingCurveAccount); +// console.log("Success:", `https://pump.fun/${mint.publicKey.toBase58()}`); +// printSPLBalance(connection, mint.publicKey, testAccount.publicKey); +// } + +// if (boundingCurveAccount) { +// //buy 0.0001 SOL worth of tokens +// let buyResults = await sdk.buy( +// testAccount, +// mint.publicKey, +// BigInt(0.0001 * LAMPORTS_PER_SOL), +// SLIPPAGE_BASIS_POINTS, +// { +// unitLimit: 250000, +// unitPrice: 250000, +// } +// ); + +// if (buyResults.success) { +// printSPLBalance(connection, mint.publicKey, testAccount.publicKey); +// console.log( +// "Bonding curve after buy", +// await sdk.getBondingCurveAccount(mint.publicKey) +// ); +// } else { +// console.log("Buy failed"); +// } + +// //sell all tokens +// let currentSPLBalance = await getSPLBalance( +// connection, +// mint.publicKey, +// testAccount.publicKey +// ); +// console.log("currentSPLBalance", currentSPLBalance); +// if (currentSPLBalance) { +// let sellResults = await sdk.sell( +// testAccount, +// mint.publicKey, +// BigInt(currentSPLBalance * Math.pow(10, DEFAULT_DECIMALS)), +// SLIPPAGE_BASIS_POINTS, +// { +// unitLimit: 250000, +// unitPrice: 250000, +// } +// ); +// if (sellResults.success) { +// await printSOLBalance( +// connection, +// testAccount.publicKey, +// "Test Account keypair" +// ); + +// printSPLBalance( +// connection, +// mint.publicKey, +// testAccount.publicKey, +// "After SPL sell all" +// ); +// console.log( +// "Bonding curve after sell", +// await sdk.getBondingCurveAccount(mint.publicKey) +// ); +// } else { +// console.log("Sell failed"); +// } +// } +// } +// }; + +// main(); diff --git a/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/basic/random.png b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/basic/random.png new file mode 100644 index 0000000..6c107cd Binary files /dev/null and b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/basic/random.png differ diff --git a/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/events/index.ts b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/events/index.ts new file mode 100644 index 0000000..cfd3bc7 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/events/index.ts @@ -0,0 +1,44 @@ +import dotenv from "dotenv"; +import { Connection, Keypair } from "@solana/web3.js"; +import { PumpFunSDK } from "../../src"; +import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; +import { AnchorProvider } from "@coral-xyz/anchor"; + +const main = async () => { + dotenv.config(); + + if (!process.env.HELIUS_RPC_URL) { + console.error("Please set HELIUS_RPC_URL in .env file"); + console.error( + "Example: HELIUS_RPC_URL=https://mainnet.helius-rpc.com/?api-key=" + ); + console.error("Get one at: https://www.helius.dev"); + return; + } + + let connection = new Connection(process.env.HELIUS_RPC_URL || ""); + + let wallet = new NodeWallet(new Keypair()); //note this is not used + const provider = new AnchorProvider(connection, wallet, { + commitment: "finalized", + }); + + let sdk = new PumpFunSDK(provider); + + let createEvent = sdk.addEventListener("createEvent", (event) => { + console.log("createEvent", event); + }); + console.log("createEvent", createEvent); + + let tradeEvent = sdk.addEventListener("tradeEvent", (event) => { + console.log("tradeEvent", event); + }); + console.log("tradeEvent", tradeEvent); + + let completeEvent = sdk.addEventListener("completeEvent", (event) => { + console.log("completeEvent", event); + }); + console.log("completeEvent", completeEvent); +}; + +main(); diff --git a/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/util.ts b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/util.ts new file mode 100644 index 0000000..9ddd534 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/example/util.ts @@ -0,0 +1,91 @@ +import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; +import { getAssociatedTokenAddressSync } from "@solana/spl-token"; +import { + Keypair, + PublicKey, + Connection, + LAMPORTS_PER_SOL, +} from "@solana/web3.js"; +import { sha256 } from "js-sha256"; + +import fs from "fs"; + +export function getOrCreateKeypair(dir: string, keyName: string): Keypair { + if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); + const authorityKey = dir + "/" + keyName + ".json"; + if (fs.existsSync(authorityKey)) { + const data: { + secretKey: string; + publicKey: string; + } = JSON.parse(fs.readFileSync(authorityKey, "utf-8")); + return Keypair.fromSecretKey(bs58.decode(data.secretKey)); + } else { + const keypair = Keypair.generate(); + keypair.secretKey; + fs.writeFileSync( + authorityKey, + JSON.stringify({ + secretKey: bs58.encode(keypair.secretKey), + publicKey: keypair.publicKey.toBase58(), + }) + ); + return keypair; + } +} + +export const printSOLBalance = async ( + connection: Connection, + pubKey: PublicKey, + info: string = "" +) => { + const balance = await connection.getBalance(pubKey); + console.log( + `${info ? info + " " : ""}${pubKey.toBase58()}:`, + balance / LAMPORTS_PER_SOL, + `SOL` + ); +}; + +export const getSPLBalance = async ( + connection: Connection, + mintAddress: PublicKey, + pubKey: PublicKey, + allowOffCurve: boolean = false +) => { + try { + let ata = getAssociatedTokenAddressSync(mintAddress, pubKey, allowOffCurve); + const balance = await connection.getTokenAccountBalance(ata, "processed"); + return balance.value.uiAmount; + } catch (e) {} + return null; +}; + +export const printSPLBalance = async ( + connection: Connection, + mintAddress: PublicKey, + user: PublicKey, + info: string = "" +) => { + const balance = await getSPLBalance(connection, mintAddress, user); + if (balance === null) { + console.log( + `${info ? info + " " : ""}${user.toBase58()}:`, + "No Account Found" + ); + } else { + console.log(`${info ? info + " " : ""}${user.toBase58()}:`, balance); + } +}; + +export const baseToValue = (base: number, decimals: number): number => { + return base * Math.pow(10, decimals); +}; + +export const valueToBase = (value: number, decimals: number): number => { + return value / Math.pow(10, decimals); +}; + +//i.e. account:BondingCurve +export function getDiscriminator(name: string) { + return sha256.digest(name).slice(0, 8); +} diff --git a/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/IDL/index.ts b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/IDL/index.ts new file mode 100644 index 0000000..65beef3 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/IDL/index.ts @@ -0,0 +1,2 @@ +export { default as IDL } from "./pump-fun.json"; +export { PumpFun } from "./pump-fun"; \ No newline at end of file diff --git a/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/IDL/pump-fun.json b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/IDL/pump-fun.json new file mode 100644 index 0000000..eea03f0 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/IDL/pump-fun.json @@ -0,0 +1,925 @@ +{ + "address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P", + "metadata": { + "name": "pump", + "version": "0.1.0", + "spec": "0.1.0" + }, + "instructions": [ + { + "name": "initialize", + "discriminator": [175, 175, 109, 31, 13, 152, 155, 237], + "docs": ["Creates the global state."], + "accounts": [ + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "setParams", + "discriminator": [165, 31, 134, 53, 189, 180, 130, 255], + "docs": ["Sets the global state parameters."], + "accounts": [ + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "event_authority", + "address": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1" + }, + { + "name": "program", + "address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" + } + ], + "args": [ + { + "name": "feeRecipient", + "type": "pubkey" + }, + { + "name": "initialVirtualTokenReserves", + "type": "u64" + }, + { + "name": "initialVirtualSolReserves", + "type": "u64" + }, + { + "name": "initialRealTokenReserves", + "type": "u64" + }, + { + "name": "tokenTotalSupply", + "type": "u64" + }, + { + "name": "feeBasisPoints", + "type": "u64" + } + ] + }, + { + "name": "create", + "discriminator": [24, 30, 200, 40, 5, 28, 7, 119], + "docs": ["Creates a new coin and bonding curve."], + "accounts": [ + { + "name": "mint", + "writable": true, + "signer": true + }, + { + "name": "mint_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 109, + 105, + 110, + 116, + 45, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ] + } + ] + } + }, + { + "name": "bonding_curve", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ] + }, + { + "kind": "account", + "path": "mint" + } + ] + } + }, + { + "name": "associated_bonding_curve", + "writable": true, + "signer": false + }, + { + "name": "global", + "writable": false, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "mpl_token_metadata", + "address": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" + }, + { + "name": "metadata", + "writable": true, + "signer": false + }, + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "associated_token_program", + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + }, + { + "name": "rent", + "address": "SysvarRent111111111111111111111111111111111" + }, + { + "name": "event_authority", + "address": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1" + }, + { + "name": "program", + "address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" + } + ], + "args": [ + { + "name": "name", + "type": "string" + }, + { + "name": "symbol", + "type": "string" + }, + { + "name": "uri", + "type": "string" + } + ] + }, + { + "name": "buy", + "discriminator": [102, 6, 61, 18, 1, 218, 235, 234], + "docs": ["Buys tokens from a bonding curve."], + "accounts": [ + { + "name": "global", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "fee_recipient", + "writable": true, + "signer": false + }, + { + "name": "mint", + "writable": false, + "signer": false + }, + { + "name": "bonding_curve", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ] + }, + { + "kind": "account", + "path": "mint" + } + ] + } + }, + { + "name": "associated_bonding_curve", + "writable": true, + "signer": false + }, + { + "name": "associated_user", + "writable": true, + "signer": false + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "rent", + "address": "SysvarRent111111111111111111111111111111111" + }, + { + "name": "event_authority", + "address": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1" + }, + { + "name": "program", + "address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "maxSolCost", + "type": "u64" + } + ] + }, + { + "name": "sell", + "discriminator": [51, 230, 133, 164, 1, 127, 131, 173], + "docs": ["Sells tokens into a bonding curve."], + "accounts": [ + { + "name": "global", + "writable": false, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "feeRecipient", + "writable": true, + "signer": false + }, + { + "name": "mint", + "writable": false, + "signer": false + }, + { + "name": "bonding_curve", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ] + }, + { + "kind": "account", + "path": "mint" + } + ] + } + }, + { + "name": "associatedBondingCurve", + "writable": true, + "signer": false + }, + { + "name": "associatedUser", + "writable": true, + "signer": false + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "associated_token_program", + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "event_authority", + "address": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1" + }, + { + "name": "program", + "address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "minSolOutput", + "type": "u64" + } + ] + }, + { + "name": "withdraw", + "discriminator": [183, 18, 70, 156, 148, 109, 161, 34], + "docs": [ + "Allows the admin to withdraw liquidity for a migration once the bonding curve completes" + ], + "accounts": [ + { + "name": "global", + "writable": false, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "lastWithdraw", + "writable": true, + "signer": false + }, + { + "name": "mint", + "writable": false, + "signer": false + }, + { + "name": "bonding_curve", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ] + }, + { + "kind": "account", + "path": "mint" + } + ] + } + }, + { + "name": "associatedBondingCurve", + "writable": true, + "signer": false + }, + { + "name": "associatedUser", + "writable": true, + "signer": false + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "rent", + "address": "SysvarRent111111111111111111111111111111111" + }, + { + "name": "event_authority", + "address": "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1" + }, + { + "name": "program", + "address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "BondingCurve", + "discriminator": [ + 23, + 183, + 248, + 55, + 96, + 216, + 172, + 96 + ] + }, + { + "name": "Global", + "discriminator": [ + 167, + 232, + 232, + 177, + 200, + 108, + 114, + 127 + ] + } + ], + "events": [ + { + "name": "CreateEvent", + "discriminator": [27, 114, 169, 77, 222, 235, 99, 118] + }, + { + "name": "TradeEvent", + "discriminator": [189, 219, 127, 211, 78, 230, 97, 238] + }, + { + "name": "CompleteEvent", + "discriminator": [95, 114, 97, 156, 212, 46, 152, 8] + }, + { + "name": "SetParamsEvent", + "discriminator": [223, 195, 159, 246, 62, 48, 143, 131] + } + ], + "types": [ + { + "name": "Global", + "type": { + "kind": "struct", + "fields": [ + { + "name": "initialized", + "type": "bool" + }, + { + "name": "authority", + "type": "pubkey" + }, + { + "name": "feeRecipient", + "type": "pubkey" + }, + { + "name": "initialVirtualTokenReserves", + "type": "u64" + }, + { + "name": "initialVirtualSolReserves", + "type": "u64" + }, + { + "name": "initialRealTokenReserves", + "type": "u64" + }, + { + "name": "tokenTotalSupply", + "type": "u64" + }, + { + "name": "feeBasisPoints", + "type": "u64" + } + ] + } + }, + { + "name": "LastWithdraw", + "type": { + "kind": "struct", + "fields": [ + { + "name": "lastWithdrawTimestamp", + "type": "i64" + } + ] + } + }, + { + "name": "BondingCurve", + "type": { + "kind": "struct", + "fields": [ + { + "name": "virtualTokenReserves", + "type": "u64" + }, + { + "name": "virtualSolReserves", + "type": "u64" + }, + { + "name": "realTokenReserves", + "type": "u64" + }, + { + "name": "realSolReserves", + "type": "u64" + }, + { + "name": "tokenTotalSupply", + "type": "u64" + }, + { + "name": "complete", + "type": "bool" + } + ] + } + }, + { + "name": "CreateEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": "string", + "index": false + }, + { + "name": "symbol", + "type": "string", + "index": false + }, + { + "name": "uri", + "type": "string", + "index": false + }, + { + "name": "mint", + "type": "pubkey", + "index": false + }, + { + "name": "bondingCurve", + "type": "pubkey", + "index": false + }, + { + "name": "user", + "type": "pubkey", + "index": false + } + ] + } + }, + { + "name": "TradeEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "mint", + "type": "pubkey", + "index": false + }, + { + "name": "solAmount", + "type": "u64", + "index": false + }, + { + "name": "tokenAmount", + "type": "u64", + "index": false + }, + { + "name": "isBuy", + "type": "bool", + "index": false + }, + { + "name": "user", + "type": "pubkey", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + }, + { + "name": "virtualSolReserves", + "type": "u64", + "index": false + }, + { + "name": "virtualTokenReserves", + "type": "u64", + "index": false + }, + { + "name": "realSolReserves", + "type": "u64", + "index": false + }, + { + "name": "realTokenReserves", + "type": "u64", + "index": false + } + ] + } + }, + { + "name": "CompleteEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "user", + "type": "pubkey", + "index": false + }, + { + "name": "mint", + "type": "pubkey", + "index": false + }, + { + "name": "bondingCurve", + "type": "pubkey", + "index": false + }, + { + "name": "timestamp", + "type": "i64", + "index": false + } + ] + } + }, + { + "name": "SetParamsEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "feeRecipient", + "type": "pubkey", + "index": false + }, + { + "name": "initialVirtualTokenReserves", + "type": "u64", + "index": false + }, + { + "name": "initialVirtualSolReserves", + "type": "u64", + "index": false + }, + { + "name": "initialRealTokenReserves", + "type": "u64", + "index": false + }, + { + "name": "tokenTotalSupply", + "type": "u64", + "index": false + }, + { + "name": "feeBasisPoints", + "type": "u64", + "index": false + } + ] + } + } + ], + "errors": [ + { + "code": 6000, + "name": "NotAuthorized", + "msg": "The given account is not authorized to execute this instruction." + }, + { + "code": 6001, + "name": "AlreadyInitialized", + "msg": "The program is already initialized." + }, + { + "code": 6002, + "name": "TooMuchSolRequired", + "msg": "slippage: Too much SOL required to buy the given amount of tokens." + }, + { + "code": 6003, + "name": "TooLittleSolReceived", + "msg": "slippage: Too little SOL received to sell the given amount of tokens." + }, + { + "code": 6004, + "name": "MintDoesNotMatchBondingCurve", + "msg": "The mint does not match the bonding curve." + }, + { + "code": 6005, + "name": "BondingCurveComplete", + "msg": "The bonding curve has completed and liquidity migrated to raydium." + }, + { + "code": 6006, + "name": "BondingCurveNotComplete", + "msg": "The bonding curve has not completed." + }, + { + "code": 6007, + "name": "NotInitialized", + "msg": "The program is not initialized." + }, + { + "code": 6008, + "name": "WithdrawTooFrequent", + "msg": "Withdraw too frequent" + } + ] +} diff --git a/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/IDL/pump-fun.ts b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/IDL/pump-fun.ts new file mode 100644 index 0000000..99cc93e --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/IDL/pump-fun.ts @@ -0,0 +1,865 @@ +export type PumpFun = { + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + metadata: { + name: "pump"; + version: "0.1.0"; + spec: "0.1.0"; + }; + instructions: [ + { + name: "initialize"; + discriminator: [175, 175, 109, 31, 13, 152, 155, 237]; + docs: ["Creates the global state."]; + accounts: [ + { + name: "global"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "user"; + writable: true; + signer: true; + }, + { + name: "systemProgram"; + address: "11111111111111111111111111111111"; + } + ]; + args: []; + }, + { + name: "setParams"; + discriminator: [165, 31, 134, 53, 189, 180, 130, 255]; + docs: ["Sets the global state parameters."]; + accounts: [ + { + name: "global"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "user"; + writable: true; + signer: true; + }, + { + name: "systemProgram"; + address: "11111111111111111111111111111111"; + }, + { + name: "eventAuthority"; + address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; + }, + { + name: "program"; + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + } + ]; + args: [ + { + name: "feeRecipient"; + type: "pubkey"; + }, + { + name: "initialVirtualTokenReserves"; + type: "u64"; + }, + { + name: "initialVirtualSolReserves"; + type: "u64"; + }, + { + name: "initialRealTokenReserves"; + type: "u64"; + }, + { + name: "tokenTotalSupply"; + type: "u64"; + }, + { + name: "feeBasisPoints"; + type: "u64"; + } + ]; + }, + { + name: "create"; + discriminator: [24, 30, 200, 40, 5, 28, 7, 119]; + docs: ["Creates a new coin and bonding curve."]; + accounts: [ + { + name: "mint"; + writable: true; + signer: true; + }, + { + name: "mint_authority"; + pda: { + seeds: [ + { + kind: "const"; + value: [ + 109, + 105, + 110, + 116, + 45, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ]; + } + ]; + }; + }, + { + name: "bondingCurve"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ]; + }, + { + kind: "account"; + path: "mint"; + } + ]; + }; + }, + { + name: "associatedBondingCurve"; + writable: true; + signer: false; + }, + { + name: "global"; + writable: false; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "mplTokenMetadata"; + address: "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"; + }, + { + name: "metadata"; + writable: true; + signer: false; + }, + { + name: "user"; + isMut: true; + isSigner: true; + }, + { + name: "systemProgram"; + address: "11111111111111111111111111111111"; + }, + { + name: "tokenProgram"; + address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; + }, + { + name: "associatedTokenProgram"; + address: "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"; + }, + { + name: "rent"; + address: "SysvarRent111111111111111111111111111111111"; + }, + { + name: "eventAuthority"; + address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; + }, + { + name: "program"; + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + } + ]; + args: [ + { + name: "name"; + type: "string"; + }, + { + name: "symbol"; + type: "string"; + }, + { + name: "uri"; + type: "string"; + } + ]; + }, + { + name: "buy"; + discriminator: [102, 6, 61, 18, 1, 218, 235, 234]; + docs: ["Buys tokens from a bonding curve."]; + accounts: [ + { + name: "global"; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "feeRecipient"; + writable: true; + signer: false; + }, + { + name: "mint"; + writable: false; + signer: false; + }, + { + name: "bondingCurve"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ]; + }, + { + kind: "account"; + path: "mint"; + } + ]; + }; + }, + { + name: "associatedBondingCurve"; + writable: true; + signer: false; + }, + { + name: "associatedUser"; + writable: true; + signer: false; + }, + { + name: "user"; + writable: true; + signer: true; + }, + { + name: "systemProgram"; + address: "11111111111111111111111111111111"; + }, + { + name: "tokenProgram"; + address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; + }, + { + name: "rent"; + address: "SysvarRent111111111111111111111111111111111"; + }, + { + name: "eventAuthority"; + address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; + }, + { + name: "program"; + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + } + ]; + args: [ + { + name: "amount"; + type: "u64"; + }, + { + name: "maxSolCost"; + type: "u64"; + } + ]; + }, + { + name: "sell"; + discriminator: [51, 230, 133, 164, 1, 127, 131, 173]; + docs: ["Sells tokens into a bonding curve."]; + accounts: [ + { + name: "global"; + writable: false; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "feeRecipient"; + writable: true; + signer: false; + }, + { + name: "mint"; + writable: false; + signer: false; + }, + { + name: "bondingCurve"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ]; + }, + { + kind: "account"; + path: "mint"; + } + ]; + }; + }, + { + name: "associatedBondingCurve"; + writable: true; + signer: false; + }, + { + name: "associatedUser"; + writable: true; + signer: false; + }, + { + name: "user"; + writable: true; + signer: true; + }, + { + name: "systemProgram"; + address: "11111111111111111111111111111111"; + }, + { + name: "associatedTokenProgram"; + address: "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"; + }, + { + name: "tokenProgram"; + address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; + }, + { + name: "eventAuthority"; + address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; + }, + { + name: "program"; + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + } + ]; + args: [ + { + name: "amount"; + type: "u64"; + }, + { + name: "minSolOutput"; + type: "u64"; + } + ]; + }, + { + name: "withdraw"; + discriminator: [183, 18, 70, 156, 148, 109, 161, 34]; + docs: [ + "Allows the admin to withdraw liquidity for a migration once the bonding curve completes" + ]; + accounts: [ + { + name: "global"; + writable: false; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "lastWithdraw"; + writable: true; + signer: false; + }, + { + name: "mint"; + writable: false; + signer: false; + }, + { + name: "bondingCurve"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ]; + }, + { + kind: "account"; + path: "mint"; + } + ]; + }; + }, + { + name: "associatedBondingCurve"; + writable: true; + signer: false; + }, + { + name: "associatedUser"; + writable: true; + signer: false; + }, + { + name: "user"; + writable: true; + signer: true; + }, + { + name: "system_program"; + address: "11111111111111111111111111111111"; + }, + { + name: "tokenProgram"; + address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; + }, + { + name: "rent"; + address: "SysvarRent111111111111111111111111111111111"; + }, + { + name: "eventAuthority"; + address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; + }, + { + name: "program"; + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + } + ]; + args: []; + } + ]; + accounts: [ + { + name: "bondingCurve"; + discriminator: [23, 183, 248, 55, 96, 216, 172, 96]; + }, + { + name: "global"; + discriminator: [167, 232, 232, 177, 200, 108, 114, 127]; + } + ]; + events: [ + { + name: "createEvent"; + discriminator: [27, 114, 169, 77, 222, 235, 99, 118]; + }, + { + name: "tradeEvent"; + discriminator: [189, 219, 127, 211, 78, 230, 97, 238]; + }, + { + name: "completeEvent"; + discriminator: [95, 114, 97, 156, 212, 46, 152, 8]; + }, + { + name: "setParamsEvent"; + discriminator: [223, 195, 159, 246, 62, 48, 143, 131]; + } + ]; + types: [ + { + name: "global"; + type: { + kind: "struct"; + fields: [ + { + name: "initialized"; + type: "bool"; + }, + { + name: "authority"; + type: "pubkey"; + }, + { + name: "feeRecipient"; + type: "pubkey"; + }, + { + name: "initialVirtualTokenReserves"; + type: "u64"; + }, + { + name: "initialVirtualSolReserves"; + type: "u64"; + }, + { + name: "initialRealTokenReserves"; + type: "u64"; + }, + { + name: "tokenTotalSupply"; + type: "u64"; + }, + { + name: "feeBasisPoints"; + type: "u64"; + } + ]; + }; + }, + { + name: "lastWithdraw"; + type: { + kind: "struct"; + fields: [ + { + name: "lastWithdrawTimestamp"; + type: "i64"; + } + ]; + }; + }, + { + name: "bondingCurve"; + type: { + kind: "struct"; + fields: [ + { + name: "virtualTokenReserves"; + type: "u64"; + }, + { + name: "virtualSolReserves"; + type: "u64"; + }, + { + name: "realTokenReserves"; + type: "u64"; + }, + { + name: "realSolReserves"; + type: "u64"; + }, + { + name: "tokenTotalSupply"; + type: "u64"; + }, + { + name: "complete"; + type: "bool"; + } + ]; + }; + }, + { + name: "createEvent"; + type: { + kind: "struct"; + fields: [ + { + name: "name"; + type: "string"; + index: false; + }, + { + name: "symbol"; + type: "string"; + index: false; + }, + { + name: "uri"; + type: "string"; + index: false; + }, + { + name: "mint"; + type: "pubkey"; + index: false; + }, + { + name: "bondingCurve"; + type: "pubkey"; + index: false; + }, + { + name: "user"; + type: "pubkey"; + index: false; + } + ]; + }; + }, + { + name: "tradeEvent"; + type: { + kind: "struct"; + fields: [ + { + name: "mint"; + type: "pubkey"; + index: false; + }, + { + name: "solAmount"; + type: "u64"; + index: false; + }, + { + name: "tokenAmount"; + type: "u64"; + index: false; + }, + { + name: "isBuy"; + type: "bool"; + index: false; + }, + { + name: "user"; + type: "pubkey"; + index: false; + }, + { + name: "timestamp"; + type: "i64"; + index: false; + }, + { + name: "virtualSolReserves"; + type: "u64"; + index: false; + }, + { + name: "virtualTokenReserves"; + type: "u64"; + index: false; + }, + { + name: "realSolReserves"; + type: "u64"; + index: false; + }, + { + name: "realTokenReserves"; + type: "u64"; + index: false; + } + ]; + }; + }, + { + name: "completeEvent"; + type: { + kind: "struct"; + fields: [ + { + name: "user"; + type: "pubkey"; + index: false; + }, + { + name: "mint"; + type: "pubkey"; + index: false; + }, + { + name: "bondingCurve"; + type: "pubkey"; + index: false; + }, + { + name: "timestamp"; + type: "i64"; + index: false; + } + ]; + }; + }, + { + name: "setParamsEvent"; + type: { + kind: "struct"; + fields: [ + { + name: "feeRecipient"; + type: "pubkey"; + index: false; + }, + { + name: "initialVirtualTokenReserves"; + type: "u64"; + index: false; + }, + { + name: "initialVirtualSolReserves"; + type: "u64"; + index: false; + }, + { + name: "initialRealTokenReserves"; + type: "u64"; + index: false; + }, + { + name: "tokenTotalSupply"; + type: "u64"; + index: false; + }, + { + name: "feeBasisPoints"; + type: "u64"; + index: false; + } + ]; + }; + } + ]; + errors: [ + { + code: 6000; + name: "NotAuthorized"; + msg: "The given account is not authorized to execute this instruction."; + }, + { + code: 6001; + name: "AlreadyInitialized"; + msg: "The program is already initialized."; + }, + { + code: 6002; + name: "TooMuchSolRequired"; + msg: "slippage: Too much SOL required to buy the given amount of tokens."; + }, + { + code: 6003; + name: "TooLittleSolReceived"; + msg: "slippage: Too little SOL received to sell the given amount of tokens."; + }, + { + code: 6004; + name: "MintDoesNotMatchBondingCurve"; + msg: "The mint does not match the bonding curve."; + }, + { + code: 6005; + name: "BondingCurveComplete"; + msg: "The bonding curve has completed and liquidity migrated to raydium."; + }, + { + code: 6006; + name: "BondingCurveNotComplete"; + msg: "The bonding curve has not completed."; + }, + { + code: 6007; + name: "NotInitialized"; + msg: "The program is not initialized."; + }, + { + code: 6008; + name: "WithdrawTooFrequent"; + msg: "Withdraw too frequent"; + } + ]; +}; \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/amm.js b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/amm.ts similarity index 73% rename from src/pumpfunsdk/pumpdotfun-sdk/src/amm.js rename to src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/amm.ts index 1799c3d..f48889a 100644 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/amm.js +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/amm.ts @@ -1,26 +1,26 @@ -const { BondingCurveAccount } =require ("./bondingCurveAccount"); -const { GlobalAccount } =require ("./globalAccount"); +import { BondingCurveAccount } from "./bondingCurveAccount"; +import { GlobalAccount } from "./globalAccount"; -// type BuyResult = { -// token_amount: bigint; -// sol_amount: bigint; -// }; +export type BuyResult = { + token_amount: bigint; + sol_amount: bigint; +}; -// type SellResult = { -// token_amount: bigint; -// sol_amount: bigint; -// }; +export type SellResult = { + token_amount: bigint; + sol_amount: bigint; +}; -class AMM { +export class AMM { constructor( - virtualSolReserves, - virtualTokenReserves, - realSolReserves, - realTokenReserves, - initialVirtualTokenReserves + public virtualSolReserves: bigint, + public virtualTokenReserves: bigint, + public realSolReserves: bigint, + public realTokenReserves: bigint, + public initialVirtualTokenReserves: bigint ) {} - static fromGlobalAccount(global) { + static fromGlobalAccount(global: GlobalAccount): AMM { return new AMM( global.initialVirtualSolReserves, global.initialVirtualTokenReserves, @@ -30,7 +30,7 @@ class AMM { ); } - static fromBondingCurveAccount(bonding_curve, initialVirtualTokenReserves) { + static fromBondingCurveAccount(bonding_curve: BondingCurveAccount, initialVirtualTokenReserves: bigint): AMM { return new AMM( bonding_curve.virtualSolReserves, bonding_curve.virtualTokenReserves, @@ -40,7 +40,7 @@ class AMM { ); } - getBuyPrice(tokens){ + getBuyPrice(tokens: bigint): bigint { const product_of_reserves = this.virtualSolReserves * this.virtualTokenReserves; const new_virtual_token_reserves = this.virtualTokenReserves - tokens; const new_virtual_sol_reserves = product_of_reserves / new_virtual_token_reserves + 1n; @@ -48,7 +48,7 @@ class AMM { return amount_needed > 0n ? amount_needed : 0n; } - applyBuy(token_amount ) { + applyBuy(token_amount: bigint): BuyResult { const final_token_amount = token_amount > this.realTokenReserves ? this.realTokenReserves : token_amount; const sol_amount = this.getBuyPrice(final_token_amount); @@ -64,7 +64,7 @@ class AMM { } } - applySell(token_amount ) { + applySell(token_amount: bigint): SellResult { this.virtualTokenReserves = this.virtualTokenReserves + token_amount; this.realTokenReserves = this.realTokenReserves + token_amount; @@ -79,13 +79,10 @@ class AMM { } } - getSellPrice(tokens ) { + getSellPrice(tokens: bigint): bigint { const scaling_factor = this.initialVirtualTokenReserves; const token_sell_proportion = (tokens * scaling_factor) / this.virtualTokenReserves; const sol_received = (this.virtualSolReserves * token_sell_proportion) / scaling_factor; return sol_received < this.realSolReserves ? sol_received : this.realSolReserves; } -} -module.exports = { - AMM } \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/bondingCurveAccount.js b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/bondingCurveAccount.ts similarity index 76% rename from src/pumpfunsdk/pumpdotfun-sdk/src/bondingCurveAccount.js rename to src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/bondingCurveAccount.ts index 70caf83..f2133e5 100644 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/bondingCurveAccount.js +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/bondingCurveAccount.ts @@ -1,16 +1,22 @@ -const { struct, bool, u64, Layout } =require ("@coral-xyz/borsh"); - -class BondingCurveAccount { +import { struct, bool, u64, Layout } from "@coral-xyz/borsh"; +export class BondingCurveAccount { + public discriminator: bigint; + public virtualTokenReserves: bigint; + public virtualSolReserves: bigint; + public realTokenReserves: bigint; + public realSolReserves: bigint; + public tokenTotalSupply: bigint; + public complete: boolean; constructor( - discriminator, - virtualTokenReserves, - virtualSolReserves, - realTokenReserves, - realSolReserves, - tokenTotalSupply, - complete + discriminator: bigint, + virtualTokenReserves: bigint, + virtualSolReserves: bigint, + realTokenReserves: bigint, + realSolReserves: bigint, + tokenTotalSupply: bigint, + complete: boolean ) { this.discriminator = discriminator; this.virtualTokenReserves = virtualTokenReserves; @@ -21,7 +27,7 @@ class BondingCurveAccount { this.complete = complete; } - getBuyPrice(amount) { + getBuyPrice(amount: bigint): bigint { if (this.complete) { throw new Error("Curve is complete"); } @@ -46,7 +52,7 @@ class BondingCurveAccount { return s < this.realTokenReserves ? s : this.realTokenReserves; } - getSellPrice(amount , feeBasisPoints ) { + getSellPrice(amount: bigint, feeBasisPoints: bigint): bigint { if (this.complete) { throw new Error("Curve is complete"); } @@ -66,7 +72,7 @@ class BondingCurveAccount { return n - a; } - getMarketCapSOL() { + getMarketCapSOL(): bigint { if (this.virtualTokenReserves === 0n) { return 0n; } @@ -77,7 +83,7 @@ class BondingCurveAccount { ); } - getFinalMarketCapSOL(feeBasisPoints){ + getFinalMarketCapSOL(feeBasisPoints: bigint): bigint { let totalSellValue = this.getBuyOutPrice( this.realTokenReserves, feeBasisPoints @@ -92,7 +98,7 @@ class BondingCurveAccount { return (this.tokenTotalSupply * totalVirtualValue) / totalVirtualTokens; } - getBuyOutPrice(amount, feeBasisPoints) { + getBuyOutPrice(amount: bigint, feeBasisPoints: bigint): bigint { let solTokens = amount < this.realSolReserves ? this.realSolReserves : amount; let totalSellValue = @@ -103,8 +109,8 @@ class BondingCurveAccount { return totalSellValue + fee; } - static fromBuffer(buffer) { - const structure = struct([ + public static fromBuffer(buffer: Buffer): BondingCurveAccount { + const structure: Layout = struct([ u64("discriminator"), u64("virtualTokenReserves"), u64("virtualSolReserves"), @@ -126,5 +132,3 @@ class BondingCurveAccount { ); } } - -module.exports = {BondingCurveAccount}; \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/events.js b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/events.ts similarity index 75% rename from src/pumpfunsdk/pumpdotfun-sdk/src/events.js rename to src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/events.ts index 8405c4d..bf001f8 100644 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/events.js +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/events.ts @@ -1,6 +1,12 @@ -const { PublicKey } =require ("@solana/web3.js"); +import { PublicKey } from "@solana/web3.js"; +import { + CompleteEvent, + CreateEvent, + SetParamsEvent, + TradeEvent, +} from "./types"; - function toCreateEvent(event) { +export function toCreateEvent(event: CreateEvent): CreateEvent { return { name: event.name, symbol: event.symbol, @@ -11,7 +17,7 @@ const { PublicKey } =require ("@solana/web3.js"); }; } - function toCompleteEvent(event) { +export function toCompleteEvent(event: CompleteEvent): CompleteEvent { return { user: new PublicKey(event.user), mint: new PublicKey(event.mint), @@ -20,7 +26,7 @@ const { PublicKey } =require ("@solana/web3.js"); }; } - function toTradeEvent(event) { +export function toTradeEvent(event: TradeEvent): TradeEvent { return { mint: new PublicKey(event.mint), solAmount: BigInt(event.solAmount), @@ -35,7 +41,7 @@ const { PublicKey } =require ("@solana/web3.js"); }; } - function toSetParamsEvent(event) { +export function toSetParamsEvent(event: SetParamsEvent): SetParamsEvent { return { feeRecipient: new PublicKey(event.feeRecipient), initialVirtualTokenReserves: BigInt(event.initialVirtualTokenReserves), diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/globalAccount.js b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/globalAccount.ts similarity index 62% rename from src/pumpfunsdk/pumpdotfun-sdk/src/globalAccount.js rename to src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/globalAccount.ts index 00451ef..b422c50 100644 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/globalAccount.js +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/globalAccount.ts @@ -1,19 +1,27 @@ -const { PublicKey } =require( "@solana/web3.js"); -const { struct, bool, u64, publicKey, Layout } =require( "@coral-xyz/borsh"); - -class GlobalAccount { +import { PublicKey } from "@solana/web3.js"; +import { struct, bool, u64, publicKey, Layout } from "@coral-xyz/borsh"; +export class GlobalAccount { + public discriminator: bigint; + public initialized: boolean = false; + public authority: PublicKey; + public feeRecipient: PublicKey; + public initialVirtualTokenReserves: bigint; + public initialVirtualSolReserves: bigint; + public initialRealTokenReserves: bigint; + public tokenTotalSupply: bigint; + public feeBasisPoints: bigint; constructor( - discriminator, - initialized, - authority, - feeRecipient, - initialVirtualTokenReserves, - initialVirtualSolReserves, - initialRealTokenReserves, - tokenTotalSupply, - feeBasisPoints + discriminator: bigint, + initialized: boolean, + authority: PublicKey, + feeRecipient: PublicKey, + initialVirtualTokenReserves: bigint, + initialVirtualSolReserves: bigint, + initialRealTokenReserves: bigint, + tokenTotalSupply: bigint, + feeBasisPoints: bigint ) { this.discriminator = discriminator; this.initialized = initialized; @@ -26,7 +34,7 @@ class GlobalAccount { this.feeBasisPoints = feeBasisPoints; } - getInitialBuyPrice(amount) { + getInitialBuyPrice(amount: bigint): bigint { if (amount <= 0n) { return 0n; } @@ -40,8 +48,8 @@ class GlobalAccount { : this.initialRealTokenReserves; } - static fromBuffer(buffer){ - const structure = struct([ + public static fromBuffer(buffer: Buffer): GlobalAccount { + const structure: Layout = struct([ u64("discriminator"), bool("initialized"), publicKey("authority"), @@ -67,5 +75,3 @@ class GlobalAccount { ); } } - -module.exports = {GlobalAccount}; \ No newline at end of file diff --git a/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/index.ts b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/index.ts new file mode 100644 index 0000000..79f3450 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/index.ts @@ -0,0 +1,7 @@ +export * from './pumpfun' +export * from './util' +export * from './types' +export * from './events' +export * from './globalAccount' +export * from './bondingCurveAccount' +export * from './amm' diff --git a/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/pumpfun.ts b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/pumpfun.ts new file mode 100644 index 0000000..2883cbd --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/pumpfun.ts @@ -0,0 +1,459 @@ +import { + Commitment, + Connection, + Finality, + Keypair, + PublicKey, + Transaction, +} from "@solana/web3.js"; +import { Program, Provider } from "@coral-xyz/anchor"; +import { GlobalAccount } from "./globalAccount"; +import { + CompleteEvent, + CreateEvent, + CreateTokenMetadata, + PriorityFee, + PumpFunEventHandlers, + PumpFunEventType, + SetParamsEvent, + TradeEvent, + TransactionResult, +} from "./types"; +import { + toCompleteEvent, + toCreateEvent, + toSetParamsEvent, + toTradeEvent, +} from "./events"; +import { + createAssociatedTokenAccountIdempotentInstruction, + createAssociatedTokenAccountInstruction, + getAccount, + getAssociatedTokenAddress, +} from "@solana/spl-token"; +import { BondingCurveAccount } from "./bondingCurveAccount"; +const {BN} = require('bn.js'); +import { + DEFAULT_COMMITMENT, + DEFAULT_FINALITY, + calculateWithSlippageBuy, + calculateWithSlippageSell, + sendTx, +} from "./util"; +import { PumpFun, IDL } from "./IDL"; +const PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; +const MPL_TOKEN_METADATA_PROGRAM_ID = + "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"; + +export const GLOBAL_ACCOUNT_SEED = "global"; +export const MINT_AUTHORITY_SEED = "mint-authority"; +export const BONDING_CURVE_SEED = "bonding-curve"; +export const METADATA_SEED = "metadata"; + +export const DEFAULT_DECIMALS = 6; + +export class PumpFunSDK { + public program: Program; + public connection: Connection; + constructor(provider?: Provider) { + this.program = new Program(IDL as PumpFun, provider); + this.connection = this.program.provider.connection; + } + + async createAndBuy( + creator: Keypair, + mint: Keypair, + createTokenMetadata: CreateTokenMetadata, + buyAmountSol: bigint, + slippageBasisPoints: bigint = 500n, + priorityFees?: PriorityFee, + commitment: Commitment = DEFAULT_COMMITMENT, + finality: Finality = DEFAULT_FINALITY + ): Promise { + let tokenMetadata = await this.createTokenMetadata(createTokenMetadata); + + let createTx = await this.getCreateInstructions( + creator.publicKey, + createTokenMetadata.name, + createTokenMetadata.symbol, + tokenMetadata.metadataUri, + mint + ); + + let newTx = new Transaction().add(createTx); + + if (buyAmountSol > 0) { + const globalAccount = await this.getGlobalAccount(commitment); + const buyAmount = globalAccount.getInitialBuyPrice(buyAmountSol); + const buyAmountWithSlippage = calculateWithSlippageBuy( + buyAmountSol, + slippageBasisPoints + ); + + const buyTx = await this.getBuyInstructions( + creator.publicKey, + mint.publicKey, + globalAccount.feeRecipient, + buyAmount, + buyAmountWithSlippage + ); + + newTx.add(buyTx); + } + + return newTx; + } + + async buy( + buyer: Keypair, + mint: PublicKey, + buyAmountSol: bigint, + slippageBasisPoints: bigint = 500n, + priorityFees?: PriorityFee, + commitment: Commitment = DEFAULT_COMMITMENT, + finality: Finality = DEFAULT_FINALITY + ): Promise { + let final_tx = new Transaction(); + let buyTx = await this.getBuyInstructionsBySolAmount( + buyer.publicKey, + mint, + buyAmountSol, + slippageBasisPoints, + commitment); + final_tx.add(buyTx); + return final_tx; + } + + async sell( + seller: Keypair, + mint: PublicKey, + sellTokenAmount: bigint, + slippageBasisPoints: bigint = 10000n, + priorityFees?: PriorityFee, + commitment: Commitment = DEFAULT_COMMITMENT, + finality: Finality = DEFAULT_FINALITY + ): Promise { + let final_tx = new Transaction(); + let sellTx = await this.getSellInstructionsByTokenAmount( + seller.publicKey, + mint, + sellTokenAmount, + slippageBasisPoints, + commitment + ); + final_tx.add(sellTx); + return final_tx; + } + async getBalance(account: PublicKey, mint: PublicKey) { + console.log("Fetching Ata..."); + const associatedTokenAddress = await getAssociatedTokenAddress( + mint, + account, + true + ); + let accountInfo:any = null + try { + accountInfo = await getAccount(this.connection, associatedTokenAddress, "confirmed"); + } catch (error) { + console.log("Token balance not found"); + return 0; + } + // + accountInfo = await getAccount(this.connection, associatedTokenAddress, "confirmed"); + return accountInfo.amount; + } + //create token instructions + async getCreateInstructions( + creator: PublicKey, + name: string, + symbol: string, + uri: string, + mint: Keypair + ) { + const mplTokenMetadata = new PublicKey(MPL_TOKEN_METADATA_PROGRAM_ID); + + const [metadataPDA] = PublicKey.findProgramAddressSync( + [ + Buffer.from(METADATA_SEED), + mplTokenMetadata.toBuffer(), + mint.publicKey.toBuffer(), + ], + mplTokenMetadata + ); + + const associatedBondingCurve = await getAssociatedTokenAddress( + mint.publicKey, + this.getBondingCurvePDA(mint.publicKey), + true + ); + + return this.program.methods + .create(name, symbol, uri) + .accounts({ + mint: mint.publicKey, + associatedBondingCurve: associatedBondingCurve, + metadata: metadataPDA, + user: creator, + }) + .signers([mint]) + .transaction(); + } + + async getBuyInstructionsBySolAmount( + buyer: PublicKey, + mint: PublicKey, + buyAmountSol: bigint, + slippageBasisPoints: bigint = 500n, + commitment: Commitment = DEFAULT_COMMITMENT + ) { + let bondingCurveAccount = await this.getBondingCurveAccount( + mint, + commitment + ); + if (!bondingCurveAccount) { + throw new Error(`Bonding curve account not found: ${mint.toBase58()}`); + } + + let buyAmount = bondingCurveAccount.getBuyPrice(buyAmountSol); + let buyAmountWithSlippage = calculateWithSlippageBuy( + buyAmountSol, + slippageBasisPoints + ); + + // let globalAccount = await this.getGlobalAccount(commitment); + const feeRecipient = new PublicKey("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM"); + return await this.getBuyInstructions( + buyer, + mint, + feeRecipient, + buyAmount, + buyAmountWithSlippage + ); + } + + //buy + async getBuyInstructions( + buyer: PublicKey, + mint: PublicKey, + feeRecipient: PublicKey, + amount: bigint, + solAmount: bigint, + commitment: Commitment = DEFAULT_COMMITMENT + ) { + const associatedBondingCurve = await getAssociatedTokenAddress( + mint, + this.getBondingCurvePDA(mint), + true + ); + + const associatedUser = await getAssociatedTokenAddress(mint, buyer, false); + let transaction = new Transaction(); + // try { + // await getAccount(this.connection, associatedUser, commitment); + // } catch (e) { + transaction.add( + createAssociatedTokenAccountIdempotentInstruction( + buyer, + associatedUser, + buyer, + mint + ) + ); + //} + transaction.add( + await this.program.methods + .buy(new BN(amount.toString()), new BN(solAmount.toString())) + .accounts({ + feeRecipient: feeRecipient, + mint: mint, + associatedBondingCurve: associatedBondingCurve, + associatedUser: associatedUser, + user: buyer, + }) + .transaction() + ); + + return transaction; + } + async delay(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + //sell + async getSellInstructionsByTokenAmount( + seller: PublicKey, + mint: PublicKey, + sellTokenAmount: bigint, + slippageBasisPoints: bigint = 500n, + commitment: Commitment = DEFAULT_COMMITMENT + ) { + + let bondingCurveAccount = await this.getBondingCurveAccount( + mint, + commitment + ); + if (!bondingCurveAccount) { + throw new Error(`Bonding curve account not found: ${mint.toBase58()}`); + } + + let globalAccount = await this.getGlobalAccount(commitment); + + let minSolOutput = bondingCurveAccount.getSellPrice( + sellTokenAmount, + globalAccount.feeBasisPoints + ); + let sellAmountWithSlippage = calculateWithSlippageSell( + minSolOutput, + slippageBasisPoints + ); + return await this.getSellInstructions( + seller, + mint, + globalAccount.feeRecipient, + sellTokenAmount, + sellAmountWithSlippage + ); + } + + async getSellInstructions( + seller: PublicKey, + mint: PublicKey, + feeRecipient: PublicKey, + amount: bigint, + minSolOutput: bigint + ) { + const associatedBondingCurve = await getAssociatedTokenAddress( + mint, + this.getBondingCurvePDA(mint), + true + ); + + const associatedUser = await getAssociatedTokenAddress(mint, seller, false); + + let transaction = new Transaction(); + + transaction.add( + await this.program.methods + .sell(new BN(amount.toString()), new BN(minSolOutput.toString())) + .accounts({ + feeRecipient: feeRecipient, + mint: mint, + associatedBondingCurve: associatedBondingCurve, + associatedUser: associatedUser, + user: seller, + }) + .transaction() + ); + + return transaction; + } + + async getBondingCurveAccount( + mint: PublicKey, + commitment: Commitment = DEFAULT_COMMITMENT + ) { + const tokenAccount = await this.connection.getAccountInfo( + this.getBondingCurvePDA(mint), + commitment + ); + if (!tokenAccount) { + return null; + } + return BondingCurveAccount.fromBuffer(tokenAccount!.data); + } + + async getGlobalAccount(commitment: Commitment = DEFAULT_COMMITMENT) { + const [globalAccountPDA] = PublicKey.findProgramAddressSync( + [Buffer.from(GLOBAL_ACCOUNT_SEED)], + new PublicKey(PROGRAM_ID) + ); + + const tokenAccount = await this.connection.getAccountInfo( + globalAccountPDA, + commitment + ); + + return GlobalAccount.fromBuffer(tokenAccount!.data); + } + + getBondingCurvePDA(mint: PublicKey) { + return PublicKey.findProgramAddressSync( + [Buffer.from(BONDING_CURVE_SEED), mint.toBuffer()], + this.program.programId + )[0]; + } + + async createTokenMetadata(create: CreateTokenMetadata) { + let formData = new FormData(); + formData.append("file", create.file), + formData.append("name", create.name), + formData.append("symbol", create.symbol), + formData.append("description", create.description), + formData.append("twitter", create.twitter || ""), + formData.append("telegram", create.telegram || ""), + formData.append("website", create.website || ""), + formData.append("showName", "true"); + let request = await fetch("https://pump.fun/api/ipfs", { + method: "POST", + body: formData, + }); + return request.json(); + } + + //EVENTS + addEventListener( + eventType: T, + callback: ( + event: PumpFunEventHandlers[T], + slot: number, + signature: string + ) => void + ) { + return this.program.addEventListener( + eventType, + (event: any, slot: number, signature: string) => { + let processedEvent; + switch (eventType) { + case "createEvent": + processedEvent = toCreateEvent(event as CreateEvent); + callback( + processedEvent as PumpFunEventHandlers[T], + slot, + signature + ); + break; + case "tradeEvent": + processedEvent = toTradeEvent(event as TradeEvent); + callback( + processedEvent as PumpFunEventHandlers[T], + slot, + signature + ); + break; + case "completeEvent": + processedEvent = toCompleteEvent(event as CompleteEvent); + callback( + processedEvent as PumpFunEventHandlers[T], + slot, + signature + ); + console.log("completeEvent", event, slot, signature); + break; + case "setParamsEvent": + processedEvent = toSetParamsEvent(event as SetParamsEvent); + callback( + processedEvent as PumpFunEventHandlers[T], + slot, + signature + ); + break; + default: + console.error("Unhandled event type:", eventType); + } + } + ); + } + + removeEventListener(eventId: number) { + this.program.removeEventListener(eventId); + } +} diff --git a/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/types.ts b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/types.ts new file mode 100644 index 0000000..e42c826 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/types.ts @@ -0,0 +1,80 @@ +import { PublicKey, VersionedTransactionResponse } from "@solana/web3.js"; + +export type CreateTokenMetadata = { + name: string; + symbol: string; + description: string; + file: Blob; + twitter?: string; + telegram?: string; + website?: string; +}; + +export type TokenMetadata = { + name: string; + symbol: string; + description: string; + image: string; + showName: boolean; + createdOn: string; + twitter: string; +}; + +export type CreateEvent = { + name: string; + symbol: string; + uri: string; + mint: PublicKey; + bondingCurve: PublicKey; + user: PublicKey; +}; + +export type TradeEvent = { + mint: PublicKey; + solAmount: bigint; + tokenAmount: bigint; + isBuy: boolean; + user: PublicKey; + timestamp: number; + virtualSolReserves: bigint; + virtualTokenReserves: bigint; + realSolReserves: bigint; + realTokenReserves: bigint; +}; + +export type CompleteEvent = { + user: PublicKey; + mint: PublicKey; + bondingCurve: PublicKey; + timestamp: number; +}; + +export type SetParamsEvent = { + feeRecipient: PublicKey; + initialVirtualTokenReserves: bigint; + initialVirtualSolReserves: bigint; + initialRealTokenReserves: bigint; + tokenTotalSupply: bigint; + feeBasisPoints: bigint; +}; + +export interface PumpFunEventHandlers { + createEvent: CreateEvent; + tradeEvent: TradeEvent; + completeEvent: CompleteEvent; + setParamsEvent: SetParamsEvent; +} + +export type PumpFunEventType = keyof PumpFunEventHandlers; + +export type PriorityFee = { + unitLimit: number; + unitPrice: number; +}; + +export type TransactionResult = { + signature?: string; + error?: unknown; + results?: VersionedTransactionResponse; + success: boolean; +}; diff --git a/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/util.ts b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/util.ts new file mode 100644 index 0000000..fd14da8 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/pumpdotfun-sdk/src/util.ts @@ -0,0 +1,131 @@ +import { + Commitment, + ComputeBudgetProgram, + Connection, + Finality, + Keypair, + PublicKey, + SendTransactionError, + Transaction, + TransactionMessage, + VersionedTransaction, + VersionedTransactionResponse, +} from "@solana/web3.js"; +import { PriorityFee, TransactionResult } from "./types"; + +export const DEFAULT_COMMITMENT: Commitment = "processed"; +export const DEFAULT_FINALITY: Finality = "confirmed"; + +export const calculateWithSlippageBuy = ( + amount: bigint, + basisPoints: bigint +) => { + return amount + (amount * basisPoints) / 10000n; +}; + +export const calculateWithSlippageSell = ( + amount: bigint, + basisPoints: bigint +) => { + return amount - (amount * basisPoints) / 10000n; +}; + +export async function sendTx( + connection: Connection, + tx: Transaction, + payer: PublicKey, + signers: Keypair[], + priorityFees?: PriorityFee, + commitment: Commitment = DEFAULT_COMMITMENT, + finality: Finality = DEFAULT_FINALITY +): Promise { + let newTx = new Transaction(); + + if (priorityFees) { + const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({ + units: priorityFees.unitLimit, + }); + + const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({ + microLamports: priorityFees.unitPrice, + }); + newTx.add(modifyComputeUnits); + newTx.add(addPriorityFee); + } + + newTx.add(tx); + + let versionedTx = await buildVersionedTx(connection, payer, newTx, commitment); + versionedTx.sign(signers); + + try { + const sig = await connection.sendTransaction(versionedTx, { + skipPreflight: false, + }); + console.log("sig:", `https://solscan.io/tx/${sig}`); + + let txResult = await getTxDetails(connection, sig, commitment, finality); + if (!txResult) { + return { + success: false, + error: "Transaction failed", + }; + } + return { + success: true, + signature: sig, + results: txResult, + }; + } catch (e) { + if (e instanceof SendTransactionError) { + let ste = e as SendTransactionError; + //console.log(await ste.getLogs(connection)); + } else { + console.error(e); + } + return { + error: e, + success: false, + }; + } +} + +export const buildVersionedTx = async ( + connection: Connection, + payer: PublicKey, + tx: Transaction, + commitment: Commitment = DEFAULT_COMMITMENT +): Promise => { + const blockHash = (await connection.getLatestBlockhash(commitment)) + .blockhash; + + let messageV0 = new TransactionMessage({ + payerKey: payer, + recentBlockhash: blockHash, + instructions: tx.instructions, + }).compileToV0Message(); + + return new VersionedTransaction(messageV0); +}; + +export const getTxDetails = async ( + connection: Connection, + sig: string, + commitment: Commitment = DEFAULT_COMMITMENT, + finality: Finality = DEFAULT_FINALITY +): Promise => { + const latestBlockHash = await connection.getLatestBlockhash(); + await connection.confirmTransaction( + { + blockhash: latestBlockHash.blockhash, + lastValidBlockHeight: latestBlockHash.lastValidBlockHeight, + signature: sig, + }, + commitment + ); + + return connection.getTransaction(sig, { + maxSupportedTransactionVersion: 0, + commitment: finality, + }); +}; diff --git a/src/Trading_dev/grpc-pf-sniper/src/streaming/grpc-requests-type.ts b/src/Trading_dev/grpc-pf-sniper/src/streaming/grpc-requests-type.ts new file mode 100644 index 0000000..bc8e52d --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/streaming/grpc-requests-type.ts @@ -0,0 +1,121 @@ +import { + CommitmentLevel, + SubscribeRequest, + } from "@triton-one/yellowstone-grpc"; +import { req } from "pino-std-serializers"; +export async function createSubscribeNewTokenRequest( + targetToken: string | undefined + ): Promise { + let request: any = null; + if (targetToken !== undefined) { + // if has target mint to snipe + request = { + slots: {}, + accounts: {}, + transactions: { + pumpdotfun: { + vote: false, + failed: false, + signature: undefined, + accountInclude: [ + "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM", + targetToken, + ], + accountExclude: [], + accountRequired: [targetToken], + }, + }, + transactionsStatus: {}, + blocks: {}, + blocksMeta: {}, + accountsDataSlice: [], + commitment: CommitmentLevel.PROCESSED, // Subscribe to processed blocks for the fastest updates + entry: {}, + }; + } else { + // if doesn't have target mint to snipe + request = { + slots: {}, + accounts: {}, + transactions: { + pumpdotfun: { + vote: false, + failed: false, + signature: undefined, + accountInclude: ["TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"], + accountExclude: [], + accountRequired: [], + }, + }, + transactionsStatus: {}, + blocks: {}, + blocksMeta: {}, + accountsDataSlice: [], + commitment: CommitmentLevel.PROCESSED, // Subscribe to processed blocks for the fastest updates + entry: {}, + }; + } + + return request; + } +export async function createSubscribeTokenRequest(mintAddress: string) { + let request: any = null; + request = { + slots: {}, + accounts: {}, + transactions: { + pumpdotfun: { + vote: false, + failed: false, + signature: undefined, + accountInclude: [mintAddress], + accountExclude: [], + accountRequired: [mintAddress], + }, + }, + transactionsStatus: {}, + blocks: {}, + blocksMeta: {}, + accountsDataSlice: [], + commitment: CommitmentLevel.PROCESSED, // Subscribe to processed blocks for the fastest updates + entry: {}, + }; + return request; +} +export async function createSubscribeTokenInSnipeCacheRequest(snipedTokenList: []){ + let request: any = null; + request = { + slots: {}, + accounts: {}, + transactions: { + pumpdotfun: { + vote: false, + failed: false, + signature: undefined, + accountInclude: ["TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM", ...snipedTokenList], + accountExclude: [], + accountRequired: [], + }, + }, + transactionsStatus: {}, + blocks: {}, + blocksMeta: {}, + accountsDataSlice: [], + commitment: CommitmentLevel.PROCESSED, // Subscribe to processed blocks for the fastest updates + entry: {}, + }; + return request; +} +export async function createClearAllSubscriptionsRequest() { + const request = { + "slots": {}, + "accounts": {}, + "transactions": {}, + "blocks": {}, + "blocksMeta": {}, + "accountsDataSlice": [] + }; + return request; +} + + diff --git a/src/Trading_dev/grpc-pf-sniper/src/streaming/pump.fun.ts b/src/Trading_dev/grpc-pf-sniper/src/streaming/pump.fun.ts new file mode 100644 index 0000000..56c2c2c --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/streaming/pump.fun.ts @@ -0,0 +1,130 @@ +import { + CommitmentLevel, + SubscribeRequest, +} from "@triton-one/yellowstone-grpc"; +import pino from "pino"; +import Client from "@triton-one/yellowstone-grpc"; +import { PublicKey } from "@solana/web3.js"; +import { buy, solanaConnection, sell } from "../transaction/transaction"; +import { storeJitoLeaderSchedule } from "../jito/bundle"; +import { AUTO_SELL, AUTO_SELL_TIMEOUT, GRPC_XTOKEN } from "../constants"; +import * as borsh from "@coral-xyz/borsh"; +import bs58 from "bs58"; +import { Buffer } from "buffer"; +import {createSubscribeNewTokenRequest, createClearAllSubscriptionsRequest, createSubscribeTokenRequest, createSubscribeTokenInSnipeCacheRequest} from "./grpc-requests-type" +import {handleSubscribe} from "./utils" + +const client:any = new Client( + "https://grpc.fra.shyft.to", + GRPC_XTOKEN, + { + "grpc.max_receive_message_length": 64 * 1024 * 1024, // 64MiB + } +); //grpc endpoint +const transport = pino.transport({ + target: "pino-pretty", +}); + +export const logger = pino( + { + level: "info", + serializers: { + error: pino.stdSerializers.err, + }, + base: undefined, + }, + transport +); +// Array to store Jito leaders for current epoch +let leaderSchedule = new Set(); +export async function populateJitoLeaderArray() { + leaderSchedule = await storeJitoLeaderSchedule(); +} + +(async () => { + const version = await client.getVersion(); // gets the version information + logger.info(version); +})(); + +/** + * Waits for a specified timeout and then sells all tokens associated with the given mint address. + * @param mintAddress - The address of the mint associated with the tokens to be sold. + * @param isJito - A boolean value indicating whether the tokens are Jito tokens. + */ +export async function waitAndSellAll(mintAddress: string, isJito: boolean) { + const strinToInt = parseInt(AUTO_SELL_TIMEOUT); + console.log("Selling", mintAddress); + try{ + await new Promise((resolve) => setTimeout(resolve, strinToInt*1000+1000)); // extra 1s to make sure the transaction is confirmed + sell(new PublicKey(mintAddress), isJito); + }catch(e){ + logger.error(`error when selling ${mintAddress}, ${e}`); + } +} + +/** + * Subscribes to a stream and listens for new tokens and snipe it. + * + * @param isAutoSell - Indicates whether to automatically sell tokens. + * @param sellAfterNumberBuys - The number of buys after which to sell tokens. + * @param isJito - Indicates whether to use Jito for buying and selling. + */ +export async function streamAnyNewTokens(isAutoSell: boolean, sellAfterNumberBuys: number, isJito: boolean, n: number) { + const stream = await client.subscribe(); + // Create `error` / `end` handler + + // let sellQueue: string[] = []; + let count = 0; + let currentPumpFunToken: string = ""; + const r1: SubscribeRequest = await createSubscribeNewTokenRequest(undefined); + handleSubscribe(stream, r1); + stream.on("data", (data:any) => { + if (data.transaction !== undefined) { + // sellQueue = []; // clear the queue after selling all + logger.info(`Current slot: ${data.transaction.slot}`); + currentPumpFunToken = data.transaction.transaction.meta.postTokenBalances[0].mint + logger.info(`New token created: ${currentPumpFunToken}`); + if(count < n){ + buy(new PublicKey(currentPumpFunToken), isJito); + logger.info(`Sniped ${1} times`); + if(isAutoSell) waitAndSellAll(currentPumpFunToken, isJito); + count += 1; + } + } + }); + +} + +/** + * Subscribes to a stream and listens for new token creation transactions. + * If the target token is created and meets the specified conditions, it performs a buy action. + * @param mintAddress The address of the target token. + * @param isAutoSell A boolean indicating whether to automatically sell after a certain number of buys. + * @param sellAfterNumberBuys The number of buys after which to automatically sell. + * @param isJito A boolean indicating whether to use Jito for the buy action. + */ +export async function streamTargetNewToken(mintAddress: string, isAutoSell: boolean, sellAfterNumberBuys: number, isJito: boolean) { + const stream = await client.subscribe(); + let count = 0; + // Create `error` / `end` handler + const r1 = await createSubscribeNewTokenRequest(mintAddress); + await handleSubscribe(stream, r1); + stream.on("data", (data:any) => { + if (data.transaction !== undefined) { + logger.info(`Current slot: ${data.transaction.slot}`); + logger.info( + `Target token create tx: https://solscan.io/tx/${bs58.encode(Buffer.from(data.transaction.transaction.signature))}` + ); + const pumpFunNewToken = data.transaction.transaction.meta.postTokenBalances[0].mint + logger.info(`Traget token created: ${pumpFunNewToken}`); + if (pumpFunNewToken === mintAddress && count === 0) { + buy(new PublicKey(pumpFunNewToken), isJito); + if(isAutoSell) waitAndSellAll(pumpFunNewToken, isJito); + logger.info(`Sniped ${count + 1} times`); + count += 1; + } + } + }); +} + + diff --git a/src/Trading_dev/grpc-pf-sniper/src/streaming/snipe-create.ts b/src/Trading_dev/grpc-pf-sniper/src/streaming/snipe-create.ts new file mode 100644 index 0000000..9b8e8de --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/streaming/snipe-create.ts @@ -0,0 +1,75 @@ +import {streamAnyNewTokens, streamTargetNewToken} from "./pump.fun" +import {AUTO_SELL_TIMEOUT} from "../constants" +import {init} from "../transaction/transaction" +import { logger } from "../utils/logger"; +const {program} = require("commander") +let targetTokenToSnipe:string = ""; +let isAutoSell = false; +let sellAfterNumberBuys = 1 +let isJito = false; +let n = 1; + +program.option("--token ", "Specify the token you want to snipe") + .option("-h, --help", "display help for command") + .option("--auto-sell", "Auto sell token after buying") + .option("--sell-after ", "Sell token after number of buys") + .option("--n ", "number of tokens to snipe") + .option("--jito", "Jito mode") + .action((options:any) => { + if (options.help) { + logger.info( + "ts-node snipe-create.ts --token --sell-after --n --auto-sell --jito" + ); + process.exit(0); + } + if(options.token){ + targetTokenToSnipe = options.token + } + if(options.autoSell){ + isAutoSell = true; + } + if(options.sellAfter){ + sellAfterNumberBuys = options.sellAfter; + } + if(options.jito){ + isJito = true; + } + if(options.n){ + n = options.n; + } + }); +program.parse(); + +async function snipe(){ + + // show the options + logger.info(`Auto sell mode enabled: ${isAutoSell}`) + logger.info(`Sell after: ${sellAfterNumberBuys} buys`) + logger.info(`Jito mode enabled: ${isJito}`) + logger.info(`Number of tokens to snipe: ${n}`) + if(isAutoSell){ + logger.info(`Auto sell after ${AUTO_SELL_TIMEOUT} seconds`) + } + // show the target token + if(targetTokenToSnipe === ""){ + logger.info("bot will snipe any new tokens") + } + else logger.info(`bot will snipe ${targetTokenToSnipe}`) + + // initialize the bot + await init(); + // stream the tokens and auto-sell when condition is met + try{ + if(targetTokenToSnipe === ""){ + await streamAnyNewTokens(isAutoSell, sellAfterNumberBuys, isJito, n); + }else{ + await streamTargetNewToken(targetTokenToSnipe, isAutoSell, sellAfterNumberBuys, isJito); + } + }catch(e){ + logger.error(`error when streaming ${e}`); + } + + +} + +snipe(); \ No newline at end of file diff --git a/src/Trading_dev/grpc-pf-sniper/src/streaming/utils.ts b/src/Trading_dev/grpc-pf-sniper/src/streaming/utils.ts new file mode 100644 index 0000000..3233728 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/streaming/utils.ts @@ -0,0 +1,65 @@ +import { + CommitmentLevel, + SubscribeRequest, + } from "@triton-one/yellowstone-grpc"; +import Client from "@triton-one/yellowstone-grpc"; +const PING_INTERVAL_MS = 30_000; + +export async function handleSubscribe(client_stream: any, args: SubscribeRequest){ + // Create `error` / `end` handler + const streamClosed = new Promise((resolve, reject) => { + client_stream.on("error", (error:any) => { + console.log("ERROR", error); + reject(error); + client_stream.end(); + }); + client_stream.on("end", () => { + resolve(); + }); + client_stream.on("close", () => { + resolve(); + }); + }); + + // Send subscribe request + await new Promise((resolve, reject) => { + client_stream.write(args, (err: any) => { + if (err === null || err === undefined) { + resolve(); + } else { + reject(err); + } + }); + }).catch((reason) => { + console.error(reason); + throw reason; + }); + // Send pings every 5s to keep the connection open + const pingRequest: SubscribeRequest = { + ping: { id: 1 }, + // Required, but unused arguments + accounts: {}, + accountsDataSlice: [], + transactions: {}, + blocks: {}, + blocksMeta: {}, + entry: {}, + slots: {}, + }; + setInterval(async () => { + await new Promise((resolve, reject) => { + client_stream.write(pingRequest, (err:any) => { + if (err === null || err === undefined) { + resolve(); + } else { + reject(err); + } + }); + }).catch((reason) => { + console.error(reason); + throw reason; + }); + }, PING_INTERVAL_MS); + + await streamClosed; +} \ No newline at end of file diff --git a/src/Trading_dev/grpc-pf-sniper/src/transaction/index.ts b/src/Trading_dev/grpc-pf-sniper/src/transaction/index.ts new file mode 100644 index 0000000..5c71111 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/transaction/index.ts @@ -0,0 +1 @@ +export * from "./transaction" \ No newline at end of file diff --git a/src/Trading_dev/grpc-pf-sniper/src/transaction/transaction.ts b/src/Trading_dev/grpc-pf-sniper/src/transaction/transaction.ts new file mode 100644 index 0000000..e6cfad6 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/transaction/transaction.ts @@ -0,0 +1,350 @@ +import { + Liquidity, + LiquidityPoolKeys, + LiquidityStateV4, + Token, + TokenAmount, +} from "@raydium-io/raydium-sdk"; +import { + Commitment, + ComputeBudgetProgram, + Connection, + Keypair, + LAMPORTS_PER_SOL, + PublicKey, + SystemProgram, + TransactionMessage, + VersionedTransaction, + Transaction, +} from "@solana/web3.js"; +import fs from "fs"; +import bs58 from "bs58"; +import { + COMMITMENT_LEVEL, + LOG_LEVEL, + PRIVATE_KEY, + QUOTE_AMOUNT, + RPC_ENDPOINT, + RPC_WEBSOCKET_ENDPOINT, + //PRIVATE_KEY_1, +} from "../constants"; +import { + AccountLayout, + createAssociatedTokenAccountIdempotentInstruction, + createCloseAccountInstruction, + getAssociatedTokenAddress, + getAssociatedTokenAddressSync, + TOKEN_PROGRAM_ID, +} from "@solana/spl-token"; +import { TokenInstructions } from "@project-serum/serum"; +import { logger } from "../utils/logger"; +import { + retrieveEnvVariable, + getKeypairByJsonPath, + printSOLBalance, + getSPLBalance, +} from "../utils"; +import { populateJitoLeaderArray } from "../streaming/pump.fun"; +import { sendBundle } from "../jito/bundle"; +import { PumpFunSDK } from "../pumpdotfun-sdk/src/pumpfun"; +import { AnchorProvider } from "@coral-xyz/anchor"; +import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; +import { printSPLBalance } from "../pumpdotfun-sdk/example/util"; +let wallet: Keypair; +let dev_wallet: Keypair; +let quoteAmount: TokenAmount; +quoteAmount = new TokenAmount(Token.WSOL, QUOTE_AMOUNT, false); +export const solanaConnection = new Connection(RPC_ENDPOINT, { + wsEndpoint: RPC_WEBSOCKET_ENDPOINT, +}); + +// Init funtions right here + +export async function init(): Promise { + logger.level = LOG_LEVEL; + + // get wallet + wallet = Keypair.fromSecretKey(bs58.decode(PRIVATE_KEY)); + //dev_wallet = Keypair.fromSecretKey(bs58.decode(PRIVATE_KEY_1)); + logger.info(`Wallet Address: ${wallet.publicKey}`); + //logger.info(`Dev Wallet Address: ${dev_wallet.publicKey}`); + + logger.info( + `Script will buy all new tokens on Pump.fun using SOL. Amount that will be used to buy each token is: ${quoteAmount.toFixed().toString()}` + ); + + // check existing wallet for associated token account of quote mint + const SOLBalance = await solanaConnection.getBalance(wallet.publicKey); + // const dev_SOLBalance = await solanaConnection.getBalance( + // dev_wallet.publicKey + // ); + if (SOLBalance === 0) { + throw new Error(`No SOL balance left in wallet: ${wallet.publicKey}`); + } + // if (dev_SOLBalance === 0) { + // throw new Error(`No SOL balance left in wallet: ${dev_wallet.publicKey}`); + // } + const quote_amt = Number(QUOTE_AMOUNT); + if (SOLBalance < quote_amt * LAMPORTS_PER_SOL) { + throw new Error(`Insufficient SOL balance in wallet: ${wallet.publicKey}`); + } + + await populateJitoLeaderArray(); +} + +// non-jito execution functions +async function simple_executeAndConfirm(transaction: VersionedTransaction) { + logger.info("Sent tx!"); + const signature = await simple_execute(transaction); + logger.info(`https://solscan.io/tx/${signature}`); +} + +async function simple_execute(transaction: VersionedTransaction) { + return solanaConnection.sendRawTransaction(transaction.serialize(), { + skipPreflight: true, + maxRetries: 0, + }); +} + +// trading functions right here + +export async function sell( + mintPublicKey: PublicKey, + isJito: Boolean +): Promise { + const Wallet = new NodeWallet(wallet); + const provider = new AnchorProvider(solanaConnection, Wallet, { + commitment: "finalized", + }); + const latestBlockhash = await solanaConnection.getLatestBlockhash({ + commitment: "confirmed", + }); + const sdk = new PumpFunSDK(provider); + console.log("Fetching balance of mint: ", mintPublicKey.toBase58()); + const currentBalanceOfMint = await sdk.getBalance( + wallet.publicKey, + mintPublicKey + ); + if (currentBalanceOfMint === 0) { + logger.info("No balance to sell"); + return; + } + console.log("Current balance of mint: ", currentBalanceOfMint); + + let ata = await getAssociatedTokenAddress(mintPublicKey, wallet.publicKey); + const sellInstruction: Transaction = await sdk.sell( + wallet, + mintPublicKey, + currentBalanceOfMint, + 10000n, + undefined, + "confirmed", + "finalized" + ); + console.log("sellInstruction: ", sellInstruction); + const messageV0 = new TransactionMessage({ + payerKey: wallet.publicKey, + recentBlockhash: latestBlockhash.blockhash, + instructions: [ + ...[ + ComputeBudgetProgram.setComputeUnitLimit({ + units: 71999, + }), + ComputeBudgetProgram.setComputeUnitPrice({ + microLamports: 0.0004 * LAMPORTS_PER_SOL, + }), + ], + ...sellInstruction.instructions, + ], + }).compileToV0Message(); + let commitment: Commitment = retrieveEnvVariable( + "COMMITMENT_LEVEL", + logger + ) as Commitment; + const transaction = new VersionedTransaction(messageV0); + transaction.sign([wallet]); + logger.info("sell tx sent!"); + if (isJito) { + sendBundle(latestBlockhash.blockhash, transaction, mintPublicKey, wallet); // with jito + await new Promise((r) => setTimeout(r, 1000)); + sendBundle( + latestBlockhash.blockhash, + transaction, + mintPublicKey, + dev_wallet + ); // with jito + } else simple_executeAndConfirm(transaction); // without jito +} + +export async function buy( + mintPublicKey: PublicKey, + isJito: Boolean +): Promise { + try { + const Wallet = new NodeWallet(wallet); + const provider = new AnchorProvider(solanaConnection, Wallet, { + commitment: "processed", + }); + const latestBlockhash = await solanaConnection.getLatestBlockhash({ + commitment: "processed", + }); + const sdk = new PumpFunSDK(provider); + let ata = await getAssociatedTokenAddressSync( + mintPublicKey, + wallet.publicKey + ); + // this is where the buy instruction of pump.fun new token will be added + logger.info(`Sniping token: ${mintPublicKey.toBase58()}`); + const buyInstruction: Transaction = await sdk.buy( + wallet, + mintPublicKey, + BigInt(Number(quoteAmount.toFixed()) * LAMPORTS_PER_SOL) + ); + + const messageV0 = new TransactionMessage({ + payerKey: wallet.publicKey, + recentBlockhash: latestBlockhash.blockhash, + instructions: [ + ...[ + ComputeBudgetProgram.setComputeUnitLimit({ + units: 71900, + }), + ], + createAssociatedTokenAccountIdempotentInstruction( + wallet.publicKey, + ata, + wallet.publicKey, + mintPublicKey + ), + ...buyInstruction.instructions, + ], + }).compileToV0Message(); + + let commitment: Commitment = retrieveEnvVariable( + "COMMITMENT_LEVEL", + logger + ) as Commitment; + + const transaction = new VersionedTransaction(messageV0); + + transaction.sign([wallet]); + + //await sleep(30000); + logger.info("buy tx sent!"); + /*const signature = await solanaConnection.sendRawTransaction(transaction.serialize(), { + preflightCommitment: commitment, + }); + */ + //logger.info(`Sending bundle transaction with mint - ${signature}`); + if (isJito) + sendBundle(latestBlockhash.blockhash, transaction, mintPublicKey, wallet); // with jito + else simple_executeAndConfirm(transaction); // without jito + } catch (error) { + logger.error(error); + } +} + +export async function createAndBuy( + pathToMintKeypair: string, + tokenMetadata: any, + initialBuySolAmount: number +) { + const Wallet = new NodeWallet(dev_wallet); + const provider = new AnchorProvider(solanaConnection, Wallet, { + commitment: "processed", + }); + + const sdk = new PumpFunSDK(provider); + const mintKeypair = await getKeypairByJsonPath(pathToMintKeypair); + console.log("Mint keypair: ", mintKeypair); + await printSOLBalance( + solanaConnection, + dev_wallet.publicKey, + "Dev wallet keypair" + ); + let bondingCurveAccount = await sdk.getBondingCurveAccount( + mintKeypair.publicKey + ); + if (!bondingCurveAccount) { + // the mint is not exist in pump.fun yet + const latestBlockhash = await solanaConnection.getLatestBlockhash({ + commitment: "processed", + }); + let createAndBuyInstruction: Transaction = await sdk.createAndBuy( + dev_wallet, + mintKeypair, + tokenMetadata, + BigInt(initialBuySolAmount * LAMPORTS_PER_SOL) + ); + const messageV0 = new TransactionMessage({ + payerKey: dev_wallet.publicKey, + recentBlockhash: latestBlockhash.blockhash, + instructions: [ + ...[ + ComputeBudgetProgram.setComputeUnitLimit({ + units: 250000, + }), + ComputeBudgetProgram.setComputeUnitPrice({ + microLamports: 0.004 * LAMPORTS_PER_SOL, + }), + ], + ...createAndBuyInstruction.instructions, + ], + }).compileToV0Message(); + + let commitment: Commitment = retrieveEnvVariable( + "COMMITMENT_LEVEL", + logger + ) as Commitment; + + const transaction = new VersionedTransaction(messageV0); + + transaction.sign([dev_wallet, mintKeypair]); + + //await sleep(30000); + logger.info("create and buy tx sent!"); + /*const signature = await solanaConnection.sendRawTransaction(transaction.serialize(), { + preflightCommitment: commitment, + }); + */ + //logger.info(`Sending bundle transaction with mint - ${signature}`); + // await simple_executeAndConfirm(transaction); + await sendBundle( + latestBlockhash.blockhash, + transaction, + mintKeypair.publicKey, + dev_wallet + ); // with jito + // wait for 2 seconds for the transaction to be processed + await new Promise((r) => setTimeout(r, 1000)); + bondingCurveAccount = await sdk.getBondingCurveAccount( + mintKeypair.publicKey + ); + logger.info("Bonding curve after create and buy", bondingCurveAccount); + printSPLBalance( + solanaConnection, + mintKeypair.publicKey, + dev_wallet.publicKey + ); + } +} + +async function main() { + const pathToMintKeypair = + "/Users/chiwangso/Desktop/beta-memecoin-cli/src/Trading/Sniper_dev/grpc-pump.fun-bot/test-token-keypairs/soC5qgyb82XUQiEPEYsHspNtiKYcYsQiKeNSoiihyG9.json"; + let tokenMetadata = { + name: "Juice Wrld", + symbol: "JW", + description: "YES, how?", + telegram: "", + twitter: "", + website: "", + file: await fs.openAsBlob( + "/Users/chiwangso/Desktop/beta-memecoin-cli/src/Trading/pumpfun-bundler-cli/pumpfunsdk-js/pumpdotfun-sdk/images/999.jpg" // change your own path + ), + }; + let initialBuySolAmount = 0.02; + await init(); + await createAndBuy(pathToMintKeypair, tokenMetadata, initialBuySolAmount); +} +// main() diff --git a/src/Trading_dev/grpc-pf-sniper/src/utils/index.ts b/src/Trading_dev/grpc-pf-sniper/src/utils/index.ts new file mode 100644 index 0000000..d90cdf8 --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/utils/index.ts @@ -0,0 +1,2 @@ +export * from './utils'; +export * from './logger'; \ No newline at end of file diff --git a/src/Trading_dev/grpc-pf-sniper/src/utils/logger.ts b/src/Trading_dev/grpc-pf-sniper/src/utils/logger.ts new file mode 100644 index 0000000..393068e --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/utils/logger.ts @@ -0,0 +1,17 @@ +import pino from "pino"; + +const transport = pino.transport({ + target: 'pino-pretty', +}); + +export const logger = pino( + { + level: 'info', + redact: ['poolKeys'], + serializers: { + error: pino.stdSerializers.err, + }, + base: undefined, + }, + transport, +); diff --git a/src/Trading_dev/grpc-pf-sniper/src/utils/utils.ts b/src/Trading_dev/grpc-pf-sniper/src/utils/utils.ts new file mode 100644 index 0000000..0d22abd --- /dev/null +++ b/src/Trading_dev/grpc-pf-sniper/src/utils/utils.ts @@ -0,0 +1,70 @@ +import { Logger } from 'pino'; +import dotenv from 'dotenv'; +import fs from "fs"; +import { Keypair, LAMPORTS_PER_SOL } from '@solana/web3.js'; +import { Connection } from '@solana/web3.js'; +import { PublicKey } from '@solana/web3.js'; +import { getAssociatedTokenAddressSync } from '@solana/spl-token'; +dotenv.config(); + +export const retrieveEnvVariable = (variableName: string, logger: Logger) => { + const variable = process.env[variableName] || ''; + if (!variable) { + logger.error(`${variableName} is not set`); + process.exit(1); + } + return variable; +}; + +export function getKeypairByJsonPath(jsonPath: string): any { + try { + const keypairJson = fs.readFileSync(jsonPath, "utf-8"); + const data = JSON.parse(keypairJson); + const mintKeypair = Keypair.fromSecretKey(Uint8Array.from(data)); + return mintKeypair + } catch (e) { + console.log(e); + } +} +export async function printSOLBalance ( + connection: Connection, + pubKey: PublicKey, + info = "" +) { + const balance = await connection.getBalance(pubKey); + console.log( + `${info ? info + " " : ""}${pubKey.toBase58()}:`, + balance / LAMPORTS_PER_SOL, + `SOL` + ); +}; + +export async function getSPLBalance ( + connection: Connection, + mintAddress: PublicKey, + pubKey: PublicKey, + allowOffCurve = false +) { + try { + let ata = getAssociatedTokenAddressSync(mintAddress, pubKey, allowOffCurve); + const balance = await connection.getTokenAccountBalance(ata, "processed"); + return balance.value.uiAmount; + } catch (e) {} + return null; +}; +async function printSPLBalance ( + connection: Connection, + mintAddress: PublicKey, + user: PublicKey, + info = "" +) { + const balance = await getSPLBalance(connection, mintAddress, user); + if (balance === null) { + console.log( + `${info ? info + " " : ""}${user.toBase58()}:`, + "No Account Found" + ); + } else { + console.log(`${info ? info + " " : ""}${user.toBase58()}:`, balance); + } +}; \ No newline at end of file diff --git a/src/Trading_dev/memecoin_trading_strategies/copy_trading/copy-sell.js b/src/Trading_dev/memecoin_trading_strategies/copy_trading/copy-sell.js deleted file mode 100644 index 0ade9fd..0000000 --- a/src/Trading_dev/memecoin_trading_strategies/copy_trading/copy-sell.js +++ /dev/null @@ -1,111 +0,0 @@ -const { - PublicKey, -} = require("@solana/web3.js"); -const { - TOKEN_PROGRAM_ID, - AccountLayout, -} = require("@solana/spl-token"); -const fs = require('fs'); -const path = require('path'); -const { wallet, connection, smart_money_wallet } = require("../../../helpers/config"); -//const { buy } = require("../../dex/jupiter/swap/buy-helper"); -//const { sell } = require("../../dex/jupiter/swap/sell-helper"); -const {sell} = require("../../../raydium/sell_helper") - -//const {swap} = require("../../../Pool/swap") -var current_trader_wallet_state = {}; -var current_our_wallet_state = {}; -// [usdc, sol, usdt, wsol] -const wsol = "So11111111111111111111111111111111111111112" -const quoteToken = [ - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "SOL", - "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", - wsol, -]; -const boughtTokensPath = path.join(__dirname, 'bought-tokens.json'); -let boughtTokens = JSON.parse(fs.readFileSync(boughtTokensPath, 'utf8')); -function saveToJson() { - fs.writeFileSync(boughtTokensPath, JSON.stringify(boughtTokens, null, 2)); -} -/** -* Retrieves the state of a wallet by querying the Solana blockchain. -* @param {string} wallet_address - The address of the wallet to retrieve the state for. -* @returns {Object} - An object containing the token balances of the wallet and the SOL balance. -*/ -async function retriveWalletState(wallet_address) { - const filters = [ - { - dataSize: 165, //size of account (bytes) - }, - { - memcmp: { - offset: 32, //location of our query in the account (bytes) - bytes: wallet_address, //our search criteria, a base58 encoded string - }, - }, - ]; - const accounts = await connection.getParsedProgramAccounts( - TOKEN_PROGRAM_ID, //new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") - { filters: filters } - ); - let results = {}; - const solBalance = await connection.getBalance(new PublicKey(wallet_address)); - accounts.forEach((account, i) => { - //Parse the account data - const parsedAccountInfo = account.account.data; - const mintAddress = parsedAccountInfo["parsed"]["info"]["mint"]; - const tokenBalance = - parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"]; - - results[mintAddress] = tokenBalance; - results["SOL"] = solBalance / 10 ** 9; - }); - return results; -} -async function copy_sell(address){ - // 400 ms to check the wallet state - // if token we have but trader doesn't have, sell it - // that's it - let soldTokens = []; - let flag = false; - let possible_cant_sell_token = null - try{ - if(boughtTokens.length > 0){ - for(let i=0; i !soldTokens.includes(token)); - // Save the updated list back to the JSON file - saveToJson(); - - } - -} -async function main(){ -while(true){ - boughtTokens = JSON.parse(fs.readFileSync(boughtTokensPath, 'utf8')); - await copy_sell(smart_money_wallet); - - await new Promise((resolve) => setTimeout(resolve, 2500)); -} -} -main(); -module.exports = {copy_sell} \ No newline at end of file diff --git a/src/Trading_dev/dex/meteora/buy.js b/src/Transactions/README.md similarity index 100% rename from src/Trading_dev/dex/meteora/buy.js rename to src/Transactions/README.md diff --git a/src/Transactions/bloXroute_tips_tx_executor.js b/src/Transactions/bloXroute_tips_tx_executor.ts similarity index 75% rename from src/Transactions/bloXroute_tips_tx_executor.js rename to src/Transactions/bloXroute_tips_tx_executor.ts index f8df2e5..5b5a21e 100644 --- a/src/Transactions/bloXroute_tips_tx_executor.js +++ b/src/Transactions/bloXroute_tips_tx_executor.ts @@ -1,28 +1,28 @@ -const { +import { createTraderAPIMemoInstruction, HttpProvider, MAINNET_API_UK_HTTP, MAINNET_API_NY_HTTP, -} = require("@bloxroute/solana-trader-client-ts"); -const { private_key, bloXRoute_auth_header, bloXroute_fee } = require("../helpers/config"); -const { +} from "@bloxroute/solana-trader-client-ts"; +import { private_key, bloXRoute_auth_header, bloXroute_fee } from "../helpers/config"; +import { Connection, LAMPORTS_PER_SOL, PublicKey, Keypair, SystemProgram, -} = require("@solana/web3.js"); -const base58 = require("bs58"); -const { Transaction } = require("@solana/web3.js"); +} from "@solana/web3.js"; +import base58 from "bs58"; +import { Transaction } from "@solana/web3.js"; const TRADER_API_TIP_WALLET = "HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY"; const provider = new HttpProvider( - bloXRoute_auth_header, + bloXRoute_auth_header||"", private_key, MAINNET_API_UK_HTTP // or MAINNET_API_NY_HTTP ); -async function CreateTraderAPITipTransaction( - senderAddress, - tipAmountInLamports +export async function CreateTraderAPITipTransaction( + senderAddress:any, + tipAmountInLamports:any ) { const tipAddress = new PublicKey(TRADER_API_TIP_WALLET); return new Transaction().add( @@ -33,35 +33,37 @@ async function CreateTraderAPITipTransaction( }) ); } -async function bloXroute_executeAndConfirm(transaction, signers) { +export async function bloXroute_executeAndConfirm(transaction:any, signers:any) { const memo = createTraderAPIMemoInstruction( "Powered by bloXroute Trader Api" ); // why not use empty string? see https://docs.bloxroute.com/solana/trader-api-v2/achieve-best-performance-for-landing-a-transaction - const wallet = Keypair.fromSecretKey(base58.decode(private_key)); + const wallet = Keypair.fromSecretKey(base58.decode(private_key||"")); const recentBlockhash = await provider.getRecentBlockHash({}); let tx = new Transaction({ recentBlockhash: recentBlockhash.blockHash, feePayer: wallet.publicKey, }); + const fee:number = parseFloat(bloXroute_fee||"0.001"); tx.add(transaction); tx.add(memo); tx.add( await CreateTraderAPITipTransaction( wallet.publicKey, - bloXroute_fee * LAMPORTS_PER_SOL + (fee) * LAMPORTS_PER_SOL ) ); // why 0.001 SOL? tx.sign(wallet); const serializeTxBytes = tx.serialize(); const buffTx = Buffer.from(serializeTxBytes); - const encodedTx = buffTx.toString("base64"); + const encodedTx:any = buffTx.toString("base64"); console.log("Submitting transaction to bloXroute..."); - const response = await provider.postSubmit({ + const request:any= { transaction: { content: encodedTx, isCleanup: false }, frontRunningProtection: false, useStakedRPCs: true, // comment this line if you don't want to directly send txn to current blockleader - }); + } + const response = await provider.postSubmit(request); /** * For better performance, * you could include a high enough tip and set useStakedRPCs to True diff --git a/src/Transactions/index.ts b/src/Transactions/index.ts new file mode 100644 index 0000000..6fc74d9 --- /dev/null +++ b/src/Transactions/index.ts @@ -0,0 +1,3 @@ +export * from "./bloXroute_tips_tx_executor"; +export * from "./jito_tips_tx_executor"; +export * from "./simple_tx_executor"; \ No newline at end of file diff --git a/src/Transactions/jito_tips_tx_executor.js b/src/Transactions/jito_tips_tx_executor.ts similarity index 88% rename from src/Transactions/jito_tips_tx_executor.js rename to src/Transactions/jito_tips_tx_executor.ts index 6347fc6..ec51fe9 100644 --- a/src/Transactions/jito_tips_tx_executor.js +++ b/src/Transactions/jito_tips_tx_executor.ts @@ -1,4 +1,4 @@ -const { +import { BlockhashWithExpiryBlockHeight, Keypair, PublicKey, @@ -6,11 +6,11 @@ const { Connection, TransactionMessage, VersionedTransaction, -} = require("@solana/web3.js"); -const axios = require("axios"); -const bs58 = require("bs58"); -const { Currency, CurrencyAmount } = require("@raydium-io/raydium-sdk"); -const { connection } = require("../helpers/config"); +} from "@solana/web3.js"; +import axios from "axios"; +import bs58 from "bs58"; +import { Currency, CurrencyAmount } from "@raydium-io/raydium-sdk"; +import { connection } from "../helpers/config"; const jito_Validators = [ "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh", "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt", @@ -21,7 +21,8 @@ const jito_Validators = [ "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL", "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5", ]; -const endpoints = [ // TODO: Choose a jito endpoint which is closest to your location, and uncomment others +const endpoints = [ + // TODO: Choose a jito endpoint which is closest to your location, and uncomment others "https://mainnet.block-engine.jito.wtf/api/v1/bundles", "https://amsterdam.mainnet.block-engine.jito.wtf/api/v1/bundles", "https://frankfurt.mainnet.block-engine.jito.wtf/api/v1/bundles", @@ -33,7 +34,7 @@ const endpoints = [ // TODO: Choose a jito endpoint which is closest to your loc * Generates a random validator from the list of jito_Validators. * @returns {PublicKey} A new PublicKey representing the random validator. */ -async function getRandomValidator() { +export async function getRandomValidator() { const res = jito_Validators[Math.floor(Math.random() * jito_Validators.length)]; return new PublicKey(res); @@ -46,11 +47,11 @@ async function getRandomValidator() { * @param {number} jitofee - The fee for the Jito transaction. * @returns {Promise<{ confirmed: boolean, signature: string | null }>} - A promise that resolves to an object containing the confirmation status and the transaction signature. */ -async function jito_executeAndConfirm( - transaction, - payer, - lastestBlockhash, - jitofee +export async function jito_executeAndConfirm( + transaction: any, + payer: Keypair, + lastestBlockhash: any, + jitofee: any ) { console.log("Executing transaction (jito)..."); const jito_validator_wallet = await getRandomValidator(); @@ -114,7 +115,7 @@ async function jito_executeAndConfirm( * @param {object} latestBlockhash - The latest blockhash information. * @returns {object} - An object containing the confirmation status and the transaction signature. */ -async function jito_confirm(signature, latestBlockhash) { +export async function jito_confirm(signature: any, latestBlockhash: any) { console.log("Confirming the jito transaction..."); const confirmation = await connection.confirmTransaction( { @@ -127,4 +128,3 @@ async function jito_confirm(signature, latestBlockhash) { return { confirmed: !confirmation.value.err, signature }; } -module.exports = { jito_executeAndConfirm }; diff --git a/src/Transactions/simple_tx_executor.js b/src/Transactions/simple_tx_executor.ts similarity index 77% rename from src/Transactions/simple_tx_executor.js rename to src/Transactions/simple_tx_executor.ts index 5300f7c..bf46fde 100644 --- a/src/Transactions/simple_tx_executor.js +++ b/src/Transactions/simple_tx_executor.ts @@ -1,11 +1,11 @@ -const { +import { BlockhashWithExpiryBlockHeight, Connection, Keypair, Transaction, VersionedTransaction, -} = require("@solana/web3.js"); -const { connection } = require("../helpers/config.js"); +} from "@solana/web3.js"; +import { connection } from "../helpers/config"; /** * Executes a transaction and confirms it on the Solana blockchain. @@ -14,21 +14,21 @@ const { connection } = require("../helpers/config.js"); * @param {string} lastestBlockhash - The latest blockhash of the Solana blockchain. * @returns {Promise} - A promise that resolves to true if the transaction is confirmed, false otherwise. */ -async function simple_executeAndConfirm(transaction, payer, lastestBlockhash) { +export async function simple_executeAndConfirm(transaction:any, payer:any, lastestBlockhash:any) { console.log("Executing transaction..."); const signature = await simple_execute(transaction); console.log("Transaction executed. Confirming transaction..."); return simple_confirm(signature, lastestBlockhash); } -async function simple_execute(transaction) { +async function simple_execute(transaction:any) { return connection.sendRawTransaction(transaction.serialize(), { skipPreflight: true, maxRetries: 0, }); } -async function simple_confirm(signature, latestBlockhash) { +async function simple_confirm(signature:any, latestBlockhash:any) { const confirmation = await connection.confirmTransaction( { signature, @@ -40,4 +40,3 @@ async function simple_confirm(signature, latestBlockhash) { return { confirmed: !confirmation.value.err, signature }; } -module.exports = { simple_executeAndConfirm }; diff --git a/src/helpers/.env.copy b/src/helpers/.env.copy index 5e3ccf1..f00fc2b 100644 --- a/src/helpers/.env.copy +++ b/src/helpers/.env.copy @@ -14,4 +14,22 @@ BLOXROUTE_FEE = 0.001 TAKE_PROFIT = 0.1 # sell when price up 10% STOP_LOST = 0.2 # sell when price down 20% SMART_MONEY_WALLET = "YOUR_SMART_MONEY_WALLET" -BLOXROUTE_AUTH_HEADER = "BLOXROUTE_AUTH_HEADER" # to get, go to https://docs.bloxroute.com/apis/authorization-headers \ No newline at end of file +BLOXROUTE_AUTH_HEADER = "BLOXROUTE_AUTH_HEADER" # to get, go to https://docs.bloxroute.com/apis/authorization-headers + + +# for grpc development +COMMITMENT_LEVEL=confirmed +GRPC_XTOKEN=YOUR_GRPC_XTOKEN # the shyft one is great +LOG_LEVEL=info +BLOCK_ENGINE_URL=tokyo.mainnet.block-engine.jito.wtf +# choose one of this endpoint closest to you +# amsterdam.mainnet.block-engine.jito.wtf +# frankfurt.mainnet.block-engine.jito.wtf +# slc.mainnet.block-engine.jito.wtf +# tokyo.mainnet.block-engine.jito.wtf +# ny.mainnet.block-engine.jito.wtf + + # for grpc pump.fun sniper bot +QUOTE_AMOUNT=0.05 # in SOL +AUTO_SELL=true # true or false +AUTO_SELL_TIMEOUT=5 # in seconds diff --git a/src/Trading_dev/dex/meteora/index.js b/src/helpers/README.md similarity index 100% rename from src/Trading_dev/dex/meteora/index.js rename to src/helpers/README.md diff --git a/src/helpers/check_balance.js b/src/helpers/check_balance.ts similarity index 80% rename from src/helpers/check_balance.js rename to src/helpers/check_balance.ts index 2368c6d..e54d8e9 100644 --- a/src/helpers/check_balance.js +++ b/src/helpers/check_balance.ts @@ -1,19 +1,18 @@ -const { Connection, LAMPORTS_PER_SOL, PublicKey } = require("@solana/web3.js"); -const { +import { Connection, LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js"; +import { getDomainKeySync, NameRegistryState, -} = require("@bonfida/spl-name-service"); -const { main_endpoint, dev_endpoint } = require("./config"); -const connectionDev = new Connection(dev_endpoint, "confirmed"); +} from "@bonfida/spl-name-service"; +import { main_endpoint } from "./config"; const connectionMain = new Connection(main_endpoint); -const { getAssociatedTokenAddressSync } = require("@solana/spl-token"); +import { getAssociatedTokenAddressSync } from "@solana/spl-token"; /** * Retrieves the public key associated with a given .sol domain. * @param {string} domain - The .sol domain to retrieve the public key for. * @returns {Promise} The public key associated with the domain. */ -async function getPublicKeyFromSOLDomain(domain) { +export async function getPublicKeyFromSOLDomain(domain:string) { // check if the domain is a .sol domain // the last four characters should be ".sol" if (!domain.endsWith(".sol")) { @@ -35,7 +34,7 @@ async function getPublicKeyFromSOLDomain(domain) { * @param {object} connection - The connection object for interacting with the Solana network. * @returns {Promise} - A promise that resolves when the balance is checked. */ -async function checkBalanceByAddress(address, connection) { +export async function checkBalanceByAddress(address:string, connection:Connection) { // check if the address is valid // check the domain name of the address @@ -62,7 +61,7 @@ async function checkBalanceByAddress(address, connection) { * @returns {Promise} The balance of the SPL token. * @throws {Error} If no balance is found. */ -async function getSPLTokenBalance(connection, tokenAccount, payerPubKey) { +export async function getSPLTokenBalance(connection:Connection, tokenAccount:PublicKey, payerPubKey:PublicKey) { const address = getAssociatedTokenAddressSync(tokenAccount, payerPubKey); const info = await connection.getTokenAccountBalance(address); if (info.value.uiAmount == null) throw new Error("No balance found"); @@ -74,10 +73,10 @@ async function getSPLTokenBalance(connection, tokenAccount, payerPubKey) { * @param {object} connection - The connection object for interacting with the Solana network. * @returns {Promise} - A promise that resolves once the balance is checked. */ -async function checkBalanceByDomain(domain, connection) { +export async function checkBalanceByDomain(domain:string, connection:Connection) { // get the public key from the domain - const owner = await getPublicKeyFromSOLDomain(domain); + const owner:any = await getPublicKeyFromSOLDomain(domain); const balanceInLamports = await connection.getBalance(new PublicKey(owner)); const balanceInSOL = balanceInLamports / LAMPORTS_PER_SOL; @@ -85,4 +84,3 @@ async function checkBalanceByDomain(domain, connection) { `💰 Finished! The balance for the wallet at domain ${domain} is ${balanceInSOL}!` ); } -module.exports = { checkBalanceByAddress, getSPLTokenBalance }; diff --git a/src/helpers/config.js b/src/helpers/config.js deleted file mode 100644 index 9c8f933..0000000 --- a/src/helpers/config.js +++ /dev/null @@ -1,97 +0,0 @@ -const { - Currency, - Token, - ENDPOINT, - MAINNET_PROGRAM_ID, - RAYDIUM_MAINNET, - TxVersion, - LOOKUP_TABLE_CACHE, - TOKEN_PROGRAM_ID, -} = require("@raydium-io/raydium-sdk"); -const { Connection, Keypair, PublicKey } = require("@solana/web3.js"); -const fs = require("fs"); -const dotenv = require("dotenv"); -const bs58 = require("bs58"); -const path = require("path"); -// default path: /Users/{your_user_name}/Desktop/Solana-Memecoin-CLI/src/helpers/.env -// please specify your own .env path -const envPath = path.join(__dirname, ".env"); -dotenv.config({ - path: envPath, // fill in your .env path -}); -function loadKeypairFromFile(filename) { - const secret = fs.readFileSync(filename, { encoding: "utf8" }); - return Keypair.fromSecretKey(Uint8Array.from(JSON.parse(secret))); -} -const jito_fee = process.env.JITO_FEE; // 0.00009 SOL -const shyft_api_key = process.env.SHYFT_API_KEY; // your shyft api key -const wallet = Keypair.fromSecretKey(bs58.decode(process.env.PRIVATE_KEY)); // your wallet -const private_key = process.env.PRIVATE_KEY; // your private key -const dev_endpoint = process.env.DEVNET_ENDPOINT; // devnet endpoint, if you use devnet -const main_endpoint = process.env.MAINNET_ENDPOINT; // mainnet endpoint -const bloXRoute_auth_header = process.env.BLOXROUTE_AUTH_HEADER; -const bloXroute_fee = process.env.BLOXROUTE_FEE; // 0.001 SOL -// const second_main_endpoint = process.env.SECOND_MAINNET_ENDPOINT; // if you use copy trade program, second mainnet endpoint -// const RPC_Websocket_endpoint = process.env.WS_ENDPOINT; -// const second_RPC_Websocket_endpoint = process.env.SECOND_WS_ENDPOINT; // if you use copy trade program -// const stop_lost = process.env.STOP_LOST; // percentage of stop lost, if you use copy trade program -// const take_profit = process.env.TAKE_PROFIT; // percentage of take profit, if you use copy trade program -const smart_money_wallet = process.env.SMART_MONEY_WALLET; // if you use copy trade program -const connection = new Connection(main_endpoint, "confirmed"); // mainnet connection -//const connection = new Connection(main_endpoint, { // if you use copy trade program -// wsEndpoint: RPC_Websocket_endpoint, -// commitment: "confirmed", -//}); -//const second_connection = new Connection(second_main_endpoint, { // if you use copy trade program -// wsEndpoint: second_RPC_Websocket_endpoint, -// commitment: "confirmed", -//}); -const dev_connection = new Connection(dev_endpoint, "confirmed"); // devnet connection - -const PROGRAMIDS = MAINNET_PROGRAM_ID; // raydium mainnet program address - -const RAYDIUM_MAINNET_API = RAYDIUM_MAINNET; // raydium mainnet program's api - -const makeTxVersion = TxVersion.V0; // LEGACY -const _ENDPOINT = ENDPOINT; // raydium mainnet program's base api path -const addLookupTableInfo = LOOKUP_TABLE_CACHE; // only mainnet. other = undefined - -const DEFAULT_TOKEN = { - SOL: new Currency(9, "SOL", "SOL"), - WSOL: new Token( - TOKEN_PROGRAM_ID, - new PublicKey("So11111111111111111111111111111111111111112"), - 9, - "WSOL", - "WSOL" - ), - USDC: new Token( - TOKEN_PROGRAM_ID, - new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), - 6, - "USDC", - "USDC" - ), -}; - -module.exports = { - wallet, - dev_connection, - dev_endpoint, - main_endpoint, - connection, - TOKEN_PROGRAM_ID, - RAYDIUM_MAINNET, - RAYDIUM_MAINNET_API, - PROGRAMIDS, - makeTxVersion, - DEFAULT_TOKEN, - addLookupTableInfo, - _ENDPOINT, - shyft_api_key, - jito_fee, - smart_money_wallet, - bloXRoute_auth_header, - private_key, - bloXroute_fee, -}; diff --git a/src/helpers/config.ts b/src/helpers/config.ts new file mode 100644 index 0000000..e28f93f --- /dev/null +++ b/src/helpers/config.ts @@ -0,0 +1,77 @@ +import { + Currency, + Token, + ENDPOINT, + MAINNET_PROGRAM_ID, + RAYDIUM_MAINNET, + TxVersion, + LOOKUP_TABLE_CACHE, + TOKEN_PROGRAM_ID, +} from "@raydium-io/raydium-sdk"; +import { Connection, Keypair, PublicKey } from "@solana/web3.js"; +import fs from "fs"; +import dotenv from "dotenv"; +import bs58 from "bs58"; +import path from "path"; +// default path: /Users/{your_user_name}/Desktop/solana-trading-cli/src/helpers/.env +// please specify your own .env path +const envPath = path.join(__dirname, ".env"); +dotenv.config({ + path: envPath, // fill in your .env path +}); +export function loadKeypairFromFile(filename: string) { + const secret = fs.readFileSync(filename, { encoding: "utf8" }); + return Keypair.fromSecretKey(Uint8Array.from(JSON.parse(secret))); +} +export const jito_fee = process.env.JITO_FEE; // 0.00009 SOL +export const shyft_api_key = process.env.SHYFT_API_KEY; // your shyft api key +export const wallet = Keypair.fromSecretKey( + bs58.decode(process.env.PRIVATE_KEY || "") +); // your wallet +export const private_key = process.env.PRIVATE_KEY; // your private key +export const dev_endpoint = process.env.DEVNET_ENDPOINT || ""; // devnet endpoint, if you use devnet +export const main_endpoint = process.env.MAINNET_ENDPOINT || ""; // mainnet endpoint +export const bloXRoute_auth_header = process.env.BLOXROUTE_AUTH_HEADER; +export const bloXroute_fee = process.env.BLOXROUTE_FEE; // 0.001 SOL +// const second_main_endpoint = process.env.SECOND_MAINNET_ENDPOINT; // if you use copy trade program, second mainnet endpoint +// const RPC_Websocket_endpoint = process.env.WS_ENDPOINT; +// const second_RPC_Websocket_endpoint = process.env.SECOND_WS_ENDPOINT; // if you use copy trade program +// const stop_lost = process.env.STOP_LOST; // percentage of stop lost, if you use copy trade program +// const take_profit = process.env.TAKE_PROFIT; // percentage of take profit, if you use copy trade program +export const smart_money_wallet = process.env.SMART_MONEY_WALLET; // if you use copy trade program +export const connection = new Connection(main_endpoint, "confirmed"); // mainnet connection +//const connection = new Connection(main_endpoint, { // if you use copy trade program +// wsEndpoint: RPC_Websocket_endpoint, +// commitment: "confirmed", +//}); +//const second_connection = new Connection(second_main_endpoint, { // if you use copy trade program +// wsEndpoint: second_RPC_Websocket_endpoint, +// commitment: "confirmed", +//}); +export const dev_connection = new Connection(dev_endpoint, "confirmed"); // devnet connection + +export const PROGRAMIDS = MAINNET_PROGRAM_ID; // raydium mainnet program address + +export const RAYDIUM_MAINNET_API = RAYDIUM_MAINNET; // raydium mainnet program's api + +export const makeTxVersion = TxVersion.V0; // LEGACY +export const _ENDPOINT = ENDPOINT; // raydium mainnet program's base api path +export const addLookupTableInfo = LOOKUP_TABLE_CACHE; // only mainnet. other = undefined + +export const DEFAULT_TOKEN = { + SOL: new Currency(9, "SOL", "SOL"), + WSOL: new Token( + TOKEN_PROGRAM_ID, + new PublicKey("So11111111111111111111111111111111111111112"), + 9, + "WSOL", + "WSOL" + ), + USDC: new Token( + TOKEN_PROGRAM_ID, + new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), + 6, + "USDC", + "USDC" + ), +}; diff --git a/src/helpers/index.ts b/src/helpers/index.ts new file mode 100644 index 0000000..4811d57 --- /dev/null +++ b/src/helpers/index.ts @@ -0,0 +1,7 @@ +export * from "./config"; +export * from "./util"; +export * from "./unwrap_sol"; +export * from "./check_balance"; +export * from "./wrap_sol"; +export * from "./logger"; +export * from "./utils"; \ No newline at end of file diff --git a/src/helpers/logger.ts b/src/helpers/logger.ts new file mode 100644 index 0000000..393068e --- /dev/null +++ b/src/helpers/logger.ts @@ -0,0 +1,17 @@ +import pino from "pino"; + +const transport = pino.transport({ + target: 'pino-pretty', +}); + +export const logger = pino( + { + level: 'info', + redact: ['poolKeys'], + serializers: { + error: pino.stdSerializers.err, + }, + base: undefined, + }, + transport, +); diff --git a/src/helpers/unwrap_sol.js b/src/helpers/unwrap_sol.ts similarity index 82% rename from src/helpers/unwrap_sol.js rename to src/helpers/unwrap_sol.ts index 0ea12e4..1fe496c 100644 --- a/src/helpers/unwrap_sol.js +++ b/src/helpers/unwrap_sol.ts @@ -1,7 +1,7 @@ -const { NATIVE_MINT, getOrCreateAssociatedTokenAccount, createCloseAccountInstruction } = require("@solana/spl-token"); -const { wallet, connection } = require("./config"); -const { Transaction, LAMPORTS_PER_SOL, sendAndConfirmTransaction } = require("@solana/web3.js"); -const { program } = require("commander"); +import { NATIVE_MINT, getOrCreateAssociatedTokenAccount, createCloseAccountInstruction } from "@solana/spl-token"; +import { wallet, connection } from "./config"; +import { Transaction, LAMPORTS_PER_SOL, sendAndConfirmTransaction } from "@solana/web3.js"; +import { program } from "commander"; program .option("-h, --help", "display help for command") .action((options) => { @@ -13,7 +13,7 @@ program } }); program.parse(); -async function unwrapSol(){ +export async function unwrapSol(){ // wSol ATA const wSolAta = await getOrCreateAssociatedTokenAccount(connection, wallet, NATIVE_MINT, wallet.publicKey); diff --git a/src/helpers/util.js b/src/helpers/util.ts similarity index 84% rename from src/helpers/util.js rename to src/helpers/util.ts index dfa037a..c78dd68 100644 --- a/src/helpers/util.js +++ b/src/helpers/util.ts @@ -1,18 +1,18 @@ -const { +import { TOKEN_PROGRAM_ID, SPL_ACCOUNT_LAYOUT, buildSimpleTransaction, -} = require("@raydium-io/raydium-sdk"); -const { PublicKey, VersionedTransaction, Keypair } = require("@solana/web3.js"); -const { +} from "@raydium-io/raydium-sdk"; +import { PublicKey, VersionedTransaction, Keypair } from "@solana/web3.js"; +import { addLookupTableInfo, connection, makeTxVersion, wallet, -} = require("./config.js"); -const { Metaplex } = require("@metaplex-foundation/js"); -const fs = require("fs"); -const { +} from "./config"; +import { Metaplex } from "@metaplex-foundation/js"; +import fs from "fs"; +import { Connection, LAMPORTS_PER_SOL, SystemProgram, @@ -20,24 +20,14 @@ const { TransactionMessage, Transaction, ComputeBudgetProgram, -} = require("@solana/web3.js"); +} from "@solana/web3.js"; -/** - * Retrieves the number of decimals for a given mint address. - * @param {PublicKey} mintAddress - The address of the mint. - * @returns {Promise} The number of decimals. - */ -async function getDecimals(mintAddress) { - const info = await connection.getParsedAccountInfo(mintAddress); - const result = (info.value?.data).parsed.info.decimals || 0; - return result; -} /** * Retrieves the metadata of a token based on its address. * @param {string} address - The address of the token. * @returns {Promise<{ tokenName: string, tokenSymbol: string }>} The token metadata, including the token name and symbol. */ -async function getTokenMetadata(address) { +export async function getTokenMetadata(address:string) { const metaplex = Metaplex.make(connection); const mintAddress = new PublicKey(address); @@ -69,7 +59,7 @@ async function getTokenMetadata(address) { * @param {TransactionSendOptions} options - The options for sending the transactions. * @returns {Promise>} - A promise that resolves to an array of transaction IDs. */ -async function sendTx(connection, payer, txs, options) { +export async function sendTx(connection:Connection, payer:Keypair, txs:any, options:any) { const txids = []; try { for (const iTx of txs) { @@ -96,7 +86,7 @@ async function sendTx(connection, payer, txs, options) { * @param {Wallet} localwallet - The wallet object. * @returns {Array} An array of token account objects. */ -async function getWalletTokenAccount(localconnection, localwallet) { +export async function getWalletTokenAccount(localconnection:Connection, localwallet:PublicKey) { const walletTokenAccount = await localconnection.getTokenAccountsByOwner( localwallet, { @@ -116,7 +106,7 @@ async function getWalletTokenAccount(localconnection, localwallet) { * @param {Object} options - The options for the transaction. * @returns {Promise} - A promise that resolves with the result of the transaction. */ -async function buildAndSendTx(innerSimpleV0Transaction, options) { +export async function buildAndSendTx(innerSimpleV0Transaction:any, options:any) { try { const recentBlockhash = await connection.getLatestBlockhash("confirmed"); const priority_fee_arr = [ @@ -155,7 +145,7 @@ async function buildAndSendTx(innerSimpleV0Transaction, options) { * @param {number} ms - The duration to sleep in milliseconds. * @returns {Promise} - A promise that resolves after the specified duration. */ -async function sleepTime(ms) { +export async function sleepTime(ms:any) { console.log(new Date().toLocaleString(), "sleepTime", ms); return new Promise((resolve) => setTimeout(resolve, ms)); } @@ -168,7 +158,7 @@ async function sleepTime(ms) { * @param {string} filepath - The path to the file where the keypair is stored or will be stored. * @returns {Promise} The loaded or newly created keypair. */ -async function loadOrCreateKeypair_wallet(filepath) { +export async function loadOrCreateKeypair_wallet(filepath:string) { try { const keypairString = fs.readFileSync(filepath, { encoding: "utf8" }); return Keypair.fromSecretKey(Uint8Array.from(JSON.parse(keypairString))); @@ -182,7 +172,7 @@ async function loadOrCreateKeypair_wallet(filepath) { return newKeypair; } } -async function isBlockhashExpired(lastValidBlockHeight) { +export async function isBlockhashExpired(lastValidBlockHeight:number) { let currentBlockHeight = await connection.getBlockHeight("finalized"); console.log(" "); console.log("Current Block height: ", currentBlockHeight); @@ -199,10 +189,10 @@ async function isBlockhashExpired(lastValidBlockHeight) { return currentBlockHeight > lastValidBlockHeight - 150; } -const sleep = (ms) => { +export const sleep = (ms:number) => { return new Promise((resolve) => setTimeout(resolve, ms)); }; -async function checkTx(txId) { +export async function checkTx(txId:string) { const blockhashResponse = await connection.getLatestBlockhashAndContext( "finalized" ); @@ -242,14 +232,3 @@ async function checkTx(txId) { await sleep(2500); } } - -module.exports = { - getDecimals, - getTokenMetadata, - getWalletTokenAccount, - sendTx, - buildAndSendTx, - sleepTime, - loadOrCreateKeypair_wallet, - checkTx, -}; diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts new file mode 100644 index 0000000..f147c35 --- /dev/null +++ b/src/helpers/utils.ts @@ -0,0 +1,115 @@ +import { Logger } from "pino"; +import dotenv from "dotenv"; +import fs from "fs"; +import { Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js"; +import { Connection, PublicKey } from "@solana/web3.js"; +import { getAssociatedTokenAddressSync } from "@solana/spl-token"; +import { connection } from "./config"; +dotenv.config(); + +export const TOKEN_PROGRAM_ID = new PublicKey( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" +); +export const retrieveEnvVariable = (variableName: string, logger: Logger) => { + const variable = process.env[variableName] || ""; + if (!variable) { + logger.error(`${variableName} is not set`); + process.exit(1); + } + return variable; +}; + +export function getKeypairByJsonPath(jsonPath: string): any { + try { + const keypairJson = fs.readFileSync(jsonPath, "utf-8"); + const data = JSON.parse(keypairJson); + const mintKeypair = Keypair.fromSecretKey(Uint8Array.from(data)); + return mintKeypair; + } catch (e) { + console.log(e); + } +} +export async function printSOLBalance( + connection: Connection, + pubKey: PublicKey, + info = "" +) { + const balance = await connection.getBalance(pubKey); + console.log( + `${info ? info + " " : ""}${pubKey.toBase58()}:`, + balance / LAMPORTS_PER_SOL, + `SOL` + ); +} + +export async function getSPLBalance( + connection: Connection, + mintAddress: PublicKey, + pubKey: PublicKey, + allowOffCurve = false +): Promise { + try { + let ata = getAssociatedTokenAddressSync(mintAddress, pubKey, allowOffCurve); + const balance = await connection.getTokenAccountBalance(ata, "processed"); + return balance.value.uiAmount || 0; + } catch (e) {} + return 0; +} +export async function printSPLBalance( + connection: Connection, + mintAddress: PublicKey, + user: PublicKey, + info = "" +) { + const balance = await getSPLBalance(connection, mintAddress, user); + if (balance === null) { + console.log( + `${info ? info + " " : ""}${user.toBase58()}:`, + "No Account Found" + ); + } else { + console.log(`${info ? info + " " : ""}${user.toBase58()}:`, balance); + } +} +export async function retriveWalletState(wallet_address: string) { + try { + const filters = [ + { + dataSize: 165, //size of account (bytes) + }, + { + memcmp: { + offset: 32, //location of our query in the account (bytes) + bytes: wallet_address, //our search criteria, a base58 encoded string + }, + }, + ]; + const accounts = await connection.getParsedProgramAccounts( + TOKEN_PROGRAM_ID, //new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") + { filters: filters } + ); + let results: any = {}; + const solBalance = await connection.getBalance( + new PublicKey(wallet_address) + ); + accounts.forEach((account, i) => { + //Parse the account data + const parsedAccountInfo: any = account.account.data; + const mintAddress = parsedAccountInfo["parsed"]["info"]["mint"]; + const tokenBalance = + parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"]; + results[mintAddress] = tokenBalance; + }); + results["SOL"] = solBalance / 10 ** 9; + return results || {}; + } catch (e) { + console.log(e); + } + return {}; +} + +export async function getDecimals(mintAddress: PublicKey): Promise { + const info: any = await connection.getParsedAccountInfo(mintAddress); + const result = (info.value?.data).parsed.info.decimals || 0; + return result; +} diff --git a/src/helpers/wrap_sol.js b/src/helpers/wrap_sol.ts similarity index 78% rename from src/helpers/wrap_sol.js rename to src/helpers/wrap_sol.ts index 4d47204..001509c 100644 --- a/src/helpers/wrap_sol.js +++ b/src/helpers/wrap_sol.ts @@ -1,13 +1,13 @@ -const { NATIVE_MINT, getOrCreateAssociatedTokenAccount, createSyncNativeInstruction, } = require("@solana/spl-token"); -const { wallet, connection } = require("./config"); -const { Transaction, SystemProgram, LAMPORTS_PER_SOL, sendAndConfirmTransaction } = require("@solana/web3.js"); -const {getSPLTokenBalance} = require("./check_balance") -const { program } = require("commander"); +import { NATIVE_MINT, getOrCreateAssociatedTokenAccount, createSyncNativeInstruction, } from "@solana/spl-token"; +import { wallet, connection } from "./config"; +import { Transaction, SystemProgram, LAMPORTS_PER_SOL, sendAndConfirmTransaction } from "@solana/web3.js"; +import {getSPLTokenBalance} from "./check_balance"; +import { program } from "commander"; let wrap_size = 0; program .option("-s, --size ", "size of sol to wrap") .option("-h, --help", "display help for command") - .action((options) => { + .action((options:any) => { if (options.help) { console.log( "node wrap_sol.js --size " @@ -23,8 +23,8 @@ program } }); program.parse(); -async function wrap_sol( - amount +export async function wrap_sol( + amount:number ){ // wSol ATA const wSolAta = await getOrCreateAssociatedTokenAccount(connection, wallet, NATIVE_MINT, wallet.publicKey); @@ -62,12 +62,12 @@ async function wrap_sol( return txSignature; } -async function check_wsol_balance(wSolAta){ +export async function check_wsol_balance(wSolAta:any){ const wsolBalance = await getSPLTokenBalance(connection, NATIVE_MINT, wallet.publicKey); console.log(`new wsol balance: ${wsolBalance}`); } -async function main(){ +export async function main(){ await wrap_sol(wrap_size); } diff --git a/src/Trading_dev/dex/meteora/sell.js b/src/jupiter/README.md similarity index 100% rename from src/Trading_dev/dex/meteora/sell.js rename to src/jupiter/README.md diff --git a/src/Trading_dev/dex/orca/buy.js b/src/jupiter/dca.ts similarity index 100% rename from src/Trading_dev/dex/orca/buy.js rename to src/jupiter/dca.ts diff --git a/src/jupiter/index.ts b/src/jupiter/index.ts new file mode 100644 index 0000000..06a050f --- /dev/null +++ b/src/jupiter/index.ts @@ -0,0 +1,3 @@ +export * from "./swap/swap-helper"; +export * from "./swap/buy-helper"; +export * from "./swap/sell-helper"; \ No newline at end of file diff --git a/src/Trading_dev/dex/orca/fetch-pool.js b/src/jupiter/limit_order.ts similarity index 100% rename from src/Trading_dev/dex/orca/fetch-pool.js rename to src/jupiter/limit_order.ts diff --git a/src/jupiter/swap/buy-helper.js b/src/jupiter/swap/buy-helper.ts similarity index 58% rename from src/jupiter/swap/buy-helper.js rename to src/jupiter/swap/buy-helper.ts index 749e052..2f5d659 100644 --- a/src/jupiter/swap/buy-helper.js +++ b/src/jupiter/swap/buy-helper.ts @@ -1,7 +1,7 @@ -const swap_helper = require("./swap-helper"); -const { PublicKey } = require("@solana/web3.js"); -const { wallet } = require("../../helpers/config"); -const { getDecimals } = require("../../helpers/util"); +import {getQuote, getSwapTransaction, convertToInteger, finalizeTransaction} from "./swap-helper"; +import { PublicKey } from "@solana/web3.js"; +import { wallet } from "../../helpers/config"; +import { getDecimals } from "../../helpers/util"; const wsol = "So11111111111111111111111111111111111111112"; /** @@ -13,13 +13,13 @@ const wsol = "So11111111111111111111111111111111111111112"; * @returns {Promise} - A promise that resolves when the buy operation is completed. * @throws {Error} - If an error occurs during the buy operation. */ -async function buy(tokenToBuy, amountTokenOut, slippage) { +export async function buy(tokenToBuy:string, amountTokenOut:number, slippage:any) { try { - const convertedAmountOfTokenOut = await swap_helper.convertToInteger( + const convertedAmountOfTokenOut = await convertToInteger( amountTokenOut, 9 ); - const quoteResponse = await swap_helper.getQuote( + const quoteResponse = await getQuote( wsol, tokenToBuy, convertedAmountOfTokenOut, @@ -27,12 +27,12 @@ async function buy(tokenToBuy, amountTokenOut, slippage) { ); console.log(quoteResponse); const wallet_PubKey = wallet.publicKey.toBase58(); - const swapTransaction = await swap_helper.getSwapTransaction( + const swapTransaction = await getSwapTransaction( quoteResponse, wallet_PubKey ); const { confirmed, signature } = - await swap_helper.finalizeTransaction(swapTransaction); + await finalizeTransaction(swapTransaction); if (confirmed) { console.log("http://solscan.io/tx/" + signature); } else { @@ -45,4 +45,12 @@ async function buy(tokenToBuy, amountTokenOut, slippage) { } } -module.exports = { buy }; +async function main() { + const tokenAddress = "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh"; + const amountOfSOLToUse = 0.015 + const slippage = 1; + await buy(tokenAddress, amountOfSOLToUse, slippage); +} + +//main(); + diff --git a/src/jupiter/swap/sell-helper.js b/src/jupiter/swap/sell-helper.ts similarity index 57% rename from src/jupiter/swap/sell-helper.js rename to src/jupiter/swap/sell-helper.ts index 1e4d946..4eabd22 100644 --- a/src/jupiter/swap/sell-helper.js +++ b/src/jupiter/swap/sell-helper.ts @@ -1,7 +1,12 @@ -const swap_helper = require("./swap-helper"); -const { PublicKey } = require("@solana/web3.js"); -const { wallet } = require("../../helpers/config"); -const { getDecimals } = require("../../helpers/util"); +import { + convertToInteger, + getQuote, + getSwapTransaction, + finalizeTransaction, +} from "./swap-helper"; +import { PublicKey } from "@solana/web3.js"; +import { wallet } from "../../helpers/config"; +import { getDecimals } from "../../helpers/util"; const wsol = "So11111111111111111111111111111111111111112"; /** @@ -11,29 +16,31 @@ const wsol = "So11111111111111111111111111111111111111112"; * @param {number} slippage - The slippage tolerance percentage. * @returns {Promise} - A promise that resolves when the sell operation is completed. */ -async function sell(tokenToSell, amountOfTokenToSell, slippage) { +export async function sell( + tokenToSell: string, + amountOfTokenToSell: number, + slippage: any +) { try { const decimals = await getDecimals(new PublicKey(tokenToSell)); console.log(decimals); - const convertedAmountOfTokenOut = await swap_helper.convertToInteger( + const convertedAmountOfTokenOut = await convertToInteger( amountOfTokenToSell, decimals ); console.log(convertedAmountOfTokenOut); - const quoteResponse = await swap_helper.getQuote( + const quoteResponse = await getQuote( tokenToSell, wsol, convertedAmountOfTokenOut, slippage ); const wallet_PubKey = wallet.publicKey.toBase58(); - const swapTransaction = await swap_helper.getSwapTransaction( + const swapTransaction = await getSwapTransaction( quoteResponse, wallet_PubKey ); - const { confirmed, signature } = await swap_helper.finalizeTransaction( - swapTransaction - ); + const { confirmed, signature } = await finalizeTransaction(swapTransaction); if (confirmed) { console.log("http://solscan.io/tx/" + signature); } else { @@ -46,4 +53,11 @@ async function sell(tokenToSell, amountOfTokenToSell, slippage) { } } -module.exports = { sell }; +async function main() { + const tokenAddress = "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh"; + const amountOfTokenToSell = 0.000025; + const slippage = 1; + await sell(tokenAddress, amountOfTokenToSell, slippage); +} + +// main(); \ No newline at end of file diff --git a/src/jupiter/swap/swap-helper.js b/src/jupiter/swap/swap-helper.ts similarity index 82% rename from src/jupiter/swap/swap-helper.js rename to src/jupiter/swap/swap-helper.ts index b87e83a..faa2e1a 100644 --- a/src/jupiter/swap/swap-helper.js +++ b/src/jupiter/swap/swap-helper.ts @@ -1,10 +1,10 @@ -const { VersionedTransaction, PublicKey } = require("@solana/web3.js"); -const fetch = require("cross-fetch"); -const { connection, wallet, jito_fee } = require("../../helpers/config"); -const { +import { VersionedTransaction, PublicKey } from "@solana/web3.js"; +import fetch from "cross-fetch"; +import { connection, wallet, jito_fee } from "../../helpers/config"; +import { jito_executeAndConfirm, -} = require("../../Transactions/jito_tips_tx_executor"); -const { getDecimals } = require("../../helpers/util"); +} from "../../Transactions/jito_tips_tx_executor"; +import { getDecimals } from "../../helpers/util"; /** * Retrieves a quote for swapping tokens. * @@ -14,11 +14,11 @@ const { getDecimals } = require("../../helpers/util"); * @param {number} slippage - The allowed slippage in basis points. * @returns {Promise} - The quote object containing swap details. */ -async function getQuote( - tokenToSell, - tokenToBuy, - convertedAmountOfTokenOut, - slippage +export async function getQuote( + tokenToSell:string, + tokenToBuy:string, + convertedAmountOfTokenOut:number, + slippage:any ) { const url = `https://quote-api.jup.ag/v6/quote?inputMint=${tokenToSell}&outputMint=${tokenToBuy}&amount=${convertedAmountOfTokenOut}&slippageBps=${slippage}`; const response = await fetch(url); @@ -33,7 +33,7 @@ async function getQuote( * @returns {Promise} - The swap transaction. * @throws {Error} - If an error occurs during the process. */ -async function getSwapTransaction(quoteResponse, wallet_pubKey) { +export async function getSwapTransaction(quoteResponse:any, wallet_pubKey:string) { try { let body = null; body = { @@ -42,9 +42,6 @@ async function getSwapTransaction(quoteResponse, wallet_pubKey) { wrapAndUnwrapSol: true, dynamicComputeUnitLimit: true, // allow dynamic compute limit instead of max 1,400,000 prioritizationFeeLamports: 4211970, // prioritization fee - prioritizationFeeLamports: { - autoMultiplier: 2, - }, }; const resp = await fetch("https://quote-api.jup.ag/v6/swap", { method: "POST", @@ -55,7 +52,7 @@ async function getSwapTransaction(quoteResponse, wallet_pubKey) { }); const swapResponse = await resp.json(); return swapResponse.swapTransaction; - } catch (error) { + } catch (error:any) { throw new Error(error); } } @@ -65,7 +62,7 @@ async function getSwapTransaction(quoteResponse, wallet_pubKey) { * @param {number} decimals - The number of decimal places. * @returns {Promise} The converted integer value. */ -async function convertToInteger(amount, decimals) { +export async function convertToInteger(amount:number, decimals:number) { return Math.floor(amount * 10 ** decimals); } @@ -75,7 +72,7 @@ async function convertToInteger(amount, decimals) { * @returns {Promise<{ confirmed: boolean, signature: string }>} - A promise that resolves to an object containing the confirmation status and transaction signature. * @throws {Error} - If an error occurs during the transaction finalization process. */ -async function finalizeTransaction(swapTransaction) { +export async function finalizeTransaction(swapTransaction:any) { try { let confirmed = null, signature = null; @@ -85,8 +82,8 @@ async function finalizeTransaction(swapTransaction) { // sign the transaction transaction.sign([wallet]); - const latestBlockhash = await connection.getLatestBlockhash("processed"); - res = await jito_executeAndConfirm( + const latestBlockhash = await connection.getLatestBlockhash("confirmed"); + const res = await jito_executeAndConfirm( transaction, wallet, latestBlockhash, @@ -95,7 +92,7 @@ async function finalizeTransaction(swapTransaction) { confirmed = res.confirmed; signature = res.signature; return { confirmed, signature }; - } catch (error) { + } catch (error:any) { throw new Error(error); } return { confirmed: false, signature: null }; @@ -109,7 +106,7 @@ async function finalizeTransaction(swapTransaction) { * @param {number} slippage - The allowed slippage percentage. * @returns {Promise} - A promise that resolves when the swap transaction is completed. */ -async function swap(tokenToSell, tokenToBuy, amountTokenOut, slippage) { +export async function swap(tokenToSell:string, tokenToBuy:string, amountTokenOut:number, slippage:any) { try { const decimals = await getDecimals(new PublicKey(tokenToSell)); const convertedAmountOfTokenOut = await convertToInteger( @@ -138,11 +135,4 @@ async function swap(tokenToSell, tokenToBuy, amountTokenOut, slippage) { } catch (error) { console.error(error); } -} -module.exports = { - getQuote, - getSwapTransaction, - finalizeTransaction, - convertToInteger, - swap, -}; +} \ No newline at end of file diff --git a/src/meteora/Pool/fetch-pool.ts b/src/meteora/Pool/fetch-pool.ts new file mode 100644 index 0000000..7cd364b --- /dev/null +++ b/src/meteora/Pool/fetch-pool.ts @@ -0,0 +1,36 @@ +import { PublicKey, Keypair } from "@solana/web3.js"; +import DLMM from "@meteora-ag/dlmm"; +import { connection, wallet } from "../../helpers/config"; + +export async function fetchDLMMPoolId(tokenAddress: string) { + const url = `https://dlmm-api.meteora.ag/pair/all_by_groups?sort_key=tvl&order_by=desc&search_term=${tokenAddress}&include_unknown=false`; + const response = await (await fetch(url)).json(); + // check if the string start with "SOL" or end with "SOL" + + const listOfGroups = response.groups; + for (const group of listOfGroups) { + const name = group.name; + if (name.startsWith("SOL") || name.endsWith("SOL")) { + return group.pairs[0].address; + } + } + console.log( + "No DLMM Pool ID found for the given token address: ", + tokenAddress + ); + return ""; // return empty string if no DLMMPool ID is found +} +export async function fetchDLMMPool(tokenAddress: string) { + const poolId = await fetchDLMMPoolId(tokenAddress); + console.log("Pool ID: ", poolId); + const dlmmPool = await DLMM.create(connection, new PublicKey(poolId)); + return dlmmPool; +} +async function main() { + const tokenAddress = "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"; + // const poolId = await fetchDLMMPoolId(tokenAddress); + // console.log(poolId); + await fetchDLMMPool(tokenAddress); +} + +// main(); diff --git a/src/meteora/Pool/index.ts b/src/meteora/Pool/index.ts new file mode 100644 index 0000000..62ea691 --- /dev/null +++ b/src/meteora/Pool/index.ts @@ -0,0 +1,2 @@ +export * from "./fetch-pool"; +export * from "./swap"; \ No newline at end of file diff --git a/src/meteora/Pool/swap.ts b/src/meteora/Pool/swap.ts new file mode 100644 index 0000000..97588bc --- /dev/null +++ b/src/meteora/Pool/swap.ts @@ -0,0 +1,142 @@ +import "rpc-websockets/dist/lib/client"; +import { + PublicKey, + Keypair, + LAMPORTS_PER_SOL, + sendAndConfirmRawTransaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import DLMM from "@meteora-ag/dlmm"; +//const BN =require("bn.js"); +import { connection, wallet } from "../../helpers/config"; +import { getSPLTokenBalance } from "../../helpers/check_balance"; +import { PROGRAM_ID, wsol } from "../constants"; +import { fetchDLMMPoolId, fetchDLMMPool } from "./fetch-pool"; +import { + TransactionMessage, + ComputeBudgetProgram, + VersionedTransaction, +} from "@solana/web3.js"; +import { jito_executeAndConfirm } from "../../Transactions/jito_tips_tx_executor"; +import { jito_fee } from "../../helpers/config"; +import { C } from "@raydium-io/raydium-sdk-v2/lib/raydium-276d396e"; +const BN = require("bn.js"); + +/** + * Performs a swap operation in a DLMM pool. + * @param side The side of the swap operation, either "buy" or "sell". Default is "buy". + * @param tokenAddress The address of the token to be swapped. + * @param buyAmountInSOL The amount of SOL to be used for buying the token. Default is 0.1. + * @param sellPercentage The percentage of the token to be sold. Default is 100%. + * @returns A Promise that resolves to the transaction hash if the swap is successful, otherwise an error object. + */ +export async function swap( + side: string = "buy", + tokenAddress: string, + buyAmountInSOL: number = 0.1, + sellPercentage: number = 100 +) { + let swapYtoX = true, + decimalY: number, + decimalX: number, + inToken: PublicKey, + outToken: PublicKey, + swapAmount: any; + const dlmmPool = await fetchDLMMPool(tokenAddress); // fetch the DLMM pool object for swapping + decimalY = dlmmPool.tokenY.decimal; + decimalX = dlmmPool.tokenX.decimal; + if (side === "buy") { + // inToken = wsol + if (dlmmPool.tokenY.publicKey.toBase58() === wsol) { + inToken = dlmmPool.tokenY.publicKey; + outToken = dlmmPool.tokenX.publicKey; + } else { + inToken = dlmmPool.tokenX.publicKey; + outToken = dlmmPool.tokenY.publicKey; + } + swapAmount = new BN(buyAmountInSOL * 10 ** 9); // convert to lamports + } else { + if (dlmmPool.tokenY.publicKey.toBase58() === wsol) { + inToken = dlmmPool.tokenX.publicKey; + outToken = dlmmPool.tokenY.publicKey; + const balance = await getSPLTokenBalance( + connection, + inToken, + wallet.publicKey + ); + const amount = balance * (sellPercentage / 100); + swapAmount = new BN(amount * 10 ** decimalX); // convert to lamports + } else { + inToken = dlmmPool.tokenY.publicKey; + outToken = dlmmPool.tokenX.publicKey; + const balance = await getSPLTokenBalance( + connection, + inToken, + wallet.publicKey + ); + const amount = balance * (sellPercentage / 100); + swapAmount = new BN(amount * 10 ** decimalY); // convert to lamports + } + } + + const binArrays = await dlmmPool.getBinArrayForSwap(swapYtoX); // list of pools + const swapQuote = await dlmmPool.swapQuote( + // get the swap quote + swapAmount, + swapYtoX, + new BN(10), + binArrays + ); + const swapTx: any = await dlmmPool.swap({ + inToken: inToken, + binArraysPubkey: swapQuote.binArraysPubkey, + inAmount: swapAmount, + lbPair: dlmmPool.pubkey, + user: wallet.publicKey, + minOutAmount: swapQuote.minOutAmount, + outToken: outToken, + }); + console.log(swapTx); + // try { + // const swapTxHash = await sendAndConfirmTransaction(connection, swapTx, [ + // wallet, + // ]); + // console.log(`🚀 https://solscan.io/tx/${swapTxHash}`); + // } catch (error) { + // console.log("🚀 ~ error:", JSON.parse(JSON.stringify(error))); + // } + try { + const recentBlockhash = await connection.getLatestBlockhash(); + const messageV0 = new TransactionMessage({ + payerKey: wallet.publicKey, + recentBlockhash: recentBlockhash.blockhash, + instructions: [...swapTx.instructions], + }).compileToV0Message(); + + const transaction = new VersionedTransaction(messageV0); + transaction.sign([wallet]); + const res = await jito_executeAndConfirm( + transaction, + wallet, + recentBlockhash, + jito_fee + ); + const signature = res.signature; + const confirmed = res.confirmed; + + if (confirmed) { + console.log(`🚀 https://solscan.io/tx/${signature}`); + } else { + console.log( + "jito fee transaction failed when swapping token in a DLMM pool" + ); + } + } catch (error: any) { + console.log("🚀 ~ error:", JSON.parse(JSON.stringify(error))); + } +} +async function main() { + const tokenAddress = "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"; + await swap("sell", tokenAddress, -1, 100); +} +//main(); \ No newline at end of file diff --git a/src/Trading_dev/dex/orca/sell.js b/src/meteora/README.md similarity index 100% rename from src/Trading_dev/dex/orca/sell.js rename to src/meteora/README.md diff --git a/src/meteora/buy.ts b/src/meteora/buy.ts new file mode 100644 index 0000000..df514fe --- /dev/null +++ b/src/meteora/buy.ts @@ -0,0 +1,37 @@ +import {swap} from "./Pool" +import { program } from "commander"; + +let token:string="", + sol:number=0; +program + .option("--token ", "Specify the token address") + .option("--sol ", "Specify the number of SOL") + .option("-h, --help", "display help for command") + .action((options) => { + if (options.help) { + console.log( + "ts-node buy --token --sol " + ); + process.exit(0); + } + if (!options.token || !options.sol) { + console.error("❌ Missing required options"); + process.exit(1); + } + token = options.token; + sol = options.sol; + }); +program.parse(); + +/** + * Buy function to perform a swap on the Meteora DEX. + * + * @param {string} side - The side of the trade (buy/sell). + * @param {string} token_address - The address of the token to trade. + * @param {number} no_of_sol - The amount of SOL to trade. + * @returns {Promise} - A promise that resolves when the swap is completed. + */ +async function buy(side:string, token_address:string, no_of_sol:number) { + await swap(side, token_address, no_of_sol, -1); +} +buy("buy", token, sol); diff --git a/src/meteora/buy_helper.ts b/src/meteora/buy_helper.ts new file mode 100644 index 0000000..abdc4c4 --- /dev/null +++ b/src/meteora/buy_helper.ts @@ -0,0 +1,11 @@ +import {swap} from "./Pool"; + +/** + * Buys a specified amount of tokens using SOL. + * + * @param token_address The address of the token to buy. + * @param buyAmountInSOL The amount of SOL to use for the purchase. + */ +export async function buy(token_address:string, buyAmountInSOL:number) { + await swap("buy", token_address, buyAmountInSOL, -1); +} \ No newline at end of file diff --git a/src/meteora/constants.ts b/src/meteora/constants.ts new file mode 100644 index 0000000..98e4e7b --- /dev/null +++ b/src/meteora/constants.ts @@ -0,0 +1,5 @@ +export const PROGRAM_ID = "Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB"; +export const wsol = "So11111111111111111111111111111111111111112"; +export const usdc = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; +export const usdt = "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"; // USDT + diff --git a/src/meteora/fetch-price.ts b/src/meteora/fetch-price.ts new file mode 100644 index 0000000..3e01216 --- /dev/null +++ b/src/meteora/fetch-price.ts @@ -0,0 +1,35 @@ +import { fetchDLMMPoolId, fetchDLMMPool } from "./Pool"; +import {usdc} from "./constants"; + +// on-chain rpc method to get the current price of the token +export async function getCurrentPriceInSOL(tokenAddress:string):Promise { + const dlmmPool = await fetchDLMMPool(tokenAddress); + dlmmPool.refetchStates(); + const activeBin = await dlmmPool.getActiveBin(); + const activeBinPricePerToken = dlmmPool.fromPricePerLamport( + Number(activeBin.price) + ); + return activeBinPricePerToken; +} +export async function getCurrentSolPrice():Promise { + + const dlmmPool = await fetchDLMMPool(usdc); + dlmmPool.refetchStates(); + const activeBin = await dlmmPool.getActiveBin(); + const activeBinPricePerToken = dlmmPool.fromPricePerLamport( + Number(activeBin.price) + ); + return activeBinPricePerToken; +} +export async function getCurrentPriceInUSD(tokenAddress:string):Promise { + return (await getCurrentPriceInSOL(tokenAddress))*(await getCurrentSolPrice()); +} + + +async function main(){ + // console.log(await getCurrentPriceInSOL("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr")); + // console.log(await getCurrentPriceInUSD("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr")); + console.log(await getCurrentPriceInUSD("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr")); +} + +//main(); diff --git a/src/meteora/index.ts b/src/meteora/index.ts new file mode 100644 index 0000000..fb25ce1 --- /dev/null +++ b/src/meteora/index.ts @@ -0,0 +1,5 @@ +export * from "./buy_helper"; +export * from "./sell_helper"; +export * from "./fetch-price"; +export * from "./Pool"; +export * from "./token-filters"; \ No newline at end of file diff --git a/src/meteora/sell.ts b/src/meteora/sell.ts new file mode 100644 index 0000000..eb8601f --- /dev/null +++ b/src/meteora/sell.ts @@ -0,0 +1,37 @@ +import {swap} from "./Pool" +import { program } from "commander"; + +let token:string="", + percentage:number=0; +program + .option("--token ", "Specify the token address") + .option("--percentage ", "Specify the sell percentage") + .option("-h, --help", "display help for command") + .action((options) => { + if (options.help) { + console.log( + "ts-node sell --token --percentage " + ); + process.exit(0); + } + if (!options.token || !options.percentage) { + console.error("❌ Missing required options"); + process.exit(1); + } + token = options.token; + percentage = options.percentage; + }); +program.parse(); + +/** + * Sell function to perform a swap on the Meteora DEX. + * + * @param {string} side - The side of the trade (buy/sell). + * @param {string} token_address - The address of the token to trade. + * @param {number} sell_percentage - The sell percentage. + * @returns {Promise} - A promise that resolves when the swap is completed. + */ +async function sell(side:string, token_address:string, sell_percentage:number) { + await swap(side, token_address, -1, sell_percentage); +} +sell("sell", token, percentage); diff --git a/src/meteora/sell_helper.ts b/src/meteora/sell_helper.ts new file mode 100644 index 0000000..68ac72c --- /dev/null +++ b/src/meteora/sell_helper.ts @@ -0,0 +1,11 @@ +import {swap} from "./Pool"; + +/** + * Sells a token with the specified token address and sell percentage. + * + * @param token_address The address of the token to be sold. + * @param sell_percentage The percentage of the token to be sold. + */ +export async function sell(token_address:string, sell_percentage:number) { + await swap("sell", token_address, -1, sell_percentage); +} \ No newline at end of file diff --git a/src/meteora/token-filters/index.ts b/src/meteora/token-filters/index.ts new file mode 100644 index 0000000..12b289b --- /dev/null +++ b/src/meteora/token-filters/index.ts @@ -0,0 +1,3 @@ +export * from "./marketcap"; +export * from "./pool-sol"; +export * from "./volume"; \ No newline at end of file diff --git a/src/meteora/token-filters/marketcap.ts b/src/meteora/token-filters/marketcap.ts new file mode 100644 index 0000000..484f9ad --- /dev/null +++ b/src/meteora/token-filters/marketcap.ts @@ -0,0 +1,17 @@ +import { wsol } from "../constants"; +import { getCurrentPriceInUSD } from "../fetch-price"; +import { connection } from "../../helpers/config"; +import { PublicKey } from "@solana/web3.js"; + +export async function getCurrentMarketCap( + tokenAddress: string +): Promise { + let priceInUSD: number = await getCurrentPriceInUSD(tokenAddress); + const tokenSupply: any = await connection.getTokenSupply( + new PublicKey(tokenAddress) + ); + const marketCap: number = priceInUSD * tokenSupply.value.uiAmount; + return marketCap; +} + +//getCurrentMarketCap("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"); diff --git a/src/meteora/token-filters/pool-sol.ts b/src/meteora/token-filters/pool-sol.ts new file mode 100644 index 0000000..3f5c7a5 --- /dev/null +++ b/src/meteora/token-filters/pool-sol.ts @@ -0,0 +1,16 @@ +import {fetchDLMMPool} from "../Pool"; +import {wsol} from "../constants" +export async function getCurrentSolInPool(token_address:string):Promise { + const dlmmPool = await fetchDLMMPool(token_address); + let solReserve:number; + if(dlmmPool.tokenX.publicKey.toBase58() === wsol){ + solReserve = Number(dlmmPool.tokenX.amount)/Math.pow(10,dlmmPool.tokenX.decimal); + }else{ + solReserve = Number(dlmmPool.tokenY.amount)/Math.pow(10,dlmmPool.tokenY.decimal); + } + console.log(solReserve); + return solReserve; + +} + +//getCurrentSolInPool("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"); \ No newline at end of file diff --git a/src/meteora/token-filters/volume.ts b/src/meteora/token-filters/volume.ts new file mode 100644 index 0000000..863eabe --- /dev/null +++ b/src/meteora/token-filters/volume.ts @@ -0,0 +1,58 @@ +import {fetchDLMMPoolId} from "../Pool"; +const fetch = require('node-fetch'); + + +// max 255 days of data +export async function getLastNDayVolume( + tokenAddress: string, + n: number +): Promise { + const poolId = await fetchDLMMPoolId(tokenAddress); + const url = `https://dlmm-api.meteora.ag/pair/${poolId}/analytic/pair_trade_volume?num_of_days=${n}` + const response = await (await fetch(url)).json(); + let sumOfVolume = 0; + for (const day of response) { + sumOfVolume += day.trade_volume; + } + console.log(sumOfVolume); + return sumOfVolume; +} + +export async function getDayVolume(tokenAddress:string){ + const poolId = await fetchDLMMPoolId(tokenAddress); + const url = `https://dlmm-api.meteora.ag/pair/${poolId}/analytic/pair_trade_volume?num_of_days=1` + const response = await (await fetch(url)).json(); + let sumOfVolume = 0; + for (const day of response) { + sumOfVolume += day.trade_volume; + } + console.log(sumOfVolume); + return sumOfVolume; +} + +export async function getWeekVolume(tokenAddress:string){ + const poolId = await fetchDLMMPoolId(tokenAddress); + const url = `https://dlmm-api.meteora.ag/pair/${poolId}/analytic/pair_trade_volume?num_of_days=7` + const response = await (await fetch(url)).json(); + let sumOfVolume = 0; + for (const day of response) { + sumOfVolume += day.trade_volume; + } + console.log(sumOfVolume); + return sumOfVolume; +} + +export async function getMonthVolume(tokenAddress:string){ + const poolId = await fetchDLMMPoolId(tokenAddress); + const url = `https://dlmm-api.meteora.ag/pair/${poolId}/analytic/pair_trade_volume?num_of_days=30` + const response = await (await fetch(url)).json(); + let sumOfVolume = 0; + for (const day of response) { + sumOfVolume += day.trade_volume; + } + console.log(sumOfVolume); + return sumOfVolume; +} + + +//getMonthVolume("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"); \ No newline at end of file diff --git a/src/orca/Pool/fetch-pool.ts b/src/orca/Pool/fetch-pool.ts new file mode 100644 index 0000000..a53cb27 --- /dev/null +++ b/src/orca/Pool/fetch-pool.ts @@ -0,0 +1,31 @@ +import { PublicKey } from "@solana/web3.js"; +import { + ORCA_WHIRLPOOL_PROGRAM_ID, + PDAUtil, +} from "@orca-so/whirlpools-sdk"; +import { + MAINNET_WHIRLPOOLS_CONFIG, + WSOL, + tick_spacing, + client +} from "../constants"; + +export async function fetchWhirlPoolId(tokenAddress:string) { + const tokenMint = new PublicKey(tokenAddress); + const whirlpool_pubkey = PDAUtil.getWhirlpool( + ORCA_WHIRLPOOL_PROGRAM_ID, + MAINNET_WHIRLPOOLS_CONFIG, + WSOL.mint, + tokenMint, + tick_spacing + ).publicKey; + console.log("Pool Id: ", whirlpool_pubkey.toBase58()); + return whirlpool_pubkey.toBase58(); +} +export async function fetchWhirlPool(tokenAddress:string) { + const whirlPoolId = await fetchWhirlPoolId(tokenAddress); + const whirlpool = await client.getPool(new PublicKey(whirlPoolId)); + return whirlpool; +} + +//fetchWhirlPool("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"); diff --git a/src/orca/Pool/index.ts b/src/orca/Pool/index.ts new file mode 100644 index 0000000..62ea691 --- /dev/null +++ b/src/orca/Pool/index.ts @@ -0,0 +1,2 @@ +export * from "./fetch-pool"; +export * from "./swap"; \ No newline at end of file diff --git a/src/orca/Pool/swap.ts b/src/orca/Pool/swap.ts new file mode 100644 index 0000000..dc6a6f7 --- /dev/null +++ b/src/orca/Pool/swap.ts @@ -0,0 +1,116 @@ +import { + DecimalUtil, + Percentage, +} from "@orca-so/common-sdk"; +import { + swapQuoteByInputToken, + IGNORE_CACHE, +} from "@orca-so/whirlpools-sdk"; +import { + MAINNET_WHIRLPOOLS_CONFIG, + WSOL, + USDC, + tick_spacing, + ourWallet, + client, + ctx +} from "../constants"; +import Decimal from "decimal.js"; +import { connection, wallet, jito_fee } from "../../helpers/config"; +import { getSPLTokenBalance } from "../../helpers/check_balance" +import { jito_executeAndConfirm } from "../../Transactions"; +import { TransactionMessage, Transaction, TransactionInstruction, VersionedTransaction, PublicKey} from "@solana/web3.js"; +import {fetchWhirlPool} from "./fetch-pool" +/** + * Performs a swap operation in a Whirl pool. + * @param side The side of the swap operation, either "buy" or "sell". Default is "buy". + * @param tokenAddress The address of the token to be swapped. + * @param buyAmountInSOL The amount of SOL to be used for buying the token. Default is 0.1. + * @param sellPercentage The percentage of the token to be sold. Default is 100%. + * @returns A Promise that resolves to the transaction hash if the swap is successful, otherwise an error object. + */ +export async function swap( + side: string = "buy", + tokenAddress: string, + buyAmountInSOL: number = 0.1, + sellPercentage: number = 100 +) { + const tokenMint = new PublicKey(tokenAddress); + const whirlPool:any = await fetchWhirlPool(tokenAddress); + let amountIn:Decimal, inToken:PublicKey, outToken:PublicKey, tokenDecimal:number, quote:any; + if(side === "buy"){ + amountIn = new Decimal(buyAmountInSOL); + inToken = WSOL.mint; + outToken = tokenMint; + quote = await swapQuoteByInputToken( + whirlPool, + inToken, + DecimalUtil.toBN(amountIn, WSOL.decimals), + Percentage.fromFraction(10, 1000), // 10/1000 = 1% slippage + ctx.program.programId, + ctx.fetcher, + IGNORE_CACHE + ); + }else{ + const balance = await getSPLTokenBalance(connection, tokenMint, wallet.publicKey); + amountIn = new Decimal(balance * (sellPercentage / 100)); + inToken = tokenMint; + outToken = WSOL.mint; + if(whirlPool.tokenAInfo.mint.toBase58() === tokenMint.toBase58()){ + tokenDecimal = whirlPool.tokenAInfo.decimals; + }else{ + tokenDecimal = whirlPool.tokenBInfo.decimals; + } + quote = await swapQuoteByInputToken( + whirlPool, + inToken, + DecimalUtil.toBN(amountIn, tokenDecimal), + Percentage.fromFraction(10, 1000), // 10/1000 = 1% slippage + ctx.program.programId, + ctx.fetcher, + IGNORE_CACHE + ); + } + // build the tx + const swapTx: any = await whirlPool.swap(quote); + let ixList = [], signers = []; + // extract the instructions and signers + for (const ix of swapTx.instructions) { + ixList.push(...ix.instructions); + //ixList.push(...ix.cleanupInstructions); + signers.push(...ix.signers); + } + + // send the tx to jito + try { + const recentBlockhash = await connection.getLatestBlockhash(); + const messageV0 = new TransactionMessage({ + payerKey: wallet.publicKey, + recentBlockhash: recentBlockhash.blockhash, + instructions: [...ixList], + }).compileToV0Message(); + + const transaction = new VersionedTransaction(messageV0); + transaction.sign([wallet,...signers]); + const res = await jito_executeAndConfirm( + transaction, + wallet, + recentBlockhash, + jito_fee + ); + const signature = res.signature; + const confirmed = res.confirmed; + + if (confirmed) { + console.log(`🚀 https://solscan.io/tx/${signature}`); + } else { + console.log( + "jito fee transaction failed when swapping token in a orca whirl pool" + ); + } + } catch (error: any) { + console.log("🚀 ~ error: ", JSON.parse(JSON.stringify(error))); + } +} +//swap("buy", "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr", 0.01, -1); // buy 0.01 SOL worth of the token +//swap("sell", "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr", -1, 50); // sell 50% of the token diff --git a/src/Trading_dev/dex/orca/swap.js b/src/orca/README.md similarity index 100% rename from src/Trading_dev/dex/orca/swap.js rename to src/orca/README.md diff --git a/src/orca/buy.ts b/src/orca/buy.ts new file mode 100644 index 0000000..df514fe --- /dev/null +++ b/src/orca/buy.ts @@ -0,0 +1,37 @@ +import {swap} from "./Pool" +import { program } from "commander"; + +let token:string="", + sol:number=0; +program + .option("--token ", "Specify the token address") + .option("--sol ", "Specify the number of SOL") + .option("-h, --help", "display help for command") + .action((options) => { + if (options.help) { + console.log( + "ts-node buy --token --sol " + ); + process.exit(0); + } + if (!options.token || !options.sol) { + console.error("❌ Missing required options"); + process.exit(1); + } + token = options.token; + sol = options.sol; + }); +program.parse(); + +/** + * Buy function to perform a swap on the Meteora DEX. + * + * @param {string} side - The side of the trade (buy/sell). + * @param {string} token_address - The address of the token to trade. + * @param {number} no_of_sol - The amount of SOL to trade. + * @returns {Promise} - A promise that resolves when the swap is completed. + */ +async function buy(side:string, token_address:string, no_of_sol:number) { + await swap(side, token_address, no_of_sol, -1); +} +buy("buy", token, sol); diff --git a/src/orca/buy_helper.ts b/src/orca/buy_helper.ts new file mode 100644 index 0000000..7600568 --- /dev/null +++ b/src/orca/buy_helper.ts @@ -0,0 +1,11 @@ +import {swap} from "./Pool"; + +/** + * Buys a specified amount of tokens using SOL. + * + * @param token_address The address of the token to buy. + * @param buyAmountInSOL The amount of SOL to use for the purchase. + */ +export async function buy(token_address:string, buyAmountInSOL:number) { + await swap("buy", token_address, buyAmountInSOL, -1); +} \ No newline at end of file diff --git a/src/orca/constants.ts b/src/orca/constants.ts new file mode 100644 index 0000000..8e3ecf0 --- /dev/null +++ b/src/orca/constants.ts @@ -0,0 +1,28 @@ +import { PublicKey } from "@solana/web3.js"; +import { AnchorProvider, Wallet } from "@coral-xyz/anchor"; +import { connection, wallet} from "../helpers/config" +import { + WhirlpoolContext, + buildWhirlpoolClient, + ORCA_WHIRLPOOL_PROGRAM_ID +} from "@orca-so/whirlpools-sdk"; +export const ourWallet = new Wallet(wallet); +export const provider = new AnchorProvider(connection, ourWallet, { + commitment: "confirmed", + }); +export const ctx = WhirlpoolContext.withProvider( + provider, + ORCA_WHIRLPOOL_PROGRAM_ID +); +export const client = buildWhirlpoolClient(ctx); +export const PROGRAM_ID = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc"; +export const MAINNET_WHIRLPOOLS_CONFIG = new PublicKey("2LecshUwdy9xi7meFgHtFJQNSKk4KdTrcpvaB56dP2NQ"); +export const DEVNET_WHIRLPOOLS_CONFIG = new PublicKey("FcrweFY1G9HJAHG5inkGB6pKg1HZ6x9UC2WioAfWrGkR"); +export const wsol = "So11111111111111111111111111111111111111112"; +export const usdc = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; +export const usdt = "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"; +export const USDC = {mint: new PublicKey(usdc), decimals: 6}; +export const WSOL = {mint: new PublicKey(wsol), decimals: 9}; +export const USDT = {mint: new PublicKey(usdt), decimals: 6}; +export const tick_spacing = 64; + diff --git a/src/orca/fetch-price.ts b/src/orca/fetch-price.ts new file mode 100644 index 0000000..25e814f --- /dev/null +++ b/src/orca/fetch-price.ts @@ -0,0 +1,24 @@ +import Decimal from "decimal.js"; +import { wsol, usdc } from "../raydium"; +import {fetchWhirlPool} from "./Pool" +import { PriceMath } from "@orca-so/whirlpools-sdk"; +// on-chain rpc method to get the current price of the token +export async function getCurrentPriceInSOL(tokenAddress:string):Promise { + const whirlPool:any = await fetchWhirlPool(tokenAddress); + const sqrt_price_x64 = whirlPool.getData().sqrtPrice; + const price = PriceMath.sqrtPriceX64ToPrice(sqrt_price_x64, whirlPool.tokenAInfo.decimals, whirlPool.tokenBInfo.decimals); + return new Decimal(1).div(price.toFixed(whirlPool.tokenBInfo.decimals)); +} +export async function getCurrentSolPrice():Promise { + const whirlPool:any = await fetchWhirlPool(usdc); + const sqrt_price_x64 = whirlPool.getData().sqrtPrice; + const price = PriceMath.sqrtPriceX64ToPrice(sqrt_price_x64, whirlPool.tokenAInfo.decimals, whirlPool.tokenBInfo.decimals); + return price; +} +export async function getCurrentPriceInUSD(tokenAddress:string):Promise { + return (await getCurrentPriceInSOL(tokenAddress))*(await getCurrentSolPrice()); +} + +//getCurrentPriceInSOL("DhFTtmQ1ymhWWabzViW1Ewf43iaqaVuriSsw5HF8pump"); +//getCurrentSolPrice(); +//getCurrentPriceInUSD("DhFTtmQ1ymhWWabzViW1Ewf43iaqaVuriSsw5HF8pump"); \ No newline at end of file diff --git a/src/orca/index.ts b/src/orca/index.ts new file mode 100644 index 0000000..fe46c0f --- /dev/null +++ b/src/orca/index.ts @@ -0,0 +1,3 @@ +export * from "./Pool"; +export * from "./sell_helper"; +export * from "./buy_helper"; \ No newline at end of file diff --git a/src/orca/sell.ts b/src/orca/sell.ts new file mode 100644 index 0000000..eb8601f --- /dev/null +++ b/src/orca/sell.ts @@ -0,0 +1,37 @@ +import {swap} from "./Pool" +import { program } from "commander"; + +let token:string="", + percentage:number=0; +program + .option("--token ", "Specify the token address") + .option("--percentage ", "Specify the sell percentage") + .option("-h, --help", "display help for command") + .action((options) => { + if (options.help) { + console.log( + "ts-node sell --token --percentage " + ); + process.exit(0); + } + if (!options.token || !options.percentage) { + console.error("❌ Missing required options"); + process.exit(1); + } + token = options.token; + percentage = options.percentage; + }); +program.parse(); + +/** + * Sell function to perform a swap on the Meteora DEX. + * + * @param {string} side - The side of the trade (buy/sell). + * @param {string} token_address - The address of the token to trade. + * @param {number} sell_percentage - The sell percentage. + * @returns {Promise} - A promise that resolves when the swap is completed. + */ +async function sell(side:string, token_address:string, sell_percentage:number) { + await swap(side, token_address, -1, sell_percentage); +} +sell("sell", token, percentage); diff --git a/src/orca/sell_helper.ts b/src/orca/sell_helper.ts new file mode 100644 index 0000000..68ac72c --- /dev/null +++ b/src/orca/sell_helper.ts @@ -0,0 +1,11 @@ +import {swap} from "./Pool"; + +/** + * Sells a token with the specified token address and sell percentage. + * + * @param token_address The address of the token to be sold. + * @param sell_percentage The percentage of the token to be sold. + */ +export async function sell(token_address:string, sell_percentage:number) { + await swap("sell", token_address, -1, sell_percentage); +} \ No newline at end of file diff --git a/src/orca/token-filters/marketcap.ts b/src/orca/token-filters/marketcap.ts new file mode 100644 index 0000000..85ebadd --- /dev/null +++ b/src/orca/token-filters/marketcap.ts @@ -0,0 +1,14 @@ +import {fetchWhirlPool} from "../Pool"; +import {getCurrentPriceInUSD} from "../fetch-price"; +import { PublicKey } from "@solana/web3.js"; +import { connection } from "../../helpers/config"; +export async function getCurrentMarketCap(token_address:string):Promise { + const priceInUSD = await getCurrentPriceInUSD(token_address); + const tokenSupply: any = await connection.getTokenSupply( + new PublicKey(token_address) + ); + const marketCap: number = priceInUSD * tokenSupply.value.uiAmount; + return marketCap; +} + +//getCurrentMarketCap("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"); \ No newline at end of file diff --git a/src/orca/token-filters/pool-sol.ts b/src/orca/token-filters/pool-sol.ts new file mode 100644 index 0000000..6b6811d --- /dev/null +++ b/src/orca/token-filters/pool-sol.ts @@ -0,0 +1,18 @@ +import {fetchWhirlPool} from "../Pool" +import { wsol } from "../constants"; + +export async function getCurrentSolInPool(token_address:string):Promise { + const whirlPool:any = await fetchWhirlPool(token_address); + let solReserve:number = 0; + console.log(whirlPool.tokenVaultAInfo) + if(whirlPool.tokenVaultAInfo.mint.toBase58() === wsol){ + solReserve = Number(whirlPool.tokenVaultAInfo.amount)/Math.pow(10,9); + }else{ + solReserve = Number(whirlPool.tokenVaultBInfo.amount)/Math.pow(10,9); + } + console.log(solReserve); + return solReserve; +} + + +// getCurrentSolInPool("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"); \ No newline at end of file diff --git a/src/Trading_dev/memecoin_trading_strategies/stop-loss.js b/src/orca/token-filters/volume.ts similarity index 100% rename from src/Trading_dev/memecoin_trading_strategies/stop-loss.js rename to src/orca/token-filters/volume.ts diff --git a/src/Trading_dev/memecoin_trading_strategies/take-profit.js b/src/pumpfunsdk/README.md similarity index 100% rename from src/Trading_dev/memecoin_trading_strategies/take-profit.js rename to src/pumpfunsdk/README.md diff --git a/src/pumpfunsdk/pumpdotfun-sdk/example/util.js b/src/pumpfunsdk/pumpdotfun-sdk/example/util.ts similarity index 60% rename from src/pumpfunsdk/pumpdotfun-sdk/example/util.js rename to src/pumpfunsdk/pumpdotfun-sdk/example/util.ts index f890825..1f19276 100644 --- a/src/pumpfunsdk/pumpdotfun-sdk/example/util.js +++ b/src/pumpfunsdk/pumpdotfun-sdk/example/util.ts @@ -1,20 +1,23 @@ -const { bs58 } =require ("@coral-xyz/anchor/dist/cjs/utils/bytes"); -const { getAssociatedTokenAddressSync } =require ("@solana/spl-token"); -const { +import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; +import { getAssociatedTokenAddressSync } from "@solana/spl-token"; +import { Keypair, PublicKey, Connection, LAMPORTS_PER_SOL, -} =require ("@solana/web3.js"); -const { sha256 } =require ("js-sha256"); +} from "@solana/web3.js"; +import { sha256 } from "js-sha256"; -const fs =require ("fs"); +import fs from "fs"; - function getOrCreateKeypair(dir, keyName) { +export function getOrCreateKeypair(dir: string, keyName: string): Keypair { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); const authorityKey = dir + "/" + keyName + ".json"; if (fs.existsSync(authorityKey)) { - const data= JSON.parse(fs.readFileSync(authorityKey, "utf-8")); + const data: { + secretKey: string; + publicKey: string; + } = JSON.parse(fs.readFileSync(authorityKey, "utf-8")); return Keypair.fromSecretKey(bs58.decode(data.secretKey)); } else { const keypair = Keypair.generate(); @@ -30,7 +33,7 @@ const fs =require ("fs"); } } - function getKeypairByJsonPath(jsonPath) { +export function getKeypairByJsonPath(jsonPath:string) { try { const keypairJson = fs.readFileSync(jsonPath, "utf-8"); const data = JSON.parse(keypairJson); @@ -40,12 +43,11 @@ const fs =require ("fs"); console.log(e); } } - -async function printSOLBalance ( - connection, - pubKey, - info = "" -) { +export const printSOLBalance = async ( + connection: Connection, + pubKey: PublicKey, + info: string = "" +) => { const balance = await connection.getBalance(pubKey); console.log( `${info ? info + " " : ""}${pubKey.toBase58()}:`, @@ -54,12 +56,12 @@ async function printSOLBalance ( ); }; -async function getSPLBalance ( - connection, - mintAddress, - pubKey, - allowOffCurve = false -) { +export const getSPLBalance = async ( + connection: Connection, + mintAddress: PublicKey, + pubKey: PublicKey, + allowOffCurve: boolean = false +) => { try { let ata = getAssociatedTokenAddressSync(mintAddress, pubKey, allowOffCurve); const balance = await connection.getTokenAccountBalance(ata, "processed"); @@ -68,12 +70,12 @@ async function getSPLBalance ( return null; }; -async function printSPLBalance ( - connection, - mintAddress, - user, - info = "" -) { +export const printSPLBalance = async ( + connection: Connection, + mintAddress: PublicKey, + user: PublicKey, + info: string = "" +) => { const balance = await getSPLBalance(connection, mintAddress, user); if (balance === null) { console.log( @@ -85,26 +87,15 @@ async function printSPLBalance ( } }; - const baseToValue = (base, decimals) => { +export const baseToValue = (base: number, decimals: number): number => { return base * Math.pow(10, decimals); }; - const valueToBase = (value, decimal) => { +export const valueToBase = (value: number, decimals: number): number => { return value / Math.pow(10, decimals); }; //i.e. account:BondingCurve - function getDiscriminator(name) { +export function getDiscriminator(name: string) { return sha256.digest(name).slice(0, 8); -} - -module.exports = { - getOrCreateKeypair, - getKeypairByJsonPath, - printSOLBalance, - getSPLBalance, - printSPLBalance, - baseToValue, - valueToBase, - getDiscriminator, -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/index.js b/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/index.js deleted file mode 100644 index e368b5a..0000000 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/index.js +++ /dev/null @@ -1,4 +0,0 @@ -// pump-fun.json should be a valid JSON file -const IDL = require("./pump-fun.json"); -const { PumpFun } = require("./pump-fun"); -module.exports = { PumpFun, IDL }; \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/index.ts b/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/index.ts new file mode 100644 index 0000000..fe37e18 --- /dev/null +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/index.ts @@ -0,0 +1,3 @@ +// pump-fun.json should be a valid JSON file +export const IDL = require("./pump-fun.json"); +export * from "./pump-fun"; \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/pump-fun.js b/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/pump-fun.js deleted file mode 100644 index b9537af..0000000 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/pump-fun.js +++ /dev/null @@ -1,865 +0,0 @@ -// export type PumpFun = { -// address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; -// metadata: { -// name: "pump"; -// version: "0.1.0"; -// spec: "0.1.0"; -// }; -// instructions: [ -// { -// name: "initialize"; -// discriminator: [175, 175, 109, 31, 13, 152, 155, 237]; -// docs: ["Creates the global state."]; -// accounts: [ -// { -// name: "global"; -// writable: true; -// pda: { -// seeds: [ -// { -// kind: "const"; -// value: [103, 108, 111, 98, 97, 108]; -// } -// ]; -// }; -// }, -// { -// name: "user"; -// writable: true; -// signer: true; -// }, -// { -// name: "systemProgram"; -// address: "11111111111111111111111111111111"; -// } -// ]; -// args: []; -// }, -// { -// name: "setParams"; -// discriminator: [165, 31, 134, 53, 189, 180, 130, 255]; -// docs: ["Sets the global state parameters."]; -// accounts: [ -// { -// name: "global"; -// writable: true; -// pda: { -// seeds: [ -// { -// kind: "const"; -// value: [103, 108, 111, 98, 97, 108]; -// } -// ]; -// }; -// }, -// { -// name: "user"; -// writable: true; -// signer: true; -// }, -// { -// name: "systemProgram"; -// address: "11111111111111111111111111111111"; -// }, -// { -// name: "eventAuthority"; -// address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; -// }, -// { -// name: "program"; -// address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; -// } -// ]; -// args: [ -// { -// name: "feeRecipient"; -// type: "pubkey"; -// }, -// { -// name: "initialVirtualTokenReserves"; -// type: "u64"; -// }, -// { -// name: "initialVirtualSolReserves"; -// type: "u64"; -// }, -// { -// name: "initialRealTokenReserves"; -// type: "u64"; -// }, -// { -// name: "tokenTotalSupply"; -// type: "u64"; -// }, -// { -// name: "feeBasisPoints"; -// type: "u64"; -// } -// ]; -// }, -// { -// name: "create"; -// discriminator: [24, 30, 200, 40, 5, 28, 7, 119]; -// docs: ["Creates a new coin and bonding curve."]; -// accounts: [ -// { -// name: "mint"; -// writable: true; -// signer: true; -// }, -// { -// name: "mint_authority"; -// pda: { -// seeds: [ -// { -// kind: "const"; -// value: [ -// 109, -// 105, -// 110, -// 116, -// 45, -// 97, -// 117, -// 116, -// 104, -// 111, -// 114, -// 105, -// 116, -// 121 -// ]; -// } -// ]; -// }; -// }, -// { -// name: "bondingCurve"; -// writable: true; -// pda: { -// seeds: [ -// { -// kind: "const"; -// value: [ -// 98, -// 111, -// 110, -// 100, -// 105, -// 110, -// 103, -// 45, -// 99, -// 117, -// 114, -// 118, -// 101 -// ]; -// }, -// { -// kind: "account"; -// path: "mint"; -// } -// ]; -// }; -// }, -// { -// name: "associatedBondingCurve"; -// writable: true; -// signer: false; -// }, -// { -// name: "global"; -// writable: false; -// pda: { -// seeds: [ -// { -// kind: "const"; -// value: [103, 108, 111, 98, 97, 108]; -// } -// ]; -// }; -// }, -// { -// name: "mplTokenMetadata"; -// address: "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"; -// }, -// { -// name: "metadata"; -// writable: true; -// signer: false; -// }, -// { -// name: "user"; -// isMut: true; -// isSigner: true; -// }, -// { -// name: "systemProgram"; -// address: "11111111111111111111111111111111"; -// }, -// { -// name: "tokenProgram"; -// address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; -// }, -// { -// name: "associatedTokenProgram"; -// address: "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"; -// }, -// { -// name: "rent"; -// address: "SysvarRent111111111111111111111111111111111"; -// }, -// { -// name: "eventAuthority"; -// address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; -// }, -// { -// name: "program"; -// address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; -// } -// ]; -// args: [ -// { -// name: "name"; -// type: "string"; -// }, -// { -// name: "symbol"; -// type: "string"; -// }, -// { -// name: "uri"; -// type: "string"; -// } -// ]; -// }, -// { -// name: "buy"; -// discriminator: [102, 6, 61, 18, 1, 218, 235, 234]; -// docs: ["Buys tokens from a bonding curve."]; -// accounts: [ -// { -// name: "global"; -// pda: { -// seeds: [ -// { -// kind: "const"; -// value: [103, 108, 111, 98, 97, 108]; -// } -// ]; -// }; -// }, -// { -// name: "feeRecipient"; -// writable: true; -// signer: false; -// }, -// { -// name: "mint"; -// writable: false; -// signer: false; -// }, -// { -// name: "bondingCurve"; -// writable: true; -// pda: { -// seeds: [ -// { -// kind: "const"; -// value: [ -// 98, -// 111, -// 110, -// 100, -// 105, -// 110, -// 103, -// 45, -// 99, -// 117, -// 114, -// 118, -// 101 -// ]; -// }, -// { -// kind: "account"; -// path: "mint"; -// } -// ]; -// }; -// }, -// { -// name: "associatedBondingCurve"; -// writable: true; -// signer: false; -// }, -// { -// name: "associatedUser"; -// writable: true; -// signer: false; -// }, -// { -// name: "user"; -// writable: true; -// signer: true; -// }, -// { -// name: "systemProgram"; -// address: "11111111111111111111111111111111"; -// }, -// { -// name: "tokenProgram"; -// address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; -// }, -// { -// name: "rent"; -// address: "SysvarRent111111111111111111111111111111111"; -// }, -// { -// name: "eventAuthority"; -// address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; -// }, -// { -// name: "program"; -// address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; -// } -// ]; -// args: [ -// { -// name: "amount"; -// type: "u64"; -// }, -// { -// name: "maxSolCost"; -// type: "u64"; -// } -// ]; -// }, -// { -// name: "sell"; -// discriminator: [51, 230, 133, 164, 1, 127, 131, 173]; -// docs: ["Sells tokens into a bonding curve."]; -// accounts: [ -// { -// name: "global"; -// writable: false; -// pda: { -// seeds: [ -// { -// kind: "const"; -// value: [103, 108, 111, 98, 97, 108]; -// } -// ]; -// }; -// }, -// { -// name: "feeRecipient"; -// writable: true; -// signer: false; -// }, -// { -// name: "mint"; -// writable: false; -// signer: false; -// }, -// { -// name: "bondingCurve"; -// writable: true; -// pda: { -// seeds: [ -// { -// kind: "const"; -// value: [ -// 98, -// 111, -// 110, -// 100, -// 105, -// 110, -// 103, -// 45, -// 99, -// 117, -// 114, -// 118, -// 101 -// ]; -// }, -// { -// kind: "account"; -// path: "mint"; -// } -// ]; -// }; -// }, -// { -// name: "associatedBondingCurve"; -// writable: true; -// signer: false; -// }, -// { -// name: "associatedUser"; -// writable: true; -// signer: false; -// }, -// { -// name: "user"; -// writable: true; -// signer: true; -// }, -// { -// name: "systemProgram"; -// address: "11111111111111111111111111111111"; -// }, -// { -// name: "associatedTokenProgram"; -// address: "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"; -// }, -// { -// name: "tokenProgram"; -// address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; -// }, -// { -// name: "eventAuthority"; -// address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; -// }, -// { -// name: "program"; -// address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; -// } -// ]; -// args: [ -// { -// name: "amount"; -// type: "u64"; -// }, -// { -// name: "minSolOutput"; -// type: "u64"; -// } -// ]; -// }, -// { -// name: "withdraw"; -// discriminator: [183, 18, 70, 156, 148, 109, 161, 34]; -// docs: [ -// "Allows the admin to withdraw liquidity for a migration once the bonding curve completes" -// ]; -// accounts: [ -// { -// name: "global"; -// writable: false; -// pda: { -// seeds: [ -// { -// kind: "const"; -// value: [103, 108, 111, 98, 97, 108]; -// } -// ]; -// }; -// }, -// { -// name: "lastWithdraw"; -// writable: true; -// signer: false; -// }, -// { -// name: "mint"; -// writable: false; -// signer: false; -// }, -// { -// name: "bondingCurve"; -// writable: true; -// pda: { -// seeds: [ -// { -// kind: "const"; -// value: [ -// 98, -// 111, -// 110, -// 100, -// 105, -// 110, -// 103, -// 45, -// 99, -// 117, -// 114, -// 118, -// 101 -// ]; -// }, -// { -// kind: "account"; -// path: "mint"; -// } -// ]; -// }; -// }, -// { -// name: "associatedBondingCurve"; -// writable: true; -// signer: false; -// }, -// { -// name: "associatedUser"; -// writable: true; -// signer: false; -// }, -// { -// name: "user"; -// writable: true; -// signer: true; -// }, -// { -// name: "system_program"; -// address: "11111111111111111111111111111111"; -// }, -// { -// name: "tokenProgram"; -// address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; -// }, -// { -// name: "rent"; -// address: "SysvarRent111111111111111111111111111111111"; -// }, -// { -// name: "eventAuthority"; -// address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; -// }, -// { -// name: "program"; -// address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; -// } -// ]; -// args: []; -// } -// ]; -// accounts: [ -// { -// name: "bondingCurve"; -// discriminator: [23, 183, 248, 55, 96, 216, 172, 96]; -// }, -// { -// name: "global"; -// discriminator: [167, 232, 232, 177, 200, 108, 114, 127]; -// } -// ]; -// events: [ -// { -// name: "createEvent"; -// discriminator: [27, 114, 169, 77, 222, 235, 99, 118]; -// }, -// { -// name: "tradeEvent"; -// discriminator: [189, 219, 127, 211, 78, 230, 97, 238]; -// }, -// { -// name: "completeEvent"; -// discriminator: [95, 114, 97, 156, 212, 46, 152, 8]; -// }, -// { -// name: "setParamsEvent"; -// discriminator: [223, 195, 159, 246, 62, 48, 143, 131]; -// } -// ]; -// types: [ -// { -// name: "global"; -// type: { -// kind: "struct"; -// fields: [ -// { -// name: "initialized"; -// type: "bool"; -// }, -// { -// name: "authority"; -// type: "pubkey"; -// }, -// { -// name: "feeRecipient"; -// type: "pubkey"; -// }, -// { -// name: "initialVirtualTokenReserves"; -// type: "u64"; -// }, -// { -// name: "initialVirtualSolReserves"; -// type: "u64"; -// }, -// { -// name: "initialRealTokenReserves"; -// type: "u64"; -// }, -// { -// name: "tokenTotalSupply"; -// type: "u64"; -// }, -// { -// name: "feeBasisPoints"; -// type: "u64"; -// } -// ]; -// }; -// }, -// { -// name: "lastWithdraw"; -// type: { -// kind: "struct"; -// fields: [ -// { -// name: "lastWithdrawTimestamp"; -// type: "i64"; -// } -// ]; -// }; -// }, -// { -// name: "bondingCurve"; -// type: { -// kind: "struct"; -// fields: [ -// { -// name: "virtualTokenReserves"; -// type: "u64"; -// }, -// { -// name: "virtualSolReserves"; -// type: "u64"; -// }, -// { -// name: "realTokenReserves"; -// type: "u64"; -// }, -// { -// name: "realSolReserves"; -// type: "u64"; -// }, -// { -// name: "tokenTotalSupply"; -// type: "u64"; -// }, -// { -// name: "complete"; -// type: "bool"; -// } -// ]; -// }; -// }, -// { -// name: "createEvent"; -// type: { -// kind: "struct"; -// fields: [ -// { -// name: "name"; -// type: "string"; -// index: false; -// }, -// { -// name: "symbol"; -// type: "string"; -// index: false; -// }, -// { -// name: "uri"; -// type: "string"; -// index: false; -// }, -// { -// name: "mint"; -// type: "pubkey"; -// index: false; -// }, -// { -// name: "bondingCurve"; -// type: "pubkey"; -// index: false; -// }, -// { -// name: "user"; -// type: "pubkey"; -// index: false; -// } -// ]; -// }; -// }, -// { -// name: "tradeEvent"; -// type: { -// kind: "struct"; -// fields: [ -// { -// name: "mint"; -// type: "pubkey"; -// index: false; -// }, -// { -// name: "solAmount"; -// type: "u64"; -// index: false; -// }, -// { -// name: "tokenAmount"; -// type: "u64"; -// index: false; -// }, -// { -// name: "isBuy"; -// type: "bool"; -// index: false; -// }, -// { -// name: "user"; -// type: "pubkey"; -// index: false; -// }, -// { -// name: "timestamp"; -// type: "i64"; -// index: false; -// }, -// { -// name: "virtualSolReserves"; -// type: "u64"; -// index: false; -// }, -// { -// name: "virtualTokenReserves"; -// type: "u64"; -// index: false; -// }, -// { -// name: "realSolReserves"; -// type: "u64"; -// index: false; -// }, -// { -// name: "realTokenReserves"; -// type: "u64"; -// index: false; -// } -// ]; -// }; -// }, -// { -// name: "completeEvent"; -// type: { -// kind: "struct"; -// fields: [ -// { -// name: "user"; -// type: "pubkey"; -// index: false; -// }, -// { -// name: "mint"; -// type: "pubkey"; -// index: false; -// }, -// { -// name: "bondingCurve"; -// type: "pubkey"; -// index: false; -// }, -// { -// name: "timestamp"; -// type: "i64"; -// index: false; -// } -// ]; -// }; -// }, -// { -// name: "setParamsEvent"; -// type: { -// kind: "struct"; -// fields: [ -// { -// name: "feeRecipient"; -// type: "pubkey"; -// index: false; -// }, -// { -// name: "initialVirtualTokenReserves"; -// type: "u64"; -// index: false; -// }, -// { -// name: "initialVirtualSolReserves"; -// type: "u64"; -// index: false; -// }, -// { -// name: "initialRealTokenReserves"; -// type: "u64"; -// index: false; -// }, -// { -// name: "tokenTotalSupply"; -// type: "u64"; -// index: false; -// }, -// { -// name: "feeBasisPoints"; -// type: "u64"; -// index: false; -// } -// ]; -// }; -// } -// ]; -// errors: [ -// { -// code: 6000; -// name: "NotAuthorized"; -// msg: "The given account is not authorized to execute this instruction."; -// }, -// { -// code: 6001; -// name: "AlreadyInitialized"; -// msg: "The program is already initialized."; -// }, -// { -// code: 6002; -// name: "TooMuchSolRequired"; -// msg: "slippage: Too much SOL required to buy the given amount of tokens."; -// }, -// { -// code: 6003; -// name: "TooLittleSolReceived"; -// msg: "slippage: Too little SOL received to sell the given amount of tokens."; -// }, -// { -// code: 6004; -// name: "MintDoesNotMatchBondingCurve"; -// msg: "The mint does not match the bonding curve."; -// }, -// { -// code: 6005; -// name: "BondingCurveComplete"; -// msg: "The bonding curve has completed and liquidity migrated to raydium."; -// }, -// { -// code: 6006; -// name: "BondingCurveNotComplete"; -// msg: "The bonding curve has not completed."; -// }, -// { -// code: 6007; -// name: "NotInitialized"; -// msg: "The program is not initialized."; -// }, -// { -// code: 6008; -// name: "WithdrawTooFrequent"; -// msg: "Withdraw too frequent"; -// } -// ]; -// }; \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/pump-fun.ts b/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/pump-fun.ts new file mode 100644 index 0000000..99cc93e --- /dev/null +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/IDL/pump-fun.ts @@ -0,0 +1,865 @@ +export type PumpFun = { + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + metadata: { + name: "pump"; + version: "0.1.0"; + spec: "0.1.0"; + }; + instructions: [ + { + name: "initialize"; + discriminator: [175, 175, 109, 31, 13, 152, 155, 237]; + docs: ["Creates the global state."]; + accounts: [ + { + name: "global"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "user"; + writable: true; + signer: true; + }, + { + name: "systemProgram"; + address: "11111111111111111111111111111111"; + } + ]; + args: []; + }, + { + name: "setParams"; + discriminator: [165, 31, 134, 53, 189, 180, 130, 255]; + docs: ["Sets the global state parameters."]; + accounts: [ + { + name: "global"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "user"; + writable: true; + signer: true; + }, + { + name: "systemProgram"; + address: "11111111111111111111111111111111"; + }, + { + name: "eventAuthority"; + address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; + }, + { + name: "program"; + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + } + ]; + args: [ + { + name: "feeRecipient"; + type: "pubkey"; + }, + { + name: "initialVirtualTokenReserves"; + type: "u64"; + }, + { + name: "initialVirtualSolReserves"; + type: "u64"; + }, + { + name: "initialRealTokenReserves"; + type: "u64"; + }, + { + name: "tokenTotalSupply"; + type: "u64"; + }, + { + name: "feeBasisPoints"; + type: "u64"; + } + ]; + }, + { + name: "create"; + discriminator: [24, 30, 200, 40, 5, 28, 7, 119]; + docs: ["Creates a new coin and bonding curve."]; + accounts: [ + { + name: "mint"; + writable: true; + signer: true; + }, + { + name: "mint_authority"; + pda: { + seeds: [ + { + kind: "const"; + value: [ + 109, + 105, + 110, + 116, + 45, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ]; + } + ]; + }; + }, + { + name: "bondingCurve"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ]; + }, + { + kind: "account"; + path: "mint"; + } + ]; + }; + }, + { + name: "associatedBondingCurve"; + writable: true; + signer: false; + }, + { + name: "global"; + writable: false; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "mplTokenMetadata"; + address: "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"; + }, + { + name: "metadata"; + writable: true; + signer: false; + }, + { + name: "user"; + isMut: true; + isSigner: true; + }, + { + name: "systemProgram"; + address: "11111111111111111111111111111111"; + }, + { + name: "tokenProgram"; + address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; + }, + { + name: "associatedTokenProgram"; + address: "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"; + }, + { + name: "rent"; + address: "SysvarRent111111111111111111111111111111111"; + }, + { + name: "eventAuthority"; + address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; + }, + { + name: "program"; + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + } + ]; + args: [ + { + name: "name"; + type: "string"; + }, + { + name: "symbol"; + type: "string"; + }, + { + name: "uri"; + type: "string"; + } + ]; + }, + { + name: "buy"; + discriminator: [102, 6, 61, 18, 1, 218, 235, 234]; + docs: ["Buys tokens from a bonding curve."]; + accounts: [ + { + name: "global"; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "feeRecipient"; + writable: true; + signer: false; + }, + { + name: "mint"; + writable: false; + signer: false; + }, + { + name: "bondingCurve"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ]; + }, + { + kind: "account"; + path: "mint"; + } + ]; + }; + }, + { + name: "associatedBondingCurve"; + writable: true; + signer: false; + }, + { + name: "associatedUser"; + writable: true; + signer: false; + }, + { + name: "user"; + writable: true; + signer: true; + }, + { + name: "systemProgram"; + address: "11111111111111111111111111111111"; + }, + { + name: "tokenProgram"; + address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; + }, + { + name: "rent"; + address: "SysvarRent111111111111111111111111111111111"; + }, + { + name: "eventAuthority"; + address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; + }, + { + name: "program"; + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + } + ]; + args: [ + { + name: "amount"; + type: "u64"; + }, + { + name: "maxSolCost"; + type: "u64"; + } + ]; + }, + { + name: "sell"; + discriminator: [51, 230, 133, 164, 1, 127, 131, 173]; + docs: ["Sells tokens into a bonding curve."]; + accounts: [ + { + name: "global"; + writable: false; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "feeRecipient"; + writable: true; + signer: false; + }, + { + name: "mint"; + writable: false; + signer: false; + }, + { + name: "bondingCurve"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ]; + }, + { + kind: "account"; + path: "mint"; + } + ]; + }; + }, + { + name: "associatedBondingCurve"; + writable: true; + signer: false; + }, + { + name: "associatedUser"; + writable: true; + signer: false; + }, + { + name: "user"; + writable: true; + signer: true; + }, + { + name: "systemProgram"; + address: "11111111111111111111111111111111"; + }, + { + name: "associatedTokenProgram"; + address: "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"; + }, + { + name: "tokenProgram"; + address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; + }, + { + name: "eventAuthority"; + address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; + }, + { + name: "program"; + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + } + ]; + args: [ + { + name: "amount"; + type: "u64"; + }, + { + name: "minSolOutput"; + type: "u64"; + } + ]; + }, + { + name: "withdraw"; + discriminator: [183, 18, 70, 156, 148, 109, 161, 34]; + docs: [ + "Allows the admin to withdraw liquidity for a migration once the bonding curve completes" + ]; + accounts: [ + { + name: "global"; + writable: false; + pda: { + seeds: [ + { + kind: "const"; + value: [103, 108, 111, 98, 97, 108]; + } + ]; + }; + }, + { + name: "lastWithdraw"; + writable: true; + signer: false; + }, + { + name: "mint"; + writable: false; + signer: false; + }, + { + name: "bondingCurve"; + writable: true; + pda: { + seeds: [ + { + kind: "const"; + value: [ + 98, + 111, + 110, + 100, + 105, + 110, + 103, + 45, + 99, + 117, + 114, + 118, + 101 + ]; + }, + { + kind: "account"; + path: "mint"; + } + ]; + }; + }, + { + name: "associatedBondingCurve"; + writable: true; + signer: false; + }, + { + name: "associatedUser"; + writable: true; + signer: false; + }, + { + name: "user"; + writable: true; + signer: true; + }, + { + name: "system_program"; + address: "11111111111111111111111111111111"; + }, + { + name: "tokenProgram"; + address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; + }, + { + name: "rent"; + address: "SysvarRent111111111111111111111111111111111"; + }, + { + name: "eventAuthority"; + address: "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1"; + }, + { + name: "program"; + address: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + } + ]; + args: []; + } + ]; + accounts: [ + { + name: "bondingCurve"; + discriminator: [23, 183, 248, 55, 96, 216, 172, 96]; + }, + { + name: "global"; + discriminator: [167, 232, 232, 177, 200, 108, 114, 127]; + } + ]; + events: [ + { + name: "createEvent"; + discriminator: [27, 114, 169, 77, 222, 235, 99, 118]; + }, + { + name: "tradeEvent"; + discriminator: [189, 219, 127, 211, 78, 230, 97, 238]; + }, + { + name: "completeEvent"; + discriminator: [95, 114, 97, 156, 212, 46, 152, 8]; + }, + { + name: "setParamsEvent"; + discriminator: [223, 195, 159, 246, 62, 48, 143, 131]; + } + ]; + types: [ + { + name: "global"; + type: { + kind: "struct"; + fields: [ + { + name: "initialized"; + type: "bool"; + }, + { + name: "authority"; + type: "pubkey"; + }, + { + name: "feeRecipient"; + type: "pubkey"; + }, + { + name: "initialVirtualTokenReserves"; + type: "u64"; + }, + { + name: "initialVirtualSolReserves"; + type: "u64"; + }, + { + name: "initialRealTokenReserves"; + type: "u64"; + }, + { + name: "tokenTotalSupply"; + type: "u64"; + }, + { + name: "feeBasisPoints"; + type: "u64"; + } + ]; + }; + }, + { + name: "lastWithdraw"; + type: { + kind: "struct"; + fields: [ + { + name: "lastWithdrawTimestamp"; + type: "i64"; + } + ]; + }; + }, + { + name: "bondingCurve"; + type: { + kind: "struct"; + fields: [ + { + name: "virtualTokenReserves"; + type: "u64"; + }, + { + name: "virtualSolReserves"; + type: "u64"; + }, + { + name: "realTokenReserves"; + type: "u64"; + }, + { + name: "realSolReserves"; + type: "u64"; + }, + { + name: "tokenTotalSupply"; + type: "u64"; + }, + { + name: "complete"; + type: "bool"; + } + ]; + }; + }, + { + name: "createEvent"; + type: { + kind: "struct"; + fields: [ + { + name: "name"; + type: "string"; + index: false; + }, + { + name: "symbol"; + type: "string"; + index: false; + }, + { + name: "uri"; + type: "string"; + index: false; + }, + { + name: "mint"; + type: "pubkey"; + index: false; + }, + { + name: "bondingCurve"; + type: "pubkey"; + index: false; + }, + { + name: "user"; + type: "pubkey"; + index: false; + } + ]; + }; + }, + { + name: "tradeEvent"; + type: { + kind: "struct"; + fields: [ + { + name: "mint"; + type: "pubkey"; + index: false; + }, + { + name: "solAmount"; + type: "u64"; + index: false; + }, + { + name: "tokenAmount"; + type: "u64"; + index: false; + }, + { + name: "isBuy"; + type: "bool"; + index: false; + }, + { + name: "user"; + type: "pubkey"; + index: false; + }, + { + name: "timestamp"; + type: "i64"; + index: false; + }, + { + name: "virtualSolReserves"; + type: "u64"; + index: false; + }, + { + name: "virtualTokenReserves"; + type: "u64"; + index: false; + }, + { + name: "realSolReserves"; + type: "u64"; + index: false; + }, + { + name: "realTokenReserves"; + type: "u64"; + index: false; + } + ]; + }; + }, + { + name: "completeEvent"; + type: { + kind: "struct"; + fields: [ + { + name: "user"; + type: "pubkey"; + index: false; + }, + { + name: "mint"; + type: "pubkey"; + index: false; + }, + { + name: "bondingCurve"; + type: "pubkey"; + index: false; + }, + { + name: "timestamp"; + type: "i64"; + index: false; + } + ]; + }; + }, + { + name: "setParamsEvent"; + type: { + kind: "struct"; + fields: [ + { + name: "feeRecipient"; + type: "pubkey"; + index: false; + }, + { + name: "initialVirtualTokenReserves"; + type: "u64"; + index: false; + }, + { + name: "initialVirtualSolReserves"; + type: "u64"; + index: false; + }, + { + name: "initialRealTokenReserves"; + type: "u64"; + index: false; + }, + { + name: "tokenTotalSupply"; + type: "u64"; + index: false; + }, + { + name: "feeBasisPoints"; + type: "u64"; + index: false; + } + ]; + }; + } + ]; + errors: [ + { + code: 6000; + name: "NotAuthorized"; + msg: "The given account is not authorized to execute this instruction."; + }, + { + code: 6001; + name: "AlreadyInitialized"; + msg: "The program is already initialized."; + }, + { + code: 6002; + name: "TooMuchSolRequired"; + msg: "slippage: Too much SOL required to buy the given amount of tokens."; + }, + { + code: 6003; + name: "TooLittleSolReceived"; + msg: "slippage: Too little SOL received to sell the given amount of tokens."; + }, + { + code: 6004; + name: "MintDoesNotMatchBondingCurve"; + msg: "The mint does not match the bonding curve."; + }, + { + code: 6005; + name: "BondingCurveComplete"; + msg: "The bonding curve has completed and liquidity migrated to raydium."; + }, + { + code: 6006; + name: "BondingCurveNotComplete"; + msg: "The bonding curve has not completed."; + }, + { + code: 6007; + name: "NotInitialized"; + msg: "The program is not initialized."; + }, + { + code: 6008; + name: "WithdrawTooFrequent"; + msg: "Withdraw too frequent"; + } + ]; +}; \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/amm.ts b/src/pumpfunsdk/pumpdotfun-sdk/src/amm.ts new file mode 100644 index 0000000..f48889a --- /dev/null +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/amm.ts @@ -0,0 +1,88 @@ +import { BondingCurveAccount } from "./bondingCurveAccount"; +import { GlobalAccount } from "./globalAccount"; + +export type BuyResult = { + token_amount: bigint; + sol_amount: bigint; +}; + +export type SellResult = { + token_amount: bigint; + sol_amount: bigint; +}; + +export class AMM { + constructor( + public virtualSolReserves: bigint, + public virtualTokenReserves: bigint, + public realSolReserves: bigint, + public realTokenReserves: bigint, + public initialVirtualTokenReserves: bigint + ) {} + + static fromGlobalAccount(global: GlobalAccount): AMM { + return new AMM( + global.initialVirtualSolReserves, + global.initialVirtualTokenReserves, + 0n, + global.initialRealTokenReserves, + global.initialVirtualTokenReserves + ); + } + + static fromBondingCurveAccount(bonding_curve: BondingCurveAccount, initialVirtualTokenReserves: bigint): AMM { + return new AMM( + bonding_curve.virtualSolReserves, + bonding_curve.virtualTokenReserves, + bonding_curve.realSolReserves, + bonding_curve.realTokenReserves, + initialVirtualTokenReserves + ); + } + + getBuyPrice(tokens: bigint): bigint { + const product_of_reserves = this.virtualSolReserves * this.virtualTokenReserves; + const new_virtual_token_reserves = this.virtualTokenReserves - tokens; + const new_virtual_sol_reserves = product_of_reserves / new_virtual_token_reserves + 1n; + const amount_needed = new_virtual_sol_reserves > this.virtualSolReserves ? new_virtual_sol_reserves - this.virtualSolReserves : 0n; + return amount_needed > 0n ? amount_needed : 0n; + } + + applyBuy(token_amount: bigint): BuyResult { + const final_token_amount = token_amount > this.realTokenReserves ? this.realTokenReserves : token_amount; + const sol_amount = this.getBuyPrice(final_token_amount); + + this.virtualTokenReserves = this.virtualTokenReserves - final_token_amount; + this.realTokenReserves = this.realTokenReserves - final_token_amount; + + this.virtualSolReserves = this.virtualSolReserves + sol_amount; + this.realSolReserves = this.realSolReserves + sol_amount; + + return { + token_amount: final_token_amount, + sol_amount: sol_amount + } + } + + applySell(token_amount: bigint): SellResult { + this.virtualTokenReserves = this.virtualTokenReserves + token_amount; + this.realTokenReserves = this.realTokenReserves + token_amount; + + const sell_price = this.getSellPrice(token_amount); + + this.virtualSolReserves = this.virtualSolReserves - sell_price; + this.realSolReserves = this.realSolReserves - sell_price; + + return { + token_amount: token_amount, + sol_amount: sell_price + } + } + + getSellPrice(tokens: bigint): bigint { + const scaling_factor = this.initialVirtualTokenReserves; + const token_sell_proportion = (tokens * scaling_factor) / this.virtualTokenReserves; + const sol_received = (this.virtualSolReserves * token_sell_proportion) / scaling_factor; + return sol_received < this.realSolReserves ? sol_received : this.realSolReserves; + } +} \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/bondingCurveAccount.ts b/src/pumpfunsdk/pumpdotfun-sdk/src/bondingCurveAccount.ts new file mode 100644 index 0000000..c4d25fd --- /dev/null +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/bondingCurveAccount.ts @@ -0,0 +1,134 @@ +import { struct, bool, u64, Layout } from "@coral-xyz/borsh"; + +export class BondingCurveAccount { + public discriminator: bigint; + public virtualTokenReserves: bigint; + public virtualSolReserves: bigint; + public realTokenReserves: bigint; + public realSolReserves: bigint; + public tokenTotalSupply: bigint; + public complete: boolean; + + constructor( + discriminator: bigint, + virtualTokenReserves: bigint, + virtualSolReserves: bigint, + realTokenReserves: bigint, + realSolReserves: bigint, + tokenTotalSupply: bigint, + complete: boolean + ) { + this.discriminator = discriminator; + this.virtualTokenReserves = virtualTokenReserves; + this.virtualSolReserves = virtualSolReserves; + this.realTokenReserves = realTokenReserves; + this.realSolReserves = realSolReserves; + this.tokenTotalSupply = tokenTotalSupply; + this.complete = complete; + } + + getBuyPrice(amount: bigint): bigint { + if (this.complete) { + throw new Error("Curve is complete"); + } + + if (amount <= 0n) { + return 0n; + } + + // Calculate the product of virtual reserves + let n = this.virtualSolReserves * this.virtualTokenReserves; + + // Calculate the new virtual sol reserves after the purchase + let i = this.virtualSolReserves + amount; + + // Calculate the new virtual token reserves after the purchase + let r = n / i + 1n; + + // Calculate the amount of tokens to be purchased + let s = this.virtualTokenReserves - r; + + // Return the minimum of the calculated tokens and real token reserves + return s < this.realTokenReserves ? s : this.realTokenReserves; + } + + getSellPrice(amount: bigint, feeBasisPoints: bigint): bigint { + if (this.complete) { + throw new Error("Curve is complete"); + } + + if (amount <= 0n) { + return 0n; + } + + // Calculate the proportional amount of virtual sol reserves to be received + let n = + (amount * this.virtualSolReserves) / (this.virtualTokenReserves + amount); + + // Calculate the fee amount in the same units + let a = (n * feeBasisPoints) / 10000n; + + // Return the net amount after deducting the fee + return n - a; + } + + getMarketCapSOL(): bigint { + if (this.virtualTokenReserves === 0n) { + return 0n; + } + + return ( + (this.tokenTotalSupply * this.virtualSolReserves) / + this.virtualTokenReserves + ); + } + + getFinalMarketCapSOL(feeBasisPoints: bigint): bigint { + let totalSellValue = this.getBuyOutPrice( + this.realTokenReserves, + feeBasisPoints + ); + let totalVirtualValue = this.virtualSolReserves + totalSellValue; + let totalVirtualTokens = this.virtualTokenReserves - this.realTokenReserves; + + if (totalVirtualTokens === 0n) { + return 0n; + } + + return (this.tokenTotalSupply * totalVirtualValue) / totalVirtualTokens; + } + + getBuyOutPrice(amount: bigint, feeBasisPoints: bigint): bigint { + let solTokens = + amount < this.realSolReserves ? this.realSolReserves : amount; + let totalSellValue = + (solTokens * this.virtualSolReserves) / + (this.virtualTokenReserves - solTokens) + + 1n; + let fee = (totalSellValue * feeBasisPoints) / 10000n; + return totalSellValue + fee; + } + + public static fromBuffer(buffer: Buffer): BondingCurveAccount { + const structure: Layout = struct([ + u64("discriminator"), + u64("virtualTokenReserves"), + u64("virtualSolReserves"), + u64("realTokenReserves"), + u64("realSolReserves"), + u64("tokenTotalSupply"), + bool("complete"), + ]); + + let value = structure.decode(buffer); + return new BondingCurveAccount( + BigInt(value.discriminator), + BigInt(value.virtualTokenReserves), + BigInt(value.virtualSolReserves), + BigInt(value.realTokenReserves), + BigInt(value.realSolReserves), + BigInt(value.tokenTotalSupply), + value.complete + ); + } +} \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/buy.js b/src/pumpfunsdk/pumpdotfun-sdk/src/buy.ts similarity index 79% rename from src/pumpfunsdk/pumpdotfun-sdk/src/buy.js rename to src/pumpfunsdk/pumpdotfun-sdk/src/buy.ts index b563eaf..476c9cc 100644 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/buy.js +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/buy.ts @@ -1,7 +1,7 @@ -const { PublicKey } = require("@solana/web3.js"); -const {buy} = require("./tools"); -const { program } = require("commander"); -let token_address = null, sol = null; +import { PublicKey } from "@solana/web3.js"; +import {buy} from "./tools"; +import { program } from "commander"; +let token_address:any = null, sol = null; program .option("--token_address ", "Specify the token address") .option("--sol ", "Specify the number of SOL") diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/createAndBuy.js b/src/pumpfunsdk/pumpdotfun-sdk/src/createAndBuy.ts similarity index 87% rename from src/pumpfunsdk/pumpdotfun-sdk/src/createAndBuy.js rename to src/pumpfunsdk/pumpdotfun-sdk/src/createAndBuy.ts index 2086fbd..c8ea09a 100644 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/createAndBuy.js +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/createAndBuy.ts @@ -1,9 +1,10 @@ -const {createAndBuy} = require("./tools"); +import {createAndBuy} from "./tools"; // command line tool -const {program} = require("commander"); -const fs = require("fs"); +import {program} from "commander"; +import fs from "fs"; -let sol = null, mintKeypair = null, name = null, symbol = null, description = null, telegram = null, twitter = null, website = null, file = null; +let sol:any = null, mintKeypair:any = null, name:any = null, symbol:any = null, +description:any = null, telegram:any = null, twitter:any = null, website:any = null, file:any = null; program.option("--pathToMintKeypair ", "Specify the path to your own mint keypair") .option("--sol ", "Specify the number of SOL you want to buy") .option("--name ", "Specify the token name") diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/events.ts b/src/pumpfunsdk/pumpdotfun-sdk/src/events.ts new file mode 100644 index 0000000..b2c34c3 --- /dev/null +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/events.ts @@ -0,0 +1,53 @@ +import { PublicKey } from "@solana/web3.js"; +import { + CompleteEvent, + CreateEvent, + SetParamsEvent, + TradeEvent, +} from "./types"; + +export function toCreateEvent(event: CreateEvent): CreateEvent { + return { + name: event.name, + symbol: event.symbol, + uri: event.uri, + mint: new PublicKey(event.mint), + bondingCurve: new PublicKey(event.bondingCurve), + user: new PublicKey(event.user), + }; +} + +export function toCompleteEvent(event: CompleteEvent): CompleteEvent { + return { + user: new PublicKey(event.user), + mint: new PublicKey(event.mint), + bondingCurve: new PublicKey(event.bondingCurve), + timestamp: event.timestamp, + }; +} + +export function toTradeEvent(event: TradeEvent): TradeEvent { + return { + mint: new PublicKey(event.mint), + solAmount: BigInt(event.solAmount), + tokenAmount: BigInt(event.tokenAmount), + isBuy: event.isBuy, + user: new PublicKey(event.user), + timestamp: Number(event.timestamp), + virtualSolReserves: BigInt(event.virtualSolReserves), + virtualTokenReserves: BigInt(event.virtualTokenReserves), + realSolReserves: BigInt(event.realSolReserves), + realTokenReserves: BigInt(event.realTokenReserves), + }; +} + +export function toSetParamsEvent(event: SetParamsEvent): SetParamsEvent { + return { + feeRecipient: new PublicKey(event.feeRecipient), + initialVirtualTokenReserves: BigInt(event.initialVirtualTokenReserves), + initialVirtualSolReserves: BigInt(event.initialVirtualSolReserves), + initialRealTokenReserves: BigInt(event.initialRealTokenReserves), + tokenTotalSupply: BigInt(event.tokenTotalSupply), + feeBasisPoints: BigInt(event.feeBasisPoints), + }; +} \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/globalAccount.ts b/src/pumpfunsdk/pumpdotfun-sdk/src/globalAccount.ts new file mode 100644 index 0000000..5335fe7 --- /dev/null +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/globalAccount.ts @@ -0,0 +1,77 @@ +import { PublicKey } from "@solana/web3.js"; +import { struct, bool, u64, publicKey, Layout } from "@coral-xyz/borsh"; + +export class GlobalAccount { + public discriminator: bigint; + public initialized: boolean = false; + public authority: PublicKey; + public feeRecipient: PublicKey; + public initialVirtualTokenReserves: bigint; + public initialVirtualSolReserves: bigint; + public initialRealTokenReserves: bigint; + public tokenTotalSupply: bigint; + public feeBasisPoints: bigint; + + constructor( + discriminator: bigint, + initialized: boolean, + authority: PublicKey, + feeRecipient: PublicKey, + initialVirtualTokenReserves: bigint, + initialVirtualSolReserves: bigint, + initialRealTokenReserves: bigint, + tokenTotalSupply: bigint, + feeBasisPoints: bigint + ) { + this.discriminator = discriminator; + this.initialized = initialized; + this.authority = authority; + this.feeRecipient = feeRecipient; + this.initialVirtualTokenReserves = initialVirtualTokenReserves; + this.initialVirtualSolReserves = initialVirtualSolReserves; + this.initialRealTokenReserves = initialRealTokenReserves; + this.tokenTotalSupply = tokenTotalSupply; + this.feeBasisPoints = feeBasisPoints; + } + + getInitialBuyPrice(amount: bigint): bigint { + if (amount <= 0n) { + return 0n; + } + + let n = this.initialVirtualSolReserves * this.initialVirtualTokenReserves; + let i = this.initialVirtualSolReserves + amount; + let r = n / i + 1n; + let s = this.initialVirtualTokenReserves - r; + return s < this.initialRealTokenReserves + ? s + : this.initialRealTokenReserves; + } + + public static fromBuffer(buffer: Buffer): GlobalAccount { + const structure: Layout = struct([ + u64("discriminator"), + bool("initialized"), + publicKey("authority"), + publicKey("feeRecipient"), + u64("initialVirtualTokenReserves"), + u64("initialVirtualSolReserves"), + u64("initialRealTokenReserves"), + u64("tokenTotalSupply"), + u64("feeBasisPoints"), + ]); + + let value = structure.decode(buffer); + return new GlobalAccount( + BigInt(value.discriminator), + value.initialized, + value.authority, + value.feeRecipient, + BigInt(value.initialVirtualTokenReserves), + BigInt(value.initialVirtualSolReserves), + BigInt(value.initialRealTokenReserves), + BigInt(value.tokenTotalSupply), + BigInt(value.feeBasisPoints) + ); + } +} \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/index.js b/src/pumpfunsdk/pumpdotfun-sdk/src/index.js deleted file mode 100644 index bbab489..0000000 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/index.js +++ /dev/null @@ -1,8 +0,0 @@ -// export * from './pumpfun' -// export * from './util' -// export * from './types' -// export * from './events' -// export * from './globalAccount' -// export * from './bondingCurveAccount' -// export * from './amm' - diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/index.ts b/src/pumpfunsdk/pumpdotfun-sdk/src/index.ts new file mode 100644 index 0000000..385e336 --- /dev/null +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/index.ts @@ -0,0 +1,8 @@ +export * from './pumpfun' +export * from './util' +export * from './types' +export * from './events' +export * from './globalAccount' +export * from './bondingCurveAccount' +export * from './amm' + diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/pump-events-listener/listeners.js b/src/pumpfunsdk/pumpdotfun-sdk/src/pump-events-listener/listeners.ts similarity index 67% rename from src/pumpfunsdk/pumpdotfun-sdk/src/pump-events-listener/listeners.js rename to src/pumpfunsdk/pumpdotfun-sdk/src/pump-events-listener/listeners.ts index 0c14462..0f86629 100644 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/pump-events-listener/listeners.js +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/pump-events-listener/listeners.ts @@ -1,30 +1,30 @@ -const {connection} = require("../../../../helpers/config"); -const { Keypair, Connection } = require("@solana/web3.js"); -const {PumpFunSDK} =require ("pumpdotfun-sdk"); -const { AnchorProvider } = require ("@coral-xyz/anchor"); +import {connection} from "../../../../helpers/config"; +import { Keypair, Connection } from "@solana/web3.js"; +import {PumpFunSDK} from "pumpdotfun-sdk"; +import { AnchorProvider } from "@coral-xyz/anchor"; -function getProvider(){ - const wallet = Keypair.generate(); +export function getProvider(){ + const wallet:any = Keypair.generate(); const provider = new AnchorProvider(connection, wallet, { commitment: "finalized", }); return provider; } -async function subscribeToCompleteBondingCurveEvent(sdk){ +export async function subscribeToCompleteBondingCurveEvent(sdk: PumpFunSDK){ const completeEventId = sdk.addEventListener("completeEvent", (event, slot, signature) => { console.log("completeEvent", event, slot, signature); }); console.log("Subscribed to completeEvent with ID:", completeEventId); } -async function subscribeToCreatePumpTokenEvent(sdk){ +export async function subscribeToCreatePumpTokenEvent(sdk: PumpFunSDK){ const createEventId = sdk.addEventListener("createEvent", (event, slot, signature) => { console.log("createEvent", event, slot, signature); console.log("mint pubkey", event.mint.toBase58()) }); console.log("Subscribed to createEvent with ID:", createEventId); } -async function subscribeToTradeEvent(sdk){ +export async function subscribeToTradeEvent(sdk: PumpFunSDK){ const tradeEventId = sdk.addEventListener("tradeEvent", (event, slot, signature) => { console.log("tradeEvent", event, slot, signature); }); @@ -42,5 +42,3 @@ async function main(){ } } main(); - -module.exports = {subscribeToCompleteBondingCurveEvent, subscribeToCreatePumpTokenEvent, subscribeToTradeEvent, getProvider}; \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/pumpfun.js b/src/pumpfunsdk/pumpdotfun-sdk/src/pumpfun.ts similarity index 68% rename from src/pumpfunsdk/pumpdotfun-sdk/src/pumpfun.js rename to src/pumpfunsdk/pumpdotfun-sdk/src/pumpfun.ts index b4e7e07..47a80e9 100644 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/pumpfun.js +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/pumpfun.ts @@ -1,121 +1,122 @@ -const { +import { Commitment, Connection, Finality, Keypair, PublicKey, Transaction, -} =require ("@solana/web3.js"); -const { Program, Provider } =require ("@coral-xyz/anchor"); -const { GlobalAccount } =require ("./globalAccount.js"); -const { +} from "@solana/web3.js"; +import { Program, Provider } from "@coral-xyz/anchor"; +import { GlobalAccount } from "./globalAccount"; +import { toCompleteEvent, toCreateEvent, toSetParamsEvent, toTradeEvent, -} =require ("./events.js"); -const { +} from "./events"; +import { createAssociatedTokenAccountInstruction, getAccount, getAssociatedTokenAddress, getOrCreateAssociatedTokenAccount, -} =require ("@solana/spl-token"); -const { BondingCurveAccount } =require ("./bondingCurveAccount.js"); -const { BN } =require ("bn.js"); -const { +} from "@solana/spl-token"; +import { BondingCurveAccount } from "./bondingCurveAccount"; +const {BN} = require("bn.js"); +import { DEFAULT_COMMITMENT, DEFAULT_FINALITY, calculateWithSlippageBuy, calculateWithSlippageSell, sendTx, sendTxToJito, -} =require ("./util.js"); -const { PumpFun, IDL } =require ("./IDL/index.js"); -const {wallet} = require("../../../helpers/config.js") -const PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; -const MPL_TOKEN_METADATA_PROGRAM_ID = +} from "./util"; +import { PumpFun, IDL } from "./IDL/index"; +import { wallet } from "../../../helpers/config"; +export const PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; +export const MPL_TOKEN_METADATA_PROGRAM_ID = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"; - const GLOBAL_ACCOUNT_SEED = "global"; - const MINT_AUTHORITY_SEED = "mint-authority"; - const BONDING_CURVE_SEED = "bonding-curve"; - const METADATA_SEED = "metadata"; +export const GLOBAL_ACCOUNT_SEED = "global"; +export const MINT_AUTHORITY_SEED = "mint-authority"; +export const BONDING_CURVE_SEED = "bonding-curve"; +export const METADATA_SEED = "metadata"; - const DEFAULT_DECIMALS = 6; +export const DEFAULT_DECIMALS = 6; - class PumpFunSDK { - - constructor(provider) { - this.program = new Program(IDL, provider); +export class PumpFunSDK { + public program: Program; + public connection: Connection; + constructor(provider?: Provider) { + this.program = new Program(IDL as PumpFun, provider); this.connection = this.program.provider.connection; } - async bundleBuys( creator, - mint, - createTokenMetadata, - buyAmountSol, - buyersWallets, + async bundleBuys( + creator: any, + mint: any, + createTokenMetadata: any, + buyAmountSol: any, + buyersWallets: any, slippageBasisPoints = 500n, - priorityFees, + priorityFees: any, commitment = DEFAULT_COMMITMENT, - finality = DEFAULT_FINALITY, - ){ - let tokenMetadata = await this.createTokenMetadata(createTokenMetadata); - let createTx = await this.getCreateInstructions( + finality = DEFAULT_FINALITY + ) { + let tokenMetadata = await this.createTokenMetadata(createTokenMetadata); + let createTx = await this.getCreateInstructions( + creator.publicKey, + createTokenMetadata.name, + createTokenMetadata.symbol, + tokenMetadata.metadataUri, + mint + ); + let final_tx = new Transaction().add(createTx); + const globalAccount = await this.getGlobalAccount(commitment); + const buyAmount = globalAccount.getInitialBuyPrice(buyAmountSol); + const buyAmountWithSlippage = calculateWithSlippageBuy( + buyAmountSol, + slippageBasisPoints + ); + final_tx.add( + await this.getBuyInstructions( creator.publicKey, - createTokenMetadata.name, - createTokenMetadata.symbol, - tokenMetadata.metadataUri, - mint - ); - let final_tx = new Transaction().add(createTx); - const globalAccount = await this.getGlobalAccount(commitment); - const buyAmount = globalAccount.getInitialBuyPrice(buyAmountSol); - const buyAmountWithSlippage = calculateWithSlippageBuy( - buyAmountSol, - slippageBasisPoints - ); - final_tx.add( - await this.getBuyInstructions( - creator.publicKey, - mint.publicKey, - globalAccount.feeRecipient, - buyAmount, - buyAmountWithSlippage - ) - ); + mint.publicKey, + globalAccount.feeRecipient, + buyAmount, + buyAmountWithSlippage + ) + ); - for(let i=0; i { @@ -501,36 +490,20 @@ const MPL_TOKEN_METADATA_PROGRAM_ID = switch (eventType) { case "createEvent": processedEvent = toCreateEvent(event); - callback( - processedEvent, - slot, - signature - ); + callback(processedEvent, slot, signature); break; case "tradeEvent": processedEvent = toTradeEvent(event); - callback( - processedEvent, - slot, - signature - ); + callback(processedEvent, slot, signature); break; case "completeEvent": processedEvent = toCompleteEvent(event); - callback( - processedEvent , - slot, - signature - ); + callback(processedEvent, slot, signature); console.log("completeEvent", event, slot, signature); break; case "setParamsEvent": - processedEvent = toSetParamsEvent(event ); - callback( - processedEvent, - slot, - signature - ); + processedEvent = toSetParamsEvent(event); + callback(processedEvent, slot, signature); break; default: console.error("Unhandled event type:", eventType); @@ -539,9 +512,8 @@ const MPL_TOKEN_METADATA_PROGRAM_ID = ); } - removeEventListener(eventId) { + removeEventListener(eventId:any) { this.program.removeEventListener(eventId); } } -module.exports = { PumpFunSDK, PROGRAM_ID, GLOBAL_ACCOUNT_SEED, MINT_AUTHORITY_SEED, BONDING_CURVE_SEED, METADATA_SEED, DEFAULT_DECIMALS }; \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/sell.js b/src/pumpfunsdk/pumpdotfun-sdk/src/sell.ts similarity index 77% rename from src/pumpfunsdk/pumpdotfun-sdk/src/sell.js rename to src/pumpfunsdk/pumpdotfun-sdk/src/sell.ts index 5fbe1cc..c91019a 100644 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/sell.js +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/sell.ts @@ -1,12 +1,12 @@ -const {sell} = require('./tools'); -const { PublicKey } = require("@solana/web3.js"); -const { program } = require("commander"); -let token_address = null, sellPercentage = null; +import {sell} from './tools'; +import { PublicKey } from "@solana/web3.js"; +import { program } from "commander"; +let token_address:any = null, sellPercentage:any = null; program .option("--token_address ", "Specify the token address") .option("--percentage ", "Specify the percentage of token to sell") .option("-h, --help", "display help for command") - .action((options) => { + .action((options:any) => { if (options.help) { console.log( "node sell --token_address --percentage " diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/tools.js b/src/pumpfunsdk/pumpdotfun-sdk/src/tools.ts similarity index 79% rename from src/pumpfunsdk/pumpdotfun-sdk/src/tools.js rename to src/pumpfunsdk/pumpdotfun-sdk/src/tools.ts index dbb4e41..6a26929 100644 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/tools.js +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/tools.ts @@ -1,44 +1,28 @@ -const { AnchorProvider } = require("@coral-xyz/anchor"); -const { PumpFunSDK, DEFAULT_DECIMALS } = require("./pumpfun.js"); -const { - sendTxToJito, - DEFAULT_COMMITMENT, - generateWalletsAndDropSOL, - solCollector, -} = require("./util.js"); -const { wallet, connection } = require("../../../helpers/config.js"); -const { +import { AnchorProvider } from "@coral-xyz/anchor"; +import { PumpFunSDK, DEFAULT_DECIMALS } from "./pumpfun.js"; +import { wallet, connection } from "../../../helpers/config"; +import { getOrCreateKeypair, getSPLBalance, printSOLBalance, printSPLBalance, - getKeypairByJsonPath, -} = require("../example/util.js"); -const fs = require("fs"); -const { promises } = require("dns"); -const { + getKeypairByJsonPath +} from "../example/util"; +import fs from "fs"; +import { promises } from "dns"; +import { Keypair, PublicKey, SystemProgram, Transaction, LAMPORTS_PER_SOL, -} = require("@solana/web3.js"); -const { bs58 } = require("@coral-xyz/anchor/dist/cjs/utils/bytes"); -const { - calculateWithSlippageBuy, - sendTx, - getOurWallet, - getOtherTradersWallet, - readCSVFile, - extractPrivateKeyAndSolana, -} = require("./util.js"); -const { - jito_executeAndConfirm, -} = require("./transactions/jito-tx-executor.js"); -const path = require("path"); -const { get } = require("http"); +} from "@solana/web3.js"; +import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; +import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; +import path from "path"; const SLIPPAGE_BASIS_POINTS = 100n; +const Wallet = new NodeWallet(wallet); /** * Creates and buys a token using the provided parameters. * @param {string} pathToMintKeypair - The path to the mint keypair JSON file. @@ -46,13 +30,14 @@ const SLIPPAGE_BASIS_POINTS = 100n; * @param {number} initialBuySolAmount - The initial amount of SOL to buy the token with. * @returns {Promise} - A promise that resolves when the token creation and purchase is complete. */ -async function createAndBuy(pathToMintKeypair, tokenMetadata, initialBuySolAmount) { - const provider = new AnchorProvider(connection, wallet, { +export async function createAndBuy(pathToMintKeypair:any, tokenMetadata:any, initialBuySolAmount:any) { + const Wallet = new NodeWallet(wallet); + const provider = new AnchorProvider(connection, Wallet, { commitment: "finalized", }); const sdk = new PumpFunSDK(provider); - const mintKeypair = getKeypairByJsonPath(pathToMintKeypair); + const mintKeypair:any = getKeypairByJsonPath(pathToMintKeypair); console.log(mintKeypair.publicKey); await printSOLBalance(connection, wallet.publicKey, "Master wallet keypair"); let globalAccount = await sdk.getGlobalAccount(); @@ -100,8 +85,8 @@ async function createAndBuy(pathToMintKeypair, tokenMetadata, initialBuySolAmoun * @param {number} sellPercentage - The percentage of tokens to sell. * @returns {Promise} - A promise that resolves when the sell operation is complete. */ -async function sell(mintPubKey, sellPercentage) { - const provider = new AnchorProvider(connection, wallet, { +export async function sell(mintPubKey:any, sellPercentage:any) { + const provider = new AnchorProvider(connection, Wallet, { commitment: "finalized", }); @@ -143,8 +128,8 @@ async function sell(mintPubKey, sellPercentage) { * @param {number} solPerOrder - The amount of SOL to spend per order. * @returns {Promise} - A promise that resolves when the buy operation is complete. */ -async function buy(mintPubKey, solPerOrder) { - const provider = new AnchorProvider(connection, wallet, { +export async function buy(mintPubKey:any, solPerOrder:any) { + const provider = new AnchorProvider(connection, Wallet, { commitment: "finalized", }); @@ -211,5 +196,3 @@ async function run() { } //run(); - -module.exports = {buy, sell, createAndBuy} \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/transactions/jito-tx-executor.js b/src/pumpfunsdk/pumpdotfun-sdk/src/transactions/jito-tx-executor.js deleted file mode 100644 index e8a762f..0000000 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/transactions/jito-tx-executor.js +++ /dev/null @@ -1,126 +0,0 @@ -const { - BlockhashWithExpiryBlockHeight, - Keypair, - PublicKey, - SystemProgram, - Connection, - TransactionMessage, - VersionedTransaction, - } = require("@solana/web3.js"); -const axios = require("axios"); -const bs58 = require("bs58"); -const { Currency, CurrencyAmount } = require("@raydium-io/raydium-sdk"); -const { connection } = require("../../../../helpers/config"); - const jito_Validators = [ - "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh", - "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt", - "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT", - "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe", - "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49", - "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY", - "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL", - "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5", - ]; - const endpoints = [ // TODO: Choose a jito endpoint which is closest to your location, and uncomment others - //"https://mainnet.block-engine.jito.wtf/api/v1/bundles", - //"https://amsterdam.mainnet.block-engine.jito.wtf/api/v1/bundles", - //"https://frankfurt.mainnet.block-engine.jito.wtf/api/v1/bundles", - //"https://ny.mainnet.block-engine.jito.wtf/api/v1/bundles", - "https://tokyo.mainnet.block-engine.jito.wtf/api/v1/bundles", - ]; -async function getRandomValidator() { - const res = - jito_Validators[Math.floor(Math.random() * jito_Validators.length)]; - return new PublicKey(res); - } - /** - * Executes and confirms a Jito transaction. - * @param {Transaction} transaction - The transaction to be executed and confirmed. - * @param {Account} payer - The payer account for the transaction. - * @param {Blockhash} lastestBlockhash - The latest blockhash. - * @param {number} jitofee - The fee for the Jito transaction. - * @returns {Promise<{ confirmed: boolean, signature: string | null }>} - A promise that resolves to an object containing the confirmation status and the transaction signature. - */ -async function jito_executeAndConfirm( - transaction, - payer, - lastestBlockhash, - jitofee - ){ - const jito_validator_wallet = await getRandomValidator(); - console.log("Executing transaction (jito)..."); - console.log("Selected Jito Validator: ", jito_validator_wallet.toBase58()); - try { - const fee = new CurrencyAmount(Currency.SOL, jitofee, false).raw.toNumber(); - console.log(`Jito Fee: ${fee / 10 ** 9} sol`); - const jitoFee_message = new TransactionMessage({ - payerKey: payer.publicKey, - recentBlockhash: lastestBlockhash.blockhash, - instructions: [ - SystemProgram.transfer({ - fromPubkey: payer.publicKey, - toPubkey: jito_validator_wallet, - lamports: fee, - }), - ], - }).compileToV0Message(); - const jitoFee_transaction = new VersionedTransaction(jitoFee_message); - jitoFee_transaction.sign([payer]); - const jitoTxSignature = bs58.encode(jitoFee_transaction.signatures[0]); - const serializedJitoFeeTransaction = bs58.encode( - jitoFee_transaction.serialize() - ); - const serializedTransaction = bs58.encode(transaction.serialize()); - const final_transaction = [ - serializedJitoFeeTransaction, - serializedTransaction, - ]; - const requests = endpoints.map((url) => - axios.post(url, { - jsonrpc: "2.0", - id: 1, - method: "sendBundle", - params: [final_transaction], - }) - ); - console.log("Sending tx to Jito validators..."); - const res = await Promise.all(requests.map((p) => p.catch((e) => e))); - const success_res = res.filter((r) => !(r instanceof Error)); - if (success_res.length > 0) { - console.log("Jito validator accepted the tx"); - return await jito_confirm(jitoTxSignature, lastestBlockhash); - } else { - console.log("No Jito validators accepted the tx"); - return { confirmed: false, signature: jitoTxSignature }; - } - } catch (e) { - if (e instanceof axios.AxiosError) { - console.log("Failed to execute the jito transaction"); - } else { - console.log("Error during jito transaction execution: ", e); - } - return { confirmed: false, signature: null }; - } - } - - /** - * Confirms a transaction on the Solana blockchain. - * @param {string} signature - The signature of the transaction. - * @param {object} latestBlockhash - The latest blockhash information. - * @returns {object} - An object containing the confirmation status and the transaction signature. - */ -async function jito_confirm(signature, latestBlockhash) { - console.log("Confirming the jito transaction..."); - const confirmation = await connection.confirmTransaction( - { - signature, - lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, - blockhash: latestBlockhash.blockhash, - }, - "confirmed" - ); - return { confirmed: !confirmation.value.err, signature: signature }; - } - - -module.exports = { jito_executeAndConfirm, jito_confirm }; \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/types.js b/src/pumpfunsdk/pumpdotfun-sdk/src/types.js deleted file mode 100644 index 4b9bf2c..0000000 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/types.js +++ /dev/null @@ -1,80 +0,0 @@ -const { PublicKey, VersionedTransactionResponse } = require("@solana/web3.js"); - -// export type CreateTokenMetadata = { -// name: string; -// symbol: string; -// description: string; -// file: Blob; -// twitter?: string; -// telegram?: string; -// website?: string; -// }; - -// export type TokenMetadata = { -// name: string; -// symbol: string; -// description: string; -// image: string; -// showName: boolean; -// createdOn: string; -// twitter: string; -// }; - -// export type CreateEvent = { -// name: string; -// symbol: string; -// uri: string; -// mint: PublicKey; -// bondingCurve: PublicKey; -// user: PublicKey; -// }; - -// export type TradeEvent = { -// mint: PublicKey; -// solAmount: bigint; -// tokenAmount: bigint; -// isBuy: boolean; -// user: PublicKey; -// timestamp: number; -// virtualSolReserves: bigint; -// virtualTokenReserves: bigint; -// realSolReserves: bigint; -// realTokenReserves: bigint; -// }; - -// export type CompleteEvent = { -// user: PublicKey; -// mint: PublicKey; -// bondingCurve: PublicKey; -// timestamp: number; -// }; - -// export type SetParamsEvent = { -// feeRecipient: PublicKey; -// initialVirtualTokenReserves: bigint; -// initialVirtualSolReserves: bigint; -// initialRealTokenReserves: bigint; -// tokenTotalSupply: bigint; -// feeBasisPoints: bigint; -// }; - -// export interface PumpFunEventHandlers { -// createEvent: CreateEvent; -// tradeEvent: TradeEvent; -// completeEvent: CompleteEvent; -// setParamsEvent: SetParamsEvent; -// } - -// export type PumpFunEventType = keyof PumpFunEventHandlers; - -// export type PriorityFee = { -// unitLimit: number; -// unitPrice: number; -// }; - -// export type TransactionResult = { -// signature?: string; -// error?: unknown; -// results?: VersionedTransactionResponse; -// success: boolean; -// }; diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/types.ts b/src/pumpfunsdk/pumpdotfun-sdk/src/types.ts new file mode 100644 index 0000000..60af5ec --- /dev/null +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/types.ts @@ -0,0 +1,80 @@ +import { PublicKey, VersionedTransactionResponse } from "@solana/web3.js"; + +export type CreateTokenMetadata = { + name: string; + symbol: string; + description: string; + file: Blob; + twitter?: string; + telegram?: string; + website?: string; +}; + +export type TokenMetadata = { + name: string; + symbol: string; + description: string; + image: string; + showName: boolean; + createdOn: string; + twitter: string; +}; + +export type CreateEvent = { + name: string; + symbol: string; + uri: string; + mint: PublicKey; + bondingCurve: PublicKey; + user: PublicKey; +}; + +export type TradeEvent = { + mint: PublicKey; + solAmount: bigint; + tokenAmount: bigint; + isBuy: boolean; + user: PublicKey; + timestamp: number; + virtualSolReserves: bigint; + virtualTokenReserves: bigint; + realSolReserves: bigint; + realTokenReserves: bigint; +}; + +export type CompleteEvent = { + user: PublicKey; + mint: PublicKey; + bondingCurve: PublicKey; + timestamp: number; +}; + +export type SetParamsEvent = { + feeRecipient: PublicKey; + initialVirtualTokenReserves: bigint; + initialVirtualSolReserves: bigint; + initialRealTokenReserves: bigint; + tokenTotalSupply: bigint; + feeBasisPoints: bigint; +}; + +export interface PumpFunEventHandlers { + createEvent: CreateEvent; + tradeEvent: TradeEvent; + completeEvent: CompleteEvent; + setParamsEvent: SetParamsEvent; +} + +export type PumpFunEventType = keyof PumpFunEventHandlers; + +export type PriorityFee = { + unitLimit: number; + unitPrice: number; +}; + +export type TransactionResult = { + signature?: string; + error?: unknown; + results?: VersionedTransactionResponse; + success: boolean; +}; \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/util.js b/src/pumpfunsdk/pumpdotfun-sdk/src/util.js deleted file mode 100644 index 9b6c6f6..0000000 --- a/src/pumpfunsdk/pumpdotfun-sdk/src/util.js +++ /dev/null @@ -1,568 +0,0 @@ -const{ - Commitment, - ComputeBudgetProgram, - Connection, - Finality, - Keypair, - PublicKey, - SendTransactionError, - Transaction, - TransactionMessage, - VersionedTransaction, - VersionedTransactionResponse, - sendAndConfirmTransaction, - LAMPORTS_PER_SOL, - SystemProgram -} =require ("@solana/web3.js"); -const{ AnchorProvider } =require ("@coral-xyz/anchor"); -const {PumpFunSDK, DEFAULT_DECIMALS} = require("./pumpfun.js") -const{ PriorityFee, TransactionResult } =require ("./types.js"); -const{ jito_executeAndConfirm } =require ("./transactions/jito-tx-executor.js"); -const fs =require ("fs"); -const{ bs58 } =require ("@coral-xyz/anchor/dist/cjs/utils/bytes"); -const { - getOrCreateKeypair, - getSPLBalance, - printSOLBalance, - printSPLBalance, - getKeypairByJsonPath, -} = require("../example/util.js"); -const DEFAULT_COMMITMENT = "finalized"; -const DEFAULT_FINALITY = "finalized"; - -const calculateWithSlippageBuy = ( - amount, - basisPoints -) => { - return amount + (amount * basisPoints) / 10000n; -}; - -const calculateWithSlippageSell = ( - amount, - basisPoints -) => { - return amount - (amount * basisPoints) / 10000n; -}; - -function readCSVFile(filePath) { - try { - const data = fs.readFileSync(filePath, "utf8"); - return data; - } catch (err) { - console.error("Error reading the CSV file:", err); - return null; - } -} - -async function sendTxToJito( - connection, - tx, - payer, - signers, - jitofee -){ - const blockhash = (await connection.getLatestBlockhash()); - let final_tx = new Transaction(); - final_tx.add(tx); - let versionedTx = await buildVersionedTx(connection, payer.publicKey, final_tx, connection.commitment); - versionedTx.sign(signers); - try{ - const {confirmed, signature} = await jito_executeAndConfirm(versionedTx, payer, blockhash, jitofee); - // let txResult = await getTxDetails(connection, signature, connection.commitment, DEFAULT_FINALITY); - if (!confirmed) { - return { - success: false, - error: "Transaction failed", - }; - } - return { - success: true, - signature: signature, - }; - - }catch(e){ - if(e instanceof SendTransactionError){ - let ste = e; - console.log(await ste.getLogs(connection)); - }else{ - console.error(e); - } - return { - error: e, - success: false, - }; - } - - -} - -async function sendTx( - connection, - tx, - payer, - signers, - priorityFees, - commitment = DEFAULT_COMMITMENT, - finality = DEFAULT_FINALITY -){ - let newTx = new Transaction(); - - if (priorityFees) { - const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({ - units: priorityFees.unitLimit, - }); - - const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({ - microLamports: priorityFees.unitPrice, - }); - newTx.add(modifyComputeUnits); - newTx.add(addPriorityFee); - } - - newTx.add(tx); - let versionedTx = await buildVersionedTx(connection, payer, newTx, commitment); - versionedTx.sign(signers); - - try { - const sig = await connection.sendTransaction(versionedTx, { - skipPreflight: true, - }); - - console.log("sig:", `https://solscan.io/tx/${sig}`); - - let txResult = await getTxDetails(connection, sig, commitment, finality); - if (!txResult) { - return { - success: false, - error: "Transaction failed", - }; - } - return { - success: true, - }; - } catch (e) { - if (e instanceof SendTransactionError) { - let ste = e; - console.log(await ste.getLogs(connection)); - } else { - console.error(e); - } - return { - error: e, - success: false, - }; - } -} - -async function buildVersionedTx ( - connection, - payer, - tx, - commitment = DEFAULT_COMMITMENT -){ - const blockHash = (await connection.getLatestBlockhash(commitment)) - .blockhash; - - let messageV0 = new TransactionMessage({ - payerKey: payer, - recentBlockhash: blockHash, - instructions: tx.instructions, - }).compileToV0Message(); - - return new VersionedTransaction(messageV0); -}; - -async function getTxDetails ( - connection, - sig, - commitment = DEFAULT_COMMITMENT, - finality= DEFAULT_FINALITY -){ - const latestBlockHash = await connection.getLatestBlockhash(); - await connection.confirmTransaction( - { - blockhash: latestBlockHash.blockhash, - lastValidBlockHeight: latestBlockHash.lastValidBlockHeight, - signature: sig, - }, - commitment - ); - - return connection.getTransaction(sig, { - maxSupportedTransactionVersion: 0, - commitment: finality, - }); -}; - -function generateKeysAndAllocateSol(targetNumberOfKeys, targetTotalSol) { - // Generate private keys - const keys = []; - let sum = 0; - for (let i = 0; i < targetNumberOfKeys; i++) { - const keypair = Keypair.generate(); - keys.push(bs58.encode(keypair.secretKey)); - } - - // Allocate SOL with randomness - const averageAllocation = targetTotalSol / targetNumberOfKeys; - const maxDeviation = averageAllocation * 0.2; // 10% deviation - - const allocations = []; - let totalAllocated = 0; - - for (let i = 0; i < targetNumberOfKeys - 1; i++) { - const randomDeviation = (Math.random() * 2 - 1) * maxDeviation; - const allocation = parseFloat( - (averageAllocation + randomDeviation).toFixed(10) - ); - allocations.push({ privateKey: keys[i], sol: allocation }); - sum += allocation + 0.004; - totalAllocated += allocation; - } - - // Adjust the last allocation to match the target total precisely - const lastAllocation = parseFloat( - (targetTotalSol - totalAllocated).toFixed(10) - ); - - allocations.push({ - privateKey: keys[targetNumberOfKeys - 1], - sol: lastAllocation, - }); - console.log("sum", sum); - return allocations; -} - -// Function to write the allocations to a CSV file -async function writeAllocationsToCSV(filePath, allocations) { - const csvContent = allocations - .map(({ privateKey, sol }) => `${privateKey},${sol}`) - .join("\n"); - fs.writeFileSync(filePath, csvContent, "utf8"); -} - async function dropWalletBySOL(connection, walletListWithSOL, fundingWallet) { - console.log(fundingWallet.publicKey.toBase58()); - for (let i = 0; i < walletListWithSOL.length; i++) { - // we bundle 5 wallet to drop sol - if (i % 5 == 0) { - let final_tx = new Transaction(); - let fiveSigners = []; - for (let j = i; j < i + 5; j++) { - let secretKey = new Uint8Array( - bs58.decode(walletListWithSOL[j].privateKey) - ); - let sniperWallets = Keypair.fromSecretKey(secretKey); - console.log("Existing wallet: ", sniperWallets.publicKey.toBase58()); - console.log( - "it needs to drop: ", - walletListWithSOL[j].SOL * LAMPORTS_PER_SOL - ); - final_tx.add( - SystemProgram.transfer({ - fromPubkey: fundingWallet.publicKey, - toPubkey: sniperWallets.publicKey, - lamports: Math.round(walletListWithSOL[j].SOL * LAMPORTS_PER_SOL), - }) - ); - fiveSigners.push(sniperWallets); - } - - // Send the transaction - await sendTx( - connection, - final_tx, - fundingWallet.publicKey, - [fundingWallet], - { - unitLimit: 250000, - unitPrice: 0.005 * LAMPORTS_PER_SOL, - } - ); - } - } -} - -async function extractPrivateKeyAndSolana(data, numberOfSnipers) { - // Split the input string by newlines to handle multiple lines of input - const lines = data.split("\n"); - const pathToBoughtSnipers = - "/Users/chiwangso/Desktop/beta-memecoin-cli/src/memecoin-launch/pumpdotfun-sdk/src/WalletKeypairs/already3.json"; - let boughtSnipers = []; - try { - const fileContents = await fs.promises.readFile( - pathToBoughtSnipers, - "utf8" - ); - boughtSnipers = JSON.parse(fileContents); - } catch (error) { - // If the file doesn't exist, it's okay, we'll just create a new one - } - // Initialize an array to hold the results - const results= []; - let cnt = 0; - - // Iterate over each line - lines.forEach((line) => { - // Split the line by the comma to separate the private key and the number - const parts = line.split(","); - - // Check if the line has both a private key and a number - if (parts.length >= 2) { - const privateKey = parts[0].trim(); - const SOL = parseFloat(parts[1].trim()); - const keypair = Keypair.fromSecretKey( - new Uint8Array(bs58.decode(privateKey)) - ); - - // Push the result as an object if the status is not "done" and the count is less than the number of snipers - if ( - cnt < numberOfSnipers && - !boughtSnipers.includes(keypair.publicKey.toBase58()) - ) { - results.push({ - privateKey, - SOL, - }); - cnt++; - } - } - }); - - return results; -} - - async function getKeypairFromCsv(pathToCsv, numberOfSnipers) { - const data = await readCSVFile(pathToCsv); - const extractedData = await extractPrivateKeyAndSolana(data, numberOfSnipers); - let keypairList = []; - for (let i = 0; i < extractedData.length; i++) { - let secretKey = new Uint8Array(bs58.decode(extractedData[i].privateKey)); - let keypair = Keypair.fromSecretKey(secretKey); - keypairList.push(keypair); - } - return keypairList; -} - - - -async function getOtherTradersWallet(mintPubKey) { - let page = 1; - let allOwners = new Set(); - - while (true) { - const response = await fetch( - "https://mainnet.helius-rpc.com/?api-key=448fa184-4e3c-419b-a456-e9fd6889b659", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - jsonrpc: "2.0", - method: "getTokenAccounts", - id: "helius-test", - params: { - page: page, - limit: 1000, - displayOptions: {}, - mint: mintPubKey.toBase58(), - }, - }), - } - ); - const data = await response.json(); - - if (!data.result || data.result.token_accounts.length === 0) { - break; - } - data.result.token_accounts.forEach((account) => - allOwners.add(account.owner) - ); - page++; - } - - return Array.from(allOwners) ; - // return a list of outsider wallet address - // [ - // "owner": amount - // "owner2": amount - //] -} - - -async function getOurWallet() { - // return a list of our wallet address - const pathToSave = - "/Users/chiwangso/Desktop/beta-memecoin-cli/src/memecoin-launch/pumpdotfun-sdk/src/WalletKeypairs/already3.json"; - let listOfOurWallets= []; - const fileContents = await fs.promises.readFile(pathToSave, "utf8"); - listOfOurWallets = JSON.parse(fileContents); - return listOfOurWallets ; -} - -async function solCollector(connection, wallet, numberOfSnipers, pathToSnipersPrivateKey) { - - let sniperKeypairs = []; - const privateKeysArr = await fs.promises.readFile(pathToSnipersPrivateKey, "utf8"); - existingWallets = JSON.parse(privateKeysArr); - - for (let i = 0; i < existingWallets.length; i++) { - const sniperWallet = Keypair.fromSecretKey(bs58.decode(existingWallets[i])); - sniperKeypairs.push(sniperWallet); - } - console.log("Sol Collector is start"); - let final_tx = new Transaction(); - for (let i = 0; i < numberOfSnipers; i++) { - const solbalance = await connection.getBalance(sniperKeypairs[i].publicKey); - console.log( - `Sniper ${sniperKeypairs[i].publicKey.toBase58()} SOL balance: `, - solbalance - ); - final_tx.add( - SystemProgram.transfer({ - fromPubkey: sniperKeypairs[i].publicKey, - toPubkey: wallet.publicKey, - lamports: solbalance, - }) - ); - } - //send the transaction - - await sendTx( - connection, - final_tx, - wallet.publicKey, - [wallet, ...sniperKeypairs], - { - unitLimit: 250000, - unitPrice: 750000, - } - ); -} - -async function dropSOLToWallet(connection, masterWallet, walletPublicAddress, SOLToDrop) { - let final_tx = new Transaction(); - final_tx.add( - SystemProgram.transfer({ - fromPubkey: masterWallet.publicKey, - toPubkey: walletPublicAddress, - lamports: Math.round(SOLToDrop * LAMPORTS_PER_SOL), - }) - ); - const blockhash = await connection.getLatestBlockhash("confirmed"); - final_tx.feePayer = masterWallet.publicKey; - final_tx.recentBlockhash = blockhash.blockhash; - await sendTxToJito( - connection, - final_tx, - masterWallet, - [masterWallet], - 0.0001 - ); -} -async function getNumberOfKeypairsArrayFromPath( - path, - numberOfKeypairs -){ - let existingWallets = []; - let resWalletKeypairs = []; - try { - const fileContents = await fs.promises.readFile(path, "utf8"); - existingWallets = JSON.parse(fileContents); - for (let i = 0; i < numberOfKeypairs; i++) { - const secretKey = new Uint8Array(bs58.decode(existingWallets[i])); - const wallet = Keypair.fromSecretKey(secretKey); - console.log(wallet.publicKey.toBase58()); - resWalletKeypairs.push(wallet); - } - return resWalletKeypairs; - } catch (error) { - // If the file doesn't exist, it's okay, we'll just create a new one - } - return resWalletKeypairs; -} - - async function generateWalletsAndDropSOL( - connection, - masterWallet, - amountOfSol, - numberOfNewWallet, - pathToSave -){ - // Check if the file already exists - let existingWallets= []; - try { - const fileContents = await fs.promises.readFile(pathToSave, "utf8"); - existingWallets = JSON.parse(fileContents); - } catch (error) { - // If the file doesn't exist, it's okay, we'll just create a new one - } - let final_tx = new Transaction(); - for (let i = 0; i < existingWallets.length; i++) { - const wallet = Keypair.fromSecretKey(bs58.decode(existingWallets[i])); - console.log("Existing wallet: ", wallet.publicKey.toBase58()); - final_tx.add( - SystemProgram.transfer({ - fromPubkey: masterWallet.publicKey, - toPubkey: wallet.publicKey, - lamports: amountOfSol * LAMPORTS_PER_SOL, - }) - ); - } - // Generate new wallets and append to the existing array - for (let i = 0; i < numberOfNewWallet; i++) { - let newWallet = Keypair.generate(); - - console.log("New wallet created: ", newWallet.publicKey.toBase58()); - const privateKey = bs58.encode(newWallet.secretKey); - existingWallets.push(privateKey); - // Transfer SOL to the new wallet - final_tx.add( - SystemProgram.transfer({ - fromPubkey: masterWallet.publicKey, - toPubkey: newWallet.publicKey, - lamports: amountOfSol * LAMPORTS_PER_SOL, - }) - ); - } - - // Send the transaction - const blockhash = await connection.getLatestBlockhash("confirmed"); - final_tx.feePayer = masterWallet.publicKey; - final_tx.recentBlockhash = blockhash.blockhash; - await sendTxToJito( - connection, - final_tx, - masterWallet, - [masterWallet], - 0.0001 - ); - - // Save the updated array to the file - try { - await fs.promises.writeFile( - pathToSave, - JSON.stringify(existingWallets, null, 2) - ); - console.log(`Wallets saved to ${pathToSave}`); - } catch (error) { - console.error(`Error saving wallets to ${pathToSave}:`, error); - } - - return existingWallets; -} - - async function checkIfBondingCurveComplete(connection, wallet, mintKeypair) { - const provider = new AnchorProvider(connection, wallet, { - commitment: "finalized", - }); - - const sdk = new PumpFunSDK(provider); - const bondingCurveAccount = await sdk.getBondingCurveAccount( - mintKeypair.publicKey - ); - console.log("bondingCurveAccount: ", bondingCurveAccount); - return bondingCurveAccount?.complete; -} - -module.exports = {generateWalletsAndDropSOL, getNumberOfKeypairsArrayFromPath, dropSOLToWallet, solCollector, getOurWallet, getOtherTradersWallet, getKeypairFromCsv, extractPrivateKeyAndSolana, sendTx, sendTxToJito, readCSVFile, calculateWithSlippageSell, calculateWithSlippageBuy, DEFAULT_COMMITMENT, DEFAULT_FINALITY, sendTxToJito, buildVersionedTx, getTxDetails, generateKeysAndAllocateSol, writeAllocationsToCSV, dropWalletBySOL, getKeypairFromCsv, extractPrivateKeyAndSolana, getOtherTradersWallet, getOurWallet, solCollector, dropSOLToWallet, getNumberOfKeypairsArrayFromPath, generateWalletsAndDropSOL, checkIfBondingCurveComplete} \ No newline at end of file diff --git a/src/pumpfunsdk/pumpdotfun-sdk/src/util.ts b/src/pumpfunsdk/pumpdotfun-sdk/src/util.ts new file mode 100644 index 0000000..e216c0d --- /dev/null +++ b/src/pumpfunsdk/pumpdotfun-sdk/src/util.ts @@ -0,0 +1,313 @@ +import{ + Commitment, + ComputeBudgetProgram, + Connection, + Finality, + Keypair, + PublicKey, + SendTransactionError, + Transaction, + TransactionMessage, + VersionedTransaction, + VersionedTransactionResponse, + sendAndConfirmTransaction, + LAMPORTS_PER_SOL, + SystemProgram, +} from "@solana/web3.js"; +import{ AnchorProvider } from "@coral-xyz/anchor"; +import {PumpFunSDK, DEFAULT_DECIMALS} from "./pumpfun"; +import{ PriorityFee, TransactionResult } from "./types"; +import{ jito_executeAndConfirm } from "../../../Transactions/jito_tips_tx_executor"; +import fs from "fs"; +import{ bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; +export const DEFAULT_COMMITMENT = "finalized"; +export const DEFAULT_FINALITY = "finalized"; + +export const calculateWithSlippageBuy = ( + amount: bigint, + basisPoints: bigint +) => { + return amount + (amount * basisPoints) / 10000n; +}; + +export const calculateWithSlippageSell = ( + amount: bigint, + basisPoints: bigint +) => { + return amount - (amount * basisPoints) / 10000n; +}; + +function readCSVFile(filePath:string) { + try { + const data = fs.readFileSync(filePath, "utf8"); + return data; + } catch (err) { + console.error("Error reading the CSV file:", err); + return null; + } +} + +export async function sendTxToJito( + connection:Connection, + tx:any, + payer:Keypair, + signers:Keypair[], + jitofee:any +){ + const blockhash = (await connection.getLatestBlockhash()); + let final_tx = new Transaction(); + final_tx.add(tx); + let versionedTx = await buildVersionedTx(connection, payer.publicKey, final_tx, connection.commitment); + versionedTx.sign(signers); + try{ + const {confirmed, signature} = await jito_executeAndConfirm(versionedTx, payer, blockhash, jitofee); + // let txResult = await getTxDetails(connection, signature, connection.commitment, DEFAULT_FINALITY); + if (!confirmed) { + return { + success: false, + error: "Transaction failed", + }; + } + return { + success: true, + signature: signature, + }; + + }catch(e){ + if(e instanceof SendTransactionError){ + let ste = e; + }else{ + console.error(e); + } + return { + error: e, + success: false, + }; + } + + +} + +export async function sendTx( + connection: Connection, + tx: Transaction, + payer: PublicKey, + signers: Keypair[], + priorityFees?: PriorityFee, + commitment: any = DEFAULT_COMMITMENT, + finality: any = DEFAULT_FINALITY +): Promise { + let newTx = new Transaction(); + + if (priorityFees) { + const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({ + units: priorityFees.unitLimit, + }); + + const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({ + microLamports: priorityFees.unitPrice, + }); + newTx.add(modifyComputeUnits); + newTx.add(addPriorityFee); + } + + newTx.add(tx); + + let versionedTx = await buildVersionedTx(connection, payer, newTx, commitment); + versionedTx.sign(signers); + + try { + const sig = await connection.sendTransaction(versionedTx, { + skipPreflight: false, + }); + console.log("sig:", `https://solscan.io/tx/${sig}`); + + let txResult = await getTxDetails(connection, sig, commitment, finality); + if (!txResult) { + return { + success: false, + error: "Transaction failed", + }; + } + return { + success: true, + signature: sig, + results: txResult, + }; + } catch (e) { + if (e instanceof SendTransactionError) { + let ste = e as SendTransactionError; + } else { + console.error(e); + } + return { + error: e, + success: false, + }; + } +} + +export const buildVersionedTx = async ( + connection: Connection, + payer: PublicKey, + tx: Transaction, + commitment: Commitment = DEFAULT_COMMITMENT +): Promise => { + const blockHash = (await connection.getLatestBlockhash(commitment)) + .blockhash; + + let messageV0 = new TransactionMessage({ + payerKey: payer, + recentBlockhash: blockHash, + instructions: tx.instructions, + }).compileToV0Message(); + + return new VersionedTransaction(messageV0); +}; + +export const getTxDetails = async ( + connection: Connection, + sig: string, + commitment: Commitment = DEFAULT_COMMITMENT, + finality: Finality = DEFAULT_FINALITY +): Promise => { + const latestBlockHash = await connection.getLatestBlockhash(); + await connection.confirmTransaction( + { + blockhash: latestBlockHash.blockhash, + lastValidBlockHeight: latestBlockHash.lastValidBlockHeight, + signature: sig, + }, + commitment + ); + + return connection.getTransaction(sig, { + maxSupportedTransactionVersion: 0, + commitment: finality, + }); +}; + +export function generateKeysAndAllocateSol(targetNumberOfKeys:number, targetTotalSol:number) { + // Generate private keys + const keys = []; + let sum = 0; + for (let i = 0; i < targetNumberOfKeys; i++) { + const keypair = Keypair.generate(); + keys.push(bs58.encode(keypair.secretKey)); + } + + // Allocate SOL with randomness + const averageAllocation = targetTotalSol / targetNumberOfKeys; + const maxDeviation = averageAllocation * 0.2; // 10% deviation + + const allocations = []; + let totalAllocated = 0; + + for (let i = 0; i < targetNumberOfKeys - 1; i++) { + const randomDeviation = (Math.random() * 2 - 1) * maxDeviation; + const allocation = parseFloat( + (averageAllocation + randomDeviation).toFixed(10) + ); + allocations.push({ privateKey: keys[i], sol: allocation }); + sum += allocation + 0.004; + totalAllocated += allocation; + } + + // Adjust the last allocation to match the target total precisely + const lastAllocation = parseFloat( + (targetTotalSol - totalAllocated).toFixed(10) + ); + + allocations.push({ + privateKey: keys[targetNumberOfKeys - 1], + sol: lastAllocation, + }); + console.log("sum", sum); + return allocations; +} + + +export async function generateWalletsAndDropSOL( + connection:Connection, + masterWallet:Keypair, + amountOfSol:number, + numberOfNewWallet:number, + pathToSave:string +){ + // Check if the file already exists + let existingWallets= []; + try { + const fileContents = await fs.promises.readFile(pathToSave, "utf8"); + existingWallets = JSON.parse(fileContents); + } catch (error) { + // If the file doesn't exist, it's okay, we'll just create a new one + } + let final_tx = new Transaction(); + for (let i = 0; i < existingWallets.length; i++) { + const wallet = Keypair.fromSecretKey(bs58.decode(existingWallets[i])); + console.log("Existing wallet: ", wallet.publicKey.toBase58()); + final_tx.add( + SystemProgram.transfer({ + fromPubkey: masterWallet.publicKey, + toPubkey: wallet.publicKey, + lamports: amountOfSol * LAMPORTS_PER_SOL, + }) + ); + } + // Generate new wallets and append to the existing array + for (let i = 0; i < numberOfNewWallet; i++) { + let newWallet = Keypair.generate(); + + console.log("New wallet created: ", newWallet.publicKey.toBase58()); + const privateKey = bs58.encode(newWallet.secretKey); + existingWallets.push(privateKey); + // Transfer SOL to the new wallet + final_tx.add( + SystemProgram.transfer({ + fromPubkey: masterWallet.publicKey, + toPubkey: newWallet.publicKey, + lamports: amountOfSol * LAMPORTS_PER_SOL, + }) + ); + } + + // Send the transaction + const blockhash = await connection.getLatestBlockhash("confirmed"); + final_tx.feePayer = masterWallet.publicKey; + final_tx.recentBlockhash = blockhash.blockhash; + await sendTxToJito( + connection, + final_tx, + masterWallet, + [masterWallet], + 0.0001 + ); + + // Save the updated array to the file + try { + await fs.promises.writeFile( + pathToSave, + JSON.stringify(existingWallets, null, 2) + ); + console.log(`Wallets saved to ${pathToSave}`); + } catch (error) { + console.error(`Error saving wallets to ${pathToSave}:`, error); + } + + return existingWallets; +} + + export async function checkIfBondingCurveComplete(connection:Connection, wallet:any, mintKeypair:any){ + const provider = new AnchorProvider(connection, wallet, { + commitment: "finalized", + }); + + const sdk = new PumpFunSDK(provider); + const bondingCurveAccount = await sdk.getBondingCurveAccount( + mintKeypair.publicKey + ); + console.log("bondingCurveAccount: ", bondingCurveAccount); + return bondingCurveAccount?.complete; + + } + diff --git a/src/raydium/Pool/add_pool.js b/src/raydium/Pool/add_pool.ts similarity index 82% rename from src/raydium/Pool/add_pool.js rename to src/raydium/Pool/add_pool.ts index 0074501..8807cad 100644 --- a/src/raydium/Pool/add_pool.js +++ b/src/raydium/Pool/add_pool.ts @@ -1,40 +1,40 @@ -const assert = require("assert"); -const { +import assert from "assert"; +import { jsonInfo2PoolKeys, Liquidity, Token, TOKEN_PROGRAM_ID, TokenAmount, Percent, -} = require("@raydium-io/raydium-sdk"); -const { PublicKey, Keypair } = require("@solana/web3.js"); -//const { getPoolId, getPoolIdByPair } = require("./query_pool.js"); -const {fetchAMMPoolId} = require("./fetch_pool.js") -const Decimal = require("decimal.js"); +} from "@raydium-io/raydium-sdk"; +import { PublicKey, Keypair } from "@solana/web3.js"; +//import { getPoolId, getPoolIdByPair } from("./query_pool.js"); +import {fetchAMMPoolId} from "./fetch_pool"; +import Decimal from "decimal.js"; -const { +import { connection, DEFAULT_TOKEN, makeTxVersion, dev_connection, wallet, -} = require("../helpers/config.js"); -const { formatAmmKeysById_pool } = require("./formatAmmKeysById.js"); -const { +} from "../../helpers/config"; +import { formatAmmKeysById_pool } from "./formatAmmKeysById"; +import { buildAndSendTx, getWalletTokenAccount, loadOrCreateKeypair_wallet, getDecimals, getTokenMetadata, checkTx, -} = require("../helpers/util.js"); +} from "../../helpers/util"; const BN = require("bn.js"); -const { program } = require("commander"); +import { program } from "commander"; -let payer_keypair = null, - token_address = null, - pool_id = null, - sol = null, +let payer_keypair:any = null, + token_address:any = null, + pool_id:any = null, + sol:any = null, cluster = null, priority_fee = null, connection_sol = connection; @@ -84,14 +84,14 @@ program.parse(); * @param {string} input.walletTokenAccounts - The token accounts of the wallet. * @returns {Object} - The transaction IDs and the amount of another currency. */ -async function ammAddLiquidity(input) { +export async function ammAddLiquidity(input:any) { try { const targetPoolInfo = await formatAmmKeysById_pool(input.targetPool); assert(targetPoolInfo, "cannot find the target pool"); // -------- step 1: compute another amount -------- - const poolKeys = jsonInfo2PoolKeys(targetPoolInfo); + const poolKeys:any = jsonInfo2PoolKeys(targetPoolInfo); const extraPoolInfo = await Liquidity.fetchInfo({ connection, poolKeys, @@ -113,7 +113,7 @@ async function ammAddLiquidity(input) { }); // -------- step 2: make instructions -------- - const addLiquidityInstructionResponse = + const addLiquidityInstructionResponse:any = await Liquidity.makeAddLiquidityInstructionSimple({ connection, poolKeys, @@ -134,18 +134,13 @@ async function ammAddLiquidity(input) { return { txids: await buildAndSendTx( - addLiquidityInstructionResponse.innerTransactions + addLiquidityInstructionResponse.innerTransactions, + null ), anotherAmount, }; } catch (e) { console.log(e); - return { - txids: await buildAndSendTx( - addLiquidityInstructionResponse.innerTransactions - ), - anotherAmount, - }; } } /** @@ -153,12 +148,12 @@ async function ammAddLiquidity(input) { * @param {Object} input - The input parameters for adding liquidity. * @returns {Promise} - A promise that resolves when the liquidity is added. */ -async function ammAddLiquidityHelper(input) { - const { txids, amount } = await ammAddLiquidity(input); - console.log("txids:", txids); - const response = await checkTx(txids[0]); +export async function ammAddLiquidityHelper(input:any) { + const res:any = await ammAddLiquidity(input); + console.log("txids:", res?.txids); + const response = await checkTx(res?.txids[0]); if (response) { - console.log(`https://explorer.solana.com/tx/${txids}?cluster=mainnet`); + console.log(`https://explorer.solana.com/tx/${res?.txids}?cluster=mainnet`); } else { console.log("Transaction failed"); console.log("trying to send the transaction again"); diff --git a/src/raydium/Pool/create_pool.js b/src/raydium/Pool/create_pool.ts similarity index 100% rename from src/raydium/Pool/create_pool.js rename to src/raydium/Pool/create_pool.ts diff --git a/src/raydium/Pool/fetch_pool.js b/src/raydium/Pool/fetch_pool.ts similarity index 84% rename from src/raydium/Pool/fetch_pool.js rename to src/raydium/Pool/fetch_pool.ts index 36018ad..4fbdba5 100644 --- a/src/raydium/Pool/fetch_pool.js +++ b/src/raydium/Pool/fetch_pool.ts @@ -1,8 +1,8 @@ -const { initSdk } = require("../raydium_config.js"); -const { wsol } = require("../constants.js"); +import { initSdk } from "../raydium_config"; +import { wsol } from "../constants"; let sdkCache = { sdk: null, expiry: 0 }; -async function fetchAMMPoolId(tokenAddress) { - let raydium = null; +export async function fetchAMMPoolId(tokenAddress:string) { + let raydium:any = null; if (sdkCache.sdk) { raydium = sdkCache.sdk; } else { @@ -25,8 +25,8 @@ async function fetchAMMPoolId(tokenAddress) { return ""; // return empty string if no AMM pool ID is found } -async function fetchAMMPoolIdByMintPair(mint1, mint2) { - let raydium = null; +export async function fetchAMMPoolIdByMintPair(mint1:string, mint2:string) { + let raydium:any = null; if (sdkCache.sdk) { raydium = sdkCache.sdk; } else { @@ -48,7 +48,7 @@ async function fetchAMMPoolIdByMintPair(mint1, mint2) { console.log("No AMM pool ID found for the given mint pair"); return ""; // return empty string if no AMM pool ID is found } -async function fetchLPToken(tokenAddress) { +export async function fetchLPToken(tokenAddress:string) { try { const poolId = await fetchAMMPoolId(tokenAddress); let response = await ( @@ -73,4 +73,3 @@ async function fetchLPToken(tokenAddress) { } //fetchLPToken("3XTp12PmKMHxB6YkejaGPUjMGBLKRGgzHWgJuVTsBCoP"); -module.exports = { fetchAMMPoolId, fetchAMMPoolIdByMintPair, fetchLPToken }; diff --git a/src/raydium/Pool/formatAmmKeysById.js b/src/raydium/Pool/formatAmmKeysById.ts similarity index 93% rename from src/raydium/Pool/formatAmmKeysById.js rename to src/raydium/Pool/formatAmmKeysById.ts index da16b12..1a2636f 100644 --- a/src/raydium/Pool/formatAmmKeysById.js +++ b/src/raydium/Pool/formatAmmKeysById.ts @@ -1,4 +1,4 @@ -const { +import { LIQUIDITY_STATE_LAYOUT_V4, MARKET_STATE_LAYOUT_V3, SPL_MINT_LAYOUT, @@ -8,14 +8,14 @@ const { LiquidityStateV4, publicKey, struct, -} = require("@raydium-io/raydium-sdk"); -const { PublicKey } = require("@solana/web3.js"); +} from "@raydium-io/raydium-sdk"; +import { PublicKey } from "@solana/web3.js"; const MINIMAL_MARKET_STATE_LAYOUT_V3 = struct([ publicKey("eventQueue"), publicKey("bids"), publicKey("asks"), ]); -const { connection } = require("../../helpers/config"); +import { connection } from "../../helpers/config"; // Promise /** @@ -24,7 +24,7 @@ const { connection } = require("../../helpers/config"); * @returns {Object} - The formatted AMM keys. * @throws {Error} - If there is an error retrieving the account information. */ -async function formatAmmKeysById_swap(id) { +export async function formatAmmKeysById_swap(id:PublicKey) { const account = await connection.getAccountInfo(id); if (account === null) throw Error(" get id info error "); const info = LIQUIDITY_STATE_LAYOUT_V4.decode(account.data); @@ -84,7 +84,7 @@ async function formatAmmKeysById_swap(id) { }; } -async function formatAmmKeysById_pool(id) { +export async function formatAmmKeysById_pool(id:PublicKey) { const account = await connection.getAccountInfo(id); if (account === null) throw Error(" get id info error "); const info = LIQUIDITY_STATE_LAYOUT_V4.decode(account.data); @@ -134,4 +134,3 @@ async function formatAmmKeysById_pool(id) { }; } -module.exports = { formatAmmKeysById_swap, formatAmmKeysById_pool }; diff --git a/src/raydium/Pool/index.ts b/src/raydium/Pool/index.ts new file mode 100644 index 0000000..cada997 --- /dev/null +++ b/src/raydium/Pool/index.ts @@ -0,0 +1,4 @@ +export * from "./add_pool"; +export * from "./remove_pool"; +export * from "./formatAmmKeysById"; +export * from "./swap"; \ No newline at end of file diff --git a/src/raydium/Pool/query_pool.js b/src/raydium/Pool/query_pool.js deleted file mode 100644 index 281e64b..0000000 --- a/src/raydium/Pool/query_pool.js +++ /dev/null @@ -1,377 +0,0 @@ -const { Connection, PublicKey } = require("@solana/web3.js"); -const { OpenOrders } = require("@project-serum/serum"); -const { gql, GraphQLClient } = require("graphql-request"); -const { shyft_api_key } = require("../../helpers/config"); -const {Liquidity} = require("@raydium-io/raydium-sdk"); -const { token } = require("@metaplex-foundation/js"); -const {getDecimals} = require( - "../../helpers/util" -) -const graphQLEndpoint = `https://programs.shyft.to/v0/graphql/?api_key=${shyft_api_key}`; -const rpcEndpoint = `https://rpc.shyft.to/?api_key=${shyft_api_key}`; - - - -async function generateV4PoolInfo(tokenAddress) { - // RAY-USDC - const poolInfo = Liquidity.getAssociatedPoolKeys({ - version: 4, - marketVersion: 3, - baseMint: new PublicKey('So11111111111111111111111111111111111111112'), - quoteMint: new PublicKey(tokenAddress), - baseDecimals: await getDecimals(new PublicKey(tokenAddress)), - quoteDecimals: 9, - programId: new PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'), - - marketId: new PublicKey('DZjbn4XC8qoHKikZqzmhemykVzmossoayV9ffbsUqxVj'), - marketProgramId: new PublicKey('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX'), - }) - console.log(poolInfo) - return { poolInfo } -} - -async function howToUse() { - generateV4PoolInfo().then(({ poolInfo }) => { - console.log('poolInfo: ', poolInfo) - }) -} -const graphQLClient = new GraphQLClient(graphQLEndpoint, { - method: `POST`, - jsonSerializer: { - parse: JSON.parse, - stringify: JSON.stringify, - }, -}); -// Get Pools By Token Address -/** - * Queries the liquidity pool by token. - * @param {string} token - The token to query the liquidity pool for. - * @returns {Promise} - The response object containing the liquidity pool information. - */ -async function queryLpByToken(token) { - // Get all proposalsV2 accounts - const query = gql` - query MyQuery( - $where: Raydium_LiquidityPoolv4_bool_exp - $order_by: [Raydium_LiquidityPoolv4_order_by!] - ) { - Raydium_LiquidityPoolv4(where: $where, order_by: $order_by) { - _updatedAt - amountWaveRatio - baseDecimal - baseLotSize - baseMint - baseNeedTakePnl - baseTotalPnl - baseVault - depth - lpMint - lpReserve - lpVault - marketId - marketProgramId - maxOrder - maxPriceMultiplier - minPriceMultiplier - minSeparateDenominator - minSeparateNumerator - minSize - nonce - openOrders - orderbookToInitTime - owner - pnlDenominator - pnlNumerator - poolOpenTime - punishCoinAmount - punishPcAmount - quoteDecimal - quoteLotSize - quoteMint - quoteNeedTakePnl - quoteTotalPnl - quoteVault - resetFlag - state - status - swapBase2QuoteFee - swapBaseInAmount - swapBaseOutAmount - swapFeeDenominator - swapFeeNumerator - swapQuote2BaseFee - swapQuoteInAmount - swapQuoteOutAmount - systemDecimalValue - targetOrders - tradeFeeDenominator - tradeFeeNumerator - volMaxCutRatio - withdrawQueue - pubkey - } - } - `; - - const variables = { - where: { - baseMint: { - _eq: token, - }, - }, - order_by: [ - { - lpReserve: "desc", - }, - ], - }; - - const response = await graphQLClient.request(query, variables); - return response; -} -// Get Token Supply Percentage In Pool -/** - * Queries a liquidity pool by address. - * @param {string} address - The address of the liquidity pool. - * @returns {Promise} - The result of the GraphQL query. - */ -async function queryLpByAddress(address) { - // We only fetch fields necessary for us - const query = gql` - query MyQuery($where: Raydium_LiquidityPoolv4_bool_exp) { - Raydium_LiquidityPoolv4( - where: {pubkey: {_eq: ${JSON.stringify(address)}}} - ) { - baseDecimal - baseMint - baseNeedTakePnl - baseVault - marketId - marketProgramId - openOrders - quoteDecimal - quoteMint - quoteNeedTakePnl - quoteVault - } -}`; - - return await graphQLClient.request(query); -} - -//We have to check how much tokens are present in openbook market as well -/** - * Parses the pool information and calculates various metrics related to the pool. - * @param {Object} poolInfo - The pool information object. - * @returns {Promise} - A promise that resolves once the pool information is parsed. - */ -async function parsePoolInfo(poolInfo) { - const OPENBOOK_PROGRAM_ID = new PublicKey( - "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX" - ); - - //to load openOorders from openbook - const connection = new Connection(rpcEndpoint, "confirmed"); - - const openOrders = await OpenOrders.load( - connection, - new PublicKey(poolInfo.openOrders), - OPENBOOK_PROGRAM_ID - ); - - const baseDecimal = 10 ** poolInfo.baseDecimal; // e.g. 10 ^ 6 - const quoteDecimal = 10 ** poolInfo.quoteDecimal; - console.log("baseToken: ", poolInfo.baseMint); - console.log("quoteToken: ", poolInfo.quoteMint); - - const baseTokenAmount = await connection.getTokenAccountBalance( - new PublicKey(poolInfo.baseVault) - ); - const quoteTokenAmount = await connection.getTokenAccountBalance( - new PublicKey(poolInfo.quoteVault) - ); - - const basePnl = poolInfo.baseNeedTakePnl / baseDecimal; - const quotePnl = poolInfo.quoteNeedTakePnl / quoteDecimal; - - const openOrdersBaseTokenTotal = openOrders.baseTokenTotal / baseDecimal; - const openOrdersQuoteTokenTotal = openOrders.quoteTokenTotal / quoteDecimal; - - const base = - (baseTokenAmount.value?.uiAmount || 0) + openOrdersBaseTokenTotal - basePnl; - //You can do the same for quote tokens also. This doesnt work for SOL. - const quote = - (quoteTokenAmount.value?.uiAmount || 0) + - openOrdersQuoteTokenTotal - - quotePnl; - - //We get the current token supply through RPC and find the percentage - const baseSupply = await connection.getTokenSupply( - new PublicKey(poolInfo.baseMint) - ); - console.log(`Total Base tokens: ${baseSupply.value.uiAmount}`); - console.log(`Base tokens in Pool: ${base}`); - console.log( - `Pecentage of total base tokens in Pool: ${ - (base / baseSupply?.value?.uiAmount) * 100 - } %` - ); -} - -// Sort Liquidity Pools -/** - * Queries the liquidity pool for a given pair of tokens. - * @param {string} tokenOne - The first token of the pair. - * @param {string} tokenTwo - The second token of the pair. - * @returns {Promise} - The response object containing the liquidity pool data. - */ -async function queryLpPair(tokenOne, tokenTwo) { - const query = gql` - query MyQuery( - $where: Raydium_LiquidityPoolv4_bool_exp - $order_by: [Raydium_LiquidityPoolv4_order_by!] - ) { - Raydium_LiquidityPoolv4(where: $where, order_by: $order_by) { - amountWaveRatio - baseDecimal - baseLotSize - baseMint - baseNeedTakePnl - baseTotalPnl - baseVault - depth - lpMint - lpReserve - lpVault - marketId - marketProgramId - maxOrder - maxPriceMultiplier - minPriceMultiplier - minSeparateDenominator - minSeparateNumerator - minSize - nonce - openOrders - orderbookToInitTime - owner - pnlDenominator - pnlNumerator - poolOpenTime - punishCoinAmount - punishPcAmount - quoteDecimal - quoteLotSize - quoteMint - quoteNeedTakePnl - quoteTotalPnl - quoteVault - resetFlag - state - status - swapBase2QuoteFee - swapBaseInAmount - swapBaseOutAmount - swapFeeDenominator - swapFeeNumerator - swapQuote2BaseFee - swapQuoteInAmount - swapQuoteOutAmount - systemDecimalValue - targetOrders - tradeFeeDenominator - tradeFeeNumerator - volMaxCutRatio - withdrawQueue - pubkey - } - } - `; - - const variables = { - where: { - baseMint: { - _eq: tokenOne, - }, - quoteMint: { - _eq: tokenTwo, - }, - }, - order_by: [ - { - lpReserve: "desc", - }, - ], - }; - - const response = await graphQLClient.request(query, variables); - return response; -} -/** - * Retrieves the pool ID associated with the given token. - * @param {string} token - The token to query the pool ID for. - * @returns {Promise} The pool ID if found, or null if no pool is found. - */ -async function getPoolId(token) { - const poolId = await queryLpByToken(token); - if (poolId.Raydium_LiquidityPoolv4.length === 0) { - console.log(`Cannot find any liquidity pool related to ${token}`); - return null; - } - - return poolId.Raydium_LiquidityPoolv4[0].pubkey; -} - -/** - * Retrieves the pool ID for a given base token. - * @param {string} baseToken - The base token. - * @returns {string|null} - The pool ID if found, otherwise null. - */ -async function getPoolIdByPair(baseToken) { - // token/SOL pair - const quoteToken = "So11111111111111111111111111111111111111112"; - const poolId = await queryLpPair(baseToken, quoteToken); - if (poolId.Raydium_LiquidityPoolv4.length === 0) { - console.log( - `Cannot find any liquidity pool related to ${baseToken}/${quoteToken}` - ); - console.log(`It may be a token launched on pump.fun, we try to find ${quoteToken}/${baseToken}`) - const poolIdByPair = await queryLpPair(quoteToken, baseToken); - if (poolIdByPair.Raydium_LiquidityPoolv4.length === 0) { - console.log( - `Cannot find any liquidity pool related to ${quoteToken}/${baseToken}` - ); - throw new Error(`Cannot find any liquidity pool related to ${quoteToken}`); - return null; - }else{ - return poolIdByPair.Raydium_LiquidityPoolv4[0].pubkey; - } - return null; - } - return poolId.Raydium_LiquidityPoolv4[0].pubkey; -} -async function main() { - // getting the pool address for npch - //const poolId = await getPoolIdByPair("token_address") - //console.log(poolId) - // get token supply by token address - // const poolInfo: any = await queryLpByAddress('TOKEN_ADDRESS'); - // await parsePoolInfo(poolInfo.Raydium_LiquidityPoolv4[0]); - // get the pair of liquidity pool of two tokens - // like sol/slerf - // const poolIdByPair = await getPoolIdByPair( - // 'TOKEN_ADDRESS', - // 'So11111111111111111111111111111111111111112', - // ); - // console.log(poolIdByPair); - -} -//main().catch(console.error); -module.exports = { - getPoolIdByPair, - queryLpByToken, - queryLpByAddress, - parsePoolInfo, - queryLpPair, - getPoolId, -}; diff --git a/src/raydium/Pool/remove_pool.js b/src/raydium/Pool/remove_pool.ts similarity index 77% rename from src/raydium/Pool/remove_pool.js rename to src/raydium/Pool/remove_pool.ts index 11077e2..10285e5 100644 --- a/src/raydium/Pool/remove_pool.js +++ b/src/raydium/Pool/remove_pool.ts @@ -1,49 +1,49 @@ -const assert = require("assert"); +import assert from "assert"; -const { +import { jsonInfo2PoolKeys, Liquidity, LiquidityPoolKeys, TokenAmount, Token, TOKEN_PROGRAM_ID, -} = require("@raydium-io/raydium-sdk"); +} from "@raydium-io/raydium-sdk"; -const { Keypair, PublicKey } = require("@solana/web3.js"); -const { Decimal } = require("decimal.js"); -const { +import { Keypair, PublicKey } from "@solana/web3.js"; +import { Decimal } from "decimal.js"; +import { connection, DEFAULT_TOKEN, makeTxVersion, wallet, dev_connection, -} = require("../../helpers/config.js"); -const { +} from "../../helpers/config"; +import { formatAmmKeysById_pool, formatAmmKeysById_swap, -} = require("./formatAmmKeysById.js"); -const { +} from "./formatAmmKeysById"; +import { buildAndSendTx, getWalletTokenAccount, loadOrCreateKeypair_wallet, checkTx, -} = require("../../helpers/util.js"); -// const { +} from "../../helpers/util"; +// import { // getPoolId, // getPoolIdByPair, // queryLpByToken, // queryLpPair, -// } = require("./query_pool.js"); -const { fetchAMMPoolId, fetchLPToken} = require("./fetch_pool.js") -const { getSPLTokenBalance } = require("../helpers/check_balance.js"); -const { getDecimals, getTokenMetadata } = require("../helpers/util.js"); -const { BN } = require("@project-serum/anchor"); -const { program } = require("commander"); +// } from("./query_pool.js"); +import { fetchAMMPoolId, fetchLPToken} from "./fetch_pool"; +import { getSPLTokenBalance } from "../../helpers/check_balance"; +import { getDecimals, getTokenMetadata } from "../../helpers/util"; +import { BN } from "@project-serum/anchor"; +import { program } from "commander"; -let payer_keypair = null, - tokenAddress = null, - percentage = null, - cluster = null; +let payer_keypair:any = null, + tokenAddress:any = null, + percentage:any = null, + cluster:any = null; program .option("--payer ", "Specify the path to the secret key") .option("--token_address ", "Specify the token address") @@ -83,14 +83,14 @@ program.parse(); * @param {number} makeTxVersion - The transaction version. * @returns {Object} - The transaction IDs. */ -async function ammRemoveLiquidity(input) { +export async function ammRemoveLiquidity(input:any) { try { // -------- pre-action: fetch basic info -------- const targetPoolInfo = await formatAmmKeysById_pool(input.targetPool); assert(targetPoolInfo, "cannot find the target pool"); // -------- step 1: make instructions -------- - const poolKeys = jsonInfo2PoolKeys(targetPoolInfo); + const poolKeys:any = jsonInfo2PoolKeys(targetPoolInfo); const removeLiquidityInstructionResponse = await Liquidity.makeRemoveLiquidityInstructionSimple({ connection, @@ -114,14 +114,6 @@ async function ammRemoveLiquidity(input) { }; } catch (err) { console.log(err); - return { - txids: await buildAndSendTx( - removeLiquidityInstructionResponse.innerTransactions, - { - preflightCommitment: "confirmed", - } - ), - }; } } @@ -130,11 +122,10 @@ async function ammRemoveLiquidity(input) { * @param {string} tokenAddress - The token address. * @returns {string} - The LP token address. */ -async function findLPTokenAddress(tokenAddress) { - const response = await fetchLPToken(tokenAddress); +export async function findLPTokenAddress(tokenAddress:string) { + const response:any = await fetchLPToken(tokenAddress); console.log(response); - console.log(response.Raydium_LiquidityPoolv4[0].lpMint); - return response.Raydium_LiquidityPoolv4[0].lpMint; + return response; } /** @@ -142,12 +133,12 @@ async function findLPTokenAddress(tokenAddress) { * @param {Object} input - The input parameters for removing liquidity. * @returns {Promise} - A promise that resolves when the liquidity is removed. */ -async function ammRemoveLiquidityHelper(input) { - const { txids } = await ammRemoveLiquidity(input); - console.log("txids:", txids); - const response = await checkTx(txids[0]); +export async function ammRemoveLiquidityHelper(input:any) { + const res:any = await ammRemoveLiquidity(input); + console.log("txids:", res?.txids); + const response = await checkTx(res?.txids[0]); if (response) { - console.log(`https://explorer.solana.com/tx/${txids}?cluster=mainnet`); + console.log(`https://explorer.solana.com/tx/${res.txids}?cluster=mainnet`); } else { console.log("Transaction failed"); console.log("trying to send the transaction again"); diff --git a/src/raydium/Pool/swap.js b/src/raydium/Pool/swap.ts similarity index 86% rename from src/raydium/Pool/swap.js rename to src/raydium/Pool/swap.ts index 8d91e75..a58a416 100644 --- a/src/raydium/Pool/swap.js +++ b/src/raydium/Pool/swap.ts @@ -1,24 +1,24 @@ -const assert = require("assert"); +import assert from "assert"; -const { +import { Liquidity, Percent, Token, TOKEN_PROGRAM_ID, TokenAmount, -} = require("@raydium-io/raydium-sdk"); -const { +} from "@raydium-io/raydium-sdk"; +import { PublicKey, TransactionMessage, ComputeBudgetProgram, VersionedTransaction, LAMPORTS_PER_SOL, Transaction, -} = require("@solana/web3.js"); -const { Decimal } = require("decimal.js"); -const { BN } = require("@project-serum/anchor"); -const { getSPLTokenBalance } = require("../../helpers/check_balance.js"); -const { +} from "@solana/web3.js"; +import { Decimal } from "decimal.js"; +import { BN } from "@project-serum/anchor"; +import { getSPLTokenBalance } from "../../helpers/check_balance"; +import { connection, DEFAULT_TOKEN, makeTxVersion, @@ -26,30 +26,29 @@ const { _ENDPOINT, wallet, jito_fee, -} = require("../../helpers/config.js"); -const { +} from "../../helpers/config"; +import { getDecimals, getTokenMetadata, checkTx, -} = require("../../helpers/util.js"); -//const { getPoolId, getPoolIdByPair } = require("./query_pool.js"); -const { fetchAMMPoolId } = require("./fetch_pool.js"); -const { +} from "../../helpers/util"; +import { fetchAMMPoolId } from "./fetch_pool"; +import { getAssociatedTokenAddress, getAssociatedTokenAddressSync, createAssociatedTokenAccountIdempotentInstruction, createCloseAccountInstruction, -} = require("@solana/spl-token"); -const { mint } = require("@metaplex-foundation/mpl-candy-machine"); -const { formatAmmKeysById_swap } = require("./formatAmmKeysById.js"); -const { +} from "@solana/spl-token"; +import { formatAmmKeysById_swap } from "./formatAmmKeysById"; +import { simple_executeAndConfirm, -} = require("../../Transactions/simple_tx_executor.js"); -const { +} from "../../Transactions/simple_tx_executor"; +import { jito_executeAndConfirm, -} = require("../../Transactions/jito_tips_tx_executor.js"); -const {bloXroute_executeAndConfirm} = require("../../Transactions/bloXroute_tips_tx_executor.js") -let tokenToPoolIdMap = {}; +} from "../../Transactions/jito_tips_tx_executor"; +import {bloXroute_executeAndConfirm} from "../../Transactions/bloXroute_tips_tx_executor"; +import { Keypair } from "@solana/web3.js"; +let tokenToPoolIdMap:any = {}; /** * Performs a swap transaction using an Automated Market Maker (AMM) pool. @@ -64,10 +63,10 @@ let tokenToPoolIdMap = {}; * @param {string} input.side - The side of the swap transaction (e.g., "buy"). * @returns {Object} - The transaction ID if successful, otherwise null. */ -async function swapOnlyAmm(input) { +async function swapOnlyAmm(input:any) { // -------- pre-action: get pool info --------\ - const poolKeys = await formatAmmKeysById_swap( + const poolKeys:any = await formatAmmKeysById_swap( new PublicKey(input.targetPool) ); assert(poolKeys, "cannot find the target pool"); @@ -148,7 +147,7 @@ async function swapOnlyAmm(input) { console.log("jito fee transaction failed"); console.log(`Retry attempt ${attempts}`); } - } catch (e) { + } catch (e:any) { console.log(e); if (e.signature) { return { txid: e.signature }; @@ -160,8 +159,8 @@ async function swapOnlyAmm(input) { console.log("Transaction failed after maximum retry attempts"); return { txid: null }; } -async function swapOnlyAmmUsingBloXRoute(input) { - const poolKeys = await formatAmmKeysById_swap( +async function swapOnlyAmmUsingBloXRoute(input:any) { + const poolKeys:any = await formatAmmKeysById_swap( new PublicKey(input.targetPool) ); assert(poolKeys, "cannot find the target pool"); @@ -221,8 +220,8 @@ async function swapOnlyAmmUsingBloXRoute(input) { * @param {number} sol_per_order - The price of SOL per order. * @returns {Promise<{ confirmed: boolean, txid: string }>} The confirmation status and transaction ID. */ -async function swapForVolume(tokenAddr, sol_per_order) { - const buy_instruction = await swap( +export async function swapForVolume(tokenAddr:string, sol_per_order:number) { + const buy_instruction:any = await swap( "buy", tokenAddr, sol_per_order, @@ -230,7 +229,7 @@ async function swapForVolume(tokenAddr, sol_per_order) { wallet, "volume" ); - const sell_instruction = await swap( + const sell_instruction:any = await swap( "sell", tokenAddr, -1, @@ -265,10 +264,10 @@ async function swapForVolume(tokenAddr, sol_per_order) { let signature = null, confirmed = null; try { - const res = simple_executeAndConfirm(transaction, wallet, latestBlockhash); + const res:any = simple_executeAndConfirm(transaction, wallet, latestBlockhash); signature = res.signature; confirmed = res.confirmed; - } catch (e) { + } catch (e:any) { console.log(e); return { confirmed: confirmed, txid: e.signature }; } @@ -280,10 +279,10 @@ async function swapForVolume(tokenAddr, sol_per_order) { * @param {Object} input - The input object containing the necessary parameters for the swap. * @returns {Promise} - A promise that resolves when the swap is completed. */ -async function swapOnlyAmmHelper(input) { - const { txid } = await swapOnlyAmm(input); - console.log("txids:", txid); - const response = await checkTx(txid); +async function swapOnlyAmmHelper(input:any) { + const res:any = await swapOnlyAmm(input); + console.log("txids:", res.txid); + const response = await checkTx(res.txid); if (response) { if (input.side === "buy") { console.log( @@ -294,7 +293,7 @@ async function swapOnlyAmmHelper(input) { `https://dexscreener.com/solana/${input.targetPool}?maker=${wallet.publicKey}` ); } - console.log(`https://solscan.io/tx/${txid}?cluster=mainnet`); + console.log(`https://solscan.io/tx/${res.txid}?cluster=mainnet`); } else { console.log("Transaction failed"); } @@ -309,13 +308,13 @@ async function swapOnlyAmmHelper(input) { * @param {object} payer_wallet - The payer's wallet object. * @returns {Promise} - A promise that resolves when the swap operation is completed. */ -async function swap( - side, - tokenAddr, - buy_AmountOfSol, - sell_PercentageOfToken, - payer_wallet, - usage +export async function swap( + side:string, + tokenAddr:string, + buy_AmountOfSol:number, + sell_PercentageOfToken:number, + payer_wallet:Keypair, + usage:string ) { const tokenAddress = tokenAddr; const tokenAccount = new PublicKey(tokenAddress); @@ -338,11 +337,12 @@ async function swap( ); const inputToken = DEFAULT_TOKEN.WSOL; // SOL let targetPool = null; + console.log("Fetching pool id..."); if (!(tokenAddress in tokenToPoolIdMap)) { targetPool = await fetchAMMPoolId(tokenAddress); tokenToPoolIdMap[tokenAddress] = targetPool; } else targetPool = tokenToPoolIdMap[tokenAddress]; - + console.log("Pool id fetched."); if (targetPool === null) { console.log( "Pool not found or raydium is not supported for this token. Exiting..." @@ -382,11 +382,12 @@ async function swap( ); const outputToken = DEFAULT_TOKEN.WSOL; // SOL let targetPool = null; + console.log("Fetching pool id..."); if (!(tokenAddress in tokenToPoolIdMap)) { targetPool = await fetchAMMPoolId(tokenAddress); tokenToPoolIdMap[tokenAddress] = targetPool; } else targetPool = tokenToPoolIdMap[tokenAddress]; - + console.log("Pool id fetched."); if (targetPool === null) { console.log( "Pool not found or raydium is not supported for this token. Exiting..." @@ -426,5 +427,3 @@ async function swap( //swapOnlyAmmUsingBloXRoute(input); // using bloXroute } } - -module.exports = { swap, swapForVolume }; diff --git a/src/raydium/README.md b/src/raydium/README.md new file mode 100644 index 0000000..211525f --- /dev/null +++ b/src/raydium/README.md @@ -0,0 +1,65 @@ +# Raydium DEX Usage Examples + +### Buy token through cli +` +ts-node src/raydium/buy.ts --token_address --sol +` + +### Sell token through cli +` +ts-node src/raydium/sell.ts --token_address --percentage +` +### buy/sell token by calling the function +```typescript +import {buy, sell} from "../raydium"; +import {wallet} from "../helpers/config"; +async function main() { + const tokenAddress = "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"; + const sol = 1; // buy 1 SOL worth of token using WSOL + const sellPercentage = 50; // sell 50% of the token + await buy("buy", tokenAddress, sol, wallet); // buy 1 SOL worth of POPCAT + await sell("sell", tokenAddress, sellPercentage, wallet); // sell 50% of the POPCAT +} +``` + +### Fetch the price +```typescript +import {getCurrentPriceInUSD, getCurrentPriceInSOL} from "../raydium"; + +const currentPopcatPriceInSOL = await getCurrentPriceInSOL("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"); +const currentPopcatPriceInUSD = await getCurrentPriceInUSD("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"); + +console.log(currentPopcatPriceInSOL); +console.log(currentPopcatPriceInUSD); +``` + +### Fetch the pool address for the target token +```typescript +import {fetchAMMPoolId, fetchAMMPoolIdByMintPair} from "../raydium"; + +async function main(){ + const tokenAddress = "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"; + const poolId = await fetchAMMPoolId(tokenAddress); // output Address: POPCAT/WSOL or WSOL/POPCAT + const poolIdByMintPair = await fetchAMMPoolIdByMintPair(tokenAddress, "YOUR_MINT_ADDRESS"); // output Address: POPCAT/YOUR_MINT_ADDRESS or YOUR_MINT_ADDRESS/POPCAT + console.log(poolId); + console.log(poolIdByMintPair); +} +``` + +### Fetch the metrics of the pool +```typescript +import {getLPBurnPercentage, getCurrentMarketCap, getCurrentSolInPool, getDayVolume, getWeekVolume, getMonthVolume} from "../raydium"; + +async function main(){ + const tokenAddress = "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"; + const LPBurnPercentage = await getLPBurnPercentage(tokenAddress); // to get the percentage of LP tokens burned + const currentMarketCap = await getCurrentMarketCap(tokenAddress); // to get the current market cap of the token + const currentSolInPool = await getCurrentSolInPool(tokenAddress); // to get the current number of SOL in the pool + const dayVolume = await getDayVolume(tokenAddress); // to get the volume of the pool in the last 24 hours + const weekVolume = await getWeekVolume(tokenAddress); // to get the volume of the pool in the last week + const monthVolume = await getMonthVolume(tokenAddress); // to get the volume of the pool in the last month + // output ... +} +``` + + diff --git a/src/raydium/buy.js b/src/raydium/buy.ts similarity index 79% rename from src/raydium/buy.js rename to src/raydium/buy.ts index a9811a2..3b51382 100644 --- a/src/raydium/buy.js +++ b/src/raydium/buy.ts @@ -1,12 +1,13 @@ -const { swap } = require("./Pool/swap.js"); -const { program } = require("commander"); -const { loadOrCreateKeypair_wallet } = require("../helpers/util.js"); -const { wallet } = require("../helpers/config.js"); +import { swap } from "./Pool/swap"; +import { program } from "commander"; +import { loadOrCreateKeypair_wallet } from "../helpers/util"; +import { wallet } from "../helpers/config"; +import { Keypair } from "@solana/web3.js"; -let payer_keypair = null, - token_address = null, - sol = null, - cluster = null; +let payer_keypair:any = null, + token_address:any = null, + sol:any = null, + cluster:any = null; program .option("--payer ", "Specify the path to the secret key") .option("--token_address ", "Specify the token address") @@ -42,12 +43,13 @@ program.parse(); * @param {string} payer - The payer's keypair for the transaction. * @returns {Promise} - A promise that resolves when the swap is completed. */ -async function buy(side, address, no_of_sol, payer) { +async function buy(side:string, address:string, no_of_sol:number, payer:Keypair) { let payer_wallet = null; if (payer_keypair !== null) { payer_wallet = await loadOrCreateKeypair_wallet(payer_keypair); await swap(side, address, no_of_sol, -1, payer_wallet, "trade"); } else { + console.log("here") await swap(side, address, no_of_sol, -1, wallet, "trade"); } } diff --git a/src/raydium/buy_helper.js b/src/raydium/buy_helper.ts similarity index 67% rename from src/raydium/buy_helper.js rename to src/raydium/buy_helper.ts index 82c5f2f..854ba9a 100644 --- a/src/raydium/buy_helper.js +++ b/src/raydium/buy_helper.ts @@ -1,5 +1,5 @@ -const { Keypair } = require("@solana/web3.js"); -const { swap } = require("./Pool/swap"); +import { Keypair } from "@solana/web3.js"; +import { swap } from "./Pool/swap"; /** * Buys a specified amount of a token using a amount of sol. * @@ -9,15 +9,15 @@ const { swap } = require("./Pool/swap"); * @param {Keypair} payer - The payer of the transaction. * @returns {Promise} - A promise that resolves when the trade is completed. */ -async function buy(side, address, no_of_sol, payer) { +export async function buy(side:string, address:string, no_of_sol:number, payer:Keypair) { await swap(side, address, no_of_sol, -1, payer, "trade"); } -async function get_buy_transaction( - side, - tokenAddr, - buy_AmountOfSol, - payer_wallet +export async function get_buy_transaction( + side:string, + tokenAddr:string, + buy_AmountOfSol:number, + payer_wallet:Keypair ) { const innerTransaction = await swap( side, @@ -29,5 +29,3 @@ async function get_buy_transaction( ); return innerTransaction; } - -module.exports = { buy, get_buy_transaction }; diff --git a/src/raydium/constants.js b/src/raydium/constants.js deleted file mode 100644 index 9ace8e5..0000000 --- a/src/raydium/constants.js +++ /dev/null @@ -1,5 +0,0 @@ -const wsol = "So11111111111111111111111111111111111111112"; -const usdc = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; -const usdt = "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"; // USDT - -module.exports = {wsol, usdc, usdt} \ No newline at end of file diff --git a/src/raydium/constants.ts b/src/raydium/constants.ts new file mode 100644 index 0000000..bbd67fc --- /dev/null +++ b/src/raydium/constants.ts @@ -0,0 +1,3 @@ +export const wsol = "So11111111111111111111111111111111111111112"; +export const usdc = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; +export const usdt = "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"; // USDT diff --git a/src/raydium/fetch-price.js b/src/raydium/fetch-price.ts similarity index 80% rename from src/raydium/fetch-price.js rename to src/raydium/fetch-price.ts index fdfe368..842e697 100644 --- a/src/raydium/fetch-price.js +++ b/src/raydium/fetch-price.ts @@ -1,14 +1,15 @@ -const { initSdk } = require("./raydium_config"); -const {fetchAMMPoolId} = require("./Pool/fetch_pool"); -const Decimal = require("decimal.js"); -const {wsol} = require("./constants"); +import { initSdk } from "./raydium_config"; +import {fetchAMMPoolId} from "./Pool/fetch_pool"; +import Decimal from "decimal.js"; +import {wsol} from "./constants"; +import { sol } from "@metaplex-foundation/js"; let sdkCache = { sdk: null, expiry: 0 }; -async function getCurrentPriceInSOL( - tokenAddress +export async function getCurrentPriceInSOL( + tokenAddress:string ) { try { // Check if poolId is already set - let raydium = null; + let raydium:any = null; if (sdkCache.sdk) { raydium = sdkCache.sdk; } else { @@ -56,9 +57,9 @@ async function getCurrentPriceInSOL( console.log(`Error when getting current price of ${tokenAddress} `, e); } } -async function getCurrentSolPrice(){ +export async function getCurrentSolPrice(){ try{ - let raydium = null + let raydium:any = null if(sdkCache.sdk){ raydium = sdkCache.sdk; } @@ -80,7 +81,7 @@ async function getCurrentSolPrice(){ } -async function getCurrentPriceInUSD(tokenAddress){ +export async function getCurrentPriceInUSD(tokenAddress:string){ const priceInSOL = await getCurrentPriceInSOL(tokenAddress); const solPrice = await getCurrentSolPrice(); return priceInSOL * solPrice; @@ -90,8 +91,7 @@ async function getCurrentPriceInUSD(tokenAddress){ async function main(){ // console.log(await getCurrentPriceInSOL("3XTp12PmKMHxB6YkejaGPUjMGBLKRGgzHWgJuVTsBCoP")); // console.log(await getCurrentSolPrice()); - console.log(await getCurrentPriceInUSD("4MBEqrtgabZ9G5EmKm7XTrcknZ1nWg3TrvFHZMrENgrd")); + //console.log(await getCurrentPriceInUSD("4MBEqrtgabZ9G5EmKm7XTrcknZ1nWg3TrvFHZMrENgrd")); + //console.log(await getCurrentPriceInSOL("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr")); } -main(); - -module.exports = {getCurrentPriceInSOL, getCurrentSolPrice, getCurrentPriceInUSD}; \ No newline at end of file +//main(); diff --git a/src/raydium/index.ts b/src/raydium/index.ts new file mode 100644 index 0000000..9a5e521 --- /dev/null +++ b/src/raydium/index.ts @@ -0,0 +1,7 @@ +export * from "./sell_helper"; +export * from "./buy_helper"; +export * from "./raydium_config"; +export * from "./constants"; +export * from "./fetch-price"; +export * from "./Pool"; +export * from "./token-filters"; \ No newline at end of file diff --git a/src/raydium/raydium_config.js b/src/raydium/raydium_config.js deleted file mode 100644 index 13e0e55..0000000 --- a/src/raydium/raydium_config.js +++ /dev/null @@ -1,33 +0,0 @@ -const { - Raydium, - TxVersion, - parseTokenAccountResp, -} = require("@raydium-io/raydium-sdk-v2"); -const { TOKEN_PROGRAM_ID } = require("@solana/spl-token"); -const { - wallet, - connection, - second_connection, - third_connection, -} = require("../helpers/config"); - -const txVersion = TxVersion.V0; -const cluster = "mainnet"; -let raydium = Raydium | null; - -const initSdk = async (params) => { - if (raydium) return raydium; - - raydium = await Raydium.load({ - wallet, - connection, - cluster, - disableFeatureCheck: true, - disableLoadToken: !params?.loadToken, - blockhashCommitment: "finalized", - }); - - return raydium; -}; - -module.exports = { initSdk }; diff --git a/src/raydium/raydium_config.ts b/src/raydium/raydium_config.ts new file mode 100644 index 0000000..fff4f39 --- /dev/null +++ b/src/raydium/raydium_config.ts @@ -0,0 +1,22 @@ +import { + Raydium, + TxVersion, + parseTokenAccountResp, +} from "@raydium-io/raydium-sdk-v2"; +import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; +import { wallet, connection } from "../helpers/config"; + +const txVersion = TxVersion.V0; +const cluster = "mainnet"; +export const initSdk = async () => { + + const raydium = await Raydium.load({ + owner: wallet, + connection: connection, + cluster: cluster, + disableFeatureCheck: true, + disableLoadToken: true, + blockhashCommitment: "confirmed", + }); + return raydium; +}; diff --git a/src/raydium/sell.js b/src/raydium/sell.ts similarity index 79% rename from src/raydium/sell.js rename to src/raydium/sell.ts index 30b5c9e..eb59dae 100644 --- a/src/raydium/sell.js +++ b/src/raydium/sell.ts @@ -1,11 +1,12 @@ -const { swap } = require("./Pool/swap.js"); -const { program } = require("commander"); -const { loadOrCreateKeypair_wallet } = require("../helpers/util.js"); -const { wallet } = require("../helpers/config.js"); +import { swap } from "./Pool/swap"; +import { program } from "commander"; +import { loadOrCreateKeypair_wallet } from "../helpers/util"; +import { wallet } from "../helpers/config"; +import { Keypair } from "@solana/web3.js"; -let payer_keypair = null, - token_address = null, - percentage = null, +let payer_keypair:any = null, + token_address:any = null, + percentage:any = null, cluster = null; program .option("--payer ", "Specify the path to the secret key") @@ -13,7 +14,7 @@ program .option("--percentage ", "Specify the percentage") .option("--cluster ", "Specify the cluster") .option("-h, --help", "display help for command") - .action((options) => { + .action((options:any) => { if (options.help) { console.log( "node sell --payer --token_address --percentage --cluster " @@ -42,10 +43,10 @@ program.parse(); * @param {string} payer - The payer address for the transaction. * @returns {Promise} - A promise that resolves when the swap transaction is completed. */ -async function sell(side, address, sell_percentage, payer) { +export async function sell(side:string, address:string, sell_percentage:number, payer:Keypair) { await swap(side, address, -1, sell_percentage, payer, "trade"); } -async function main() { +export async function main() { let payer_wallet = null; if (payer_keypair !== null) { payer_wallet = await loadOrCreateKeypair_wallet(payer_keypair); // specified wallet by user in command diff --git a/src/raydium/sell_helper.js b/src/raydium/sell_helper.ts similarity index 68% rename from src/raydium/sell_helper.js rename to src/raydium/sell_helper.ts index 4d54967..59b8306 100644 --- a/src/raydium/sell_helper.js +++ b/src/raydium/sell_helper.ts @@ -1,4 +1,5 @@ -const { swap } = require("./Pool/swap"); +import { Keypair } from "@solana/web3.js"; +import { swap } from "./Pool/swap"; /** * Sells a specified percentage of a token. @@ -8,10 +9,10 @@ const { swap } = require("./Pool/swap"); * @param {string} payer - The payer of the transaction. * @returns {Promise} - A promise that resolves when the sell operation is complete. */ -async function sell(side, address, sell_percentage, payer) { +export async function sell(side:string, address:string, sell_percentage:number, payer:Keypair) { await swap(side, address, -1, sell_percentage, payer, "trade"); } -async function get_sell_transaction(side, tokenAddr, payer_wallet) { +export async function get_sell_transaction(side:string, tokenAddr:string, payer_wallet:Keypair) { const innerTransaction = await swap( side, tokenAddr, @@ -22,4 +23,3 @@ async function get_sell_transaction(side, tokenAddr, payer_wallet) { ); return innerTransaction; } -module.exports = { sell, get_sell_transaction }; diff --git a/src/raydium/token-filters/index.ts b/src/raydium/token-filters/index.ts new file mode 100644 index 0000000..c26d446 --- /dev/null +++ b/src/raydium/token-filters/index.ts @@ -0,0 +1,4 @@ +export * from "./lp-burn"; +export * from "./marketcap"; +export * from "./pool-sol"; +export * from "./volume"; \ No newline at end of file diff --git a/src/raydium/token-filters/lp-burn.js b/src/raydium/token-filters/lp-burn.ts similarity index 53% rename from src/raydium/token-filters/lp-burn.js rename to src/raydium/token-filters/lp-burn.ts index 5e91971..dd51b92 100644 --- a/src/raydium/token-filters/lp-burn.js +++ b/src/raydium/token-filters/lp-burn.ts @@ -1,14 +1,13 @@ -const { initSdk } = require("../raydium_config"); -const Decimal = require("decimal.js"); -const { wsol } = require("../constants"); -const { connection } = require("../../helpers/config"); -const { PublicKey } = require("@solana/web3.js"); -const { fetchAMMPoolId } = require("../Pool/fetch_pool"); -const { getDecimals } = require("../../helpers/util"); +import { initSdk } from "../raydium_config"; +import Decimal from "decimal.js"; +import { connection } from "../../helpers/config"; +import { PublicKey } from "@solana/web3.js"; +import { fetchAMMPoolId } from "../Pool/fetch_pool"; +import { getDecimals } from "../../helpers/util"; let sdkCache = { sdk: null, expiry: 0 }; -async function getLPBurnPercentage(tokenAddress) { +export async function getLPBurnPercentage(tokenAddress:string) { try { - let raydium = null; + let raydium:any = null; if (sdkCache.sdk) { raydium = sdkCache.sdk; } else { @@ -20,10 +19,10 @@ async function getLPBurnPercentage(tokenAddress) { const poolInfo = res[poolId]; const lpDecimals = await getDecimals(poolInfo.lpMint); const lpMint = poolInfo.lpMint.toString(); - const lpReserve = new Decimal(poolInfo.lpReserve.toString()).div( + const lpReserve:any = new Decimal(poolInfo.lpReserve.toString()).div( new Decimal(10).pow(lpDecimals) ); - const lpCurrentSupply = await connection.getTokenSupply( + const lpCurrentSupply:any = await connection.getTokenSupply( new PublicKey(lpMint) ); @@ -35,6 +34,5 @@ async function getLPBurnPercentage(tokenAddress) { console.log("Error getting current SOL in pool: ", e); } } -getLPBurnPercentage("3XTp12PmKMHxB6YkejaGPUjMGBLKRGgzHWgJuVTsBCoP"); +//getLPBurnPercentage("3XTp12PmKMHxB6YkejaGPUjMGBLKRGgzHWgJuVTsBCoP"); -module.exports = { getLPBurnPercentage }; diff --git a/src/raydium/token-filters/maker-count.js b/src/raydium/token-filters/maker-count.js deleted file mode 100644 index e69de29..0000000 diff --git a/src/jupiter/dca.js b/src/raydium/token-filters/maker-count.ts similarity index 100% rename from src/jupiter/dca.js rename to src/raydium/token-filters/maker-count.ts diff --git a/src/raydium/token-filters/marketcap.js b/src/raydium/token-filters/marketcap.ts similarity index 60% rename from src/raydium/token-filters/marketcap.js rename to src/raydium/token-filters/marketcap.ts index 96dd639..98e715b 100644 --- a/src/raydium/token-filters/marketcap.js +++ b/src/raydium/token-filters/marketcap.ts @@ -1,30 +1,14 @@ -const { initSdk } = require("../raydium_config"); -const Decimal = require("decimal.js"); -const { fetchAMMPoolId } = require("../Pool/fetch_pool"); -const { wsol } = require("../constants"); -const { connection } = require("../../helpers/config"); -const { PublicKey } = require("@solana/web3.js"); +import { initSdk } from "../raydium_config"; +import Decimal from "decimal.js"; +import { fetchAMMPoolId } from "../Pool/fetch_pool"; +import { wsol } from "../constants"; +import { connection } from "../../helpers/config"; +import { PublicKey } from "@solana/web3.js"; +import { getCurrentSolPrice } from "../fetch-price"; let sdkCache = { sdk: null, expiry: 0 }; -async function getCurrentSolPrice() { +export async function getCurrentMarketCap(tokenAddress:string) { try { - let raydium = null; - if (sdkCache.sdk) { - raydium = sdkCache.sdk; - } else { - raydium = await initSdk(); - sdkCache.sdk = raydium; - } - const sol_usdc = "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"; - const res = await raydium.liquidity.getRpcPoolInfos([sol_usdc]); - const poolInfo = res[sol_usdc]; - return poolInfo.poolPrice; - } catch (e) { - console.log("Error getting current SOL price: ", e); - } -} -async function getCurrentMarketCap(tokenAddress) { - try { - let raydium = null; + let raydium:any = null; if (sdkCache.sdk) { raydium = sdkCache.sdk; } else { @@ -63,16 +47,16 @@ async function getCurrentMarketCap(tokenAddress) { priceInSOL = poolInfo.poolPrice; } const priceInUSD = priceInSOL * (await getCurrentSolPrice()); + const supply:any = await connection.getTokenSupply(new PublicKey(tokenAddress)); const mc = priceInUSD * - (await connection.getTokenSupply(new PublicKey(tokenAddress))).value - .uiAmount; + supply.value.uiAmount; + console.log(`Current market cap of ${tokenAddress} is: ${mc}`); return mc; } catch (e) { console.log(`Error when getting current market cap of ${tokenAddress} `, e); } } -//getCurrentMarketCap("3XTp12PmKMHxB6YkejaGPUjMGBLKRGgzHWgJuVTsBCoP"); +//getCurrentMarketCap("7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr"); -module.exports = { getCurrentMarketCap, getCurrentSolPrice }; diff --git a/src/raydium/token-filters/pool-sol.js b/src/raydium/token-filters/pool-sol.ts similarity index 82% rename from src/raydium/token-filters/pool-sol.js rename to src/raydium/token-filters/pool-sol.ts index 8da004a..5661f40 100644 --- a/src/raydium/token-filters/pool-sol.js +++ b/src/raydium/token-filters/pool-sol.ts @@ -1,12 +1,12 @@ -const { initSdk } = require("../raydium_config"); -const Decimal = require("decimal.js"); -const { fetchAMMPoolId } = require("../Pool/fetch_pool"); -const { wsol } = require("../constants"); +import { initSdk } from "../raydium_config"; +import Decimal from "decimal.js"; +import { fetchAMMPoolId } from "../Pool/fetch_pool"; +import { wsol } from "../constants"; let sdkCache = { sdk: null, expiry: 0 }; -async function getCurrentSolInPool(tokenAddress) { +export async function getCurrentSolInPool(tokenAddress:string) { try { - let raydium = null; + let raydium:any = null; if (sdkCache.sdk) { raydium = sdkCache.sdk; } else { @@ -48,5 +48,4 @@ async function getCurrentSolInPool(tokenAddress) { } } -//getCurrentSolInPool("3XTp12PmKMHxB6YkejaGPUjMGBLKRGgzHWgJuVTsBCoP") -module.exports = { getCurrentSolInPool }; +//getCurrentSolInPool("3XTp12PmKMHxB6YkejaGPUjMGBLKRGgzHWgJuVTsBCoP"); diff --git a/src/raydium/token-filters/tx-count.js b/src/raydium/token-filters/tx-count.js deleted file mode 100644 index e69de29..0000000 diff --git a/src/jupiter/limit_order.js b/src/raydium/token-filters/tx-count.ts similarity index 100% rename from src/jupiter/limit_order.js rename to src/raydium/token-filters/tx-count.ts diff --git a/src/raydium/token-filters/volume.js b/src/raydium/token-filters/volume.ts similarity index 85% rename from src/raydium/token-filters/volume.js rename to src/raydium/token-filters/volume.ts index 56533b0..58c5e32 100644 --- a/src/raydium/token-filters/volume.js +++ b/src/raydium/token-filters/volume.ts @@ -1,6 +1,6 @@ const fetch = require('node-fetch'); -const {fetchAMMPoolId} = require("../Pool/fetch_pool") -async function getDayVolume(tokenAddress){ +import {fetchAMMPoolId} from "../Pool/fetch_pool"; +export async function getDayVolume(tokenAddress:string){ try{ const poolId = await fetchAMMPoolId(tokenAddress); let response = await( await fetch(`https://api-v3.raydium.io/pools/info/ids?ids=${poolId}`)).json(); @@ -11,6 +11,7 @@ async function getDayVolume(tokenAddress){ response = await( await fetch(`https://api-v3.raydium.io/pools/info/ids?ids=${poolId}`)).json(); if(response.success) dayVolume = response.data[0].day.volume } + console.log(dayVolume) if(dayVolume !== 0) return dayVolume; else{ dayVolume = response.data[0].day.volume @@ -20,7 +21,7 @@ async function getDayVolume(tokenAddress){ console.log("Error getting 24h volume: ", e) } } -async function getWeekVolume(tokenAddress){ +export async function getWeekVolume(tokenAddress:string){ try{ const poolId = await fetchAMMPoolId(tokenAddress); let response = await( await fetch(`https://api-v3.raydium.io/pools/info/ids?ids=${poolId}`)).json(); @@ -30,6 +31,7 @@ async function getWeekVolume(tokenAddress){ response = await( await fetch(`https://api-v3.raydium.io/pools/info/ids?ids=${poolId}`)).json(); if(response.success) weekVolume = response.data[0].week.volume } + console.log(weekVolume); if(weekVolume !== 0) return weekVolume; else{ weekVolume = response.data[0].week.volume @@ -41,7 +43,7 @@ async function getWeekVolume(tokenAddress){ } } -async function getMonthVolume(tokenAddress){ +export async function getMonthVolume(tokenAddress:string){ try{ const poolId = await fetchAMMPoolId(tokenAddress); let response = await( await fetch(`https://api-v3.raydium.io/pools/info/ids?ids=${poolId}`)).json(); @@ -51,6 +53,7 @@ async function getMonthVolume(tokenAddress){ response = await( await fetch(`https://api-v3.raydium.io/pools/info/ids?ids=${poolId}`)).json(); if(response.success) monthVolume = response.data[0].month.volume } + console.log(monthVolume); if(monthVolume !== 0) return monthVolume; else{ monthVolume = response.data[0].month.volume @@ -61,6 +64,4 @@ async function getMonthVolume(tokenAddress){ } } -//getDayVolume("3XTp12PmKMHxB6YkejaGPUjMGBLKRGgzHWgJuVTsBCoP") - -module.exports = {getDayVolume, getMonthVolume, getWeekVolume} \ No newline at end of file +getMonthVolume("GiMsMKgMq3cX3PJwPZCxh6CsrsVTc5P975eeAMPLpump"); \ No newline at end of file diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..7afecbe --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,2 @@ +export * from "../helpers/utils"; +export * from "../helpers/logger"; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2aaa2ed --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,110 @@ +{ + "include": ["./src/**/*.ts", "./src/**/**/*.ts","./src/**/**/**/*.ts","./src/**/**/**/**/*.ts", ], + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "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. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "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. */ + // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "resolveJsonModule": true, + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} \ No newline at end of file