diff --git a/.env.copy b/.env.copy index 9151800..ca7891c 100644 --- a/.env.copy +++ b/.env.copy @@ -10,4 +10,5 @@ CHECK_IF_MINT_IS_RENOUNCED=false AUTO_SELL=true MAX_SELL_RETRIES=5 AUTO_SELL_DELAY=1000 -LOG_LEVEL=info \ No newline at end of file +LOG_LEVEL=info +MIN_POOL_SIZE=10 \ No newline at end of file diff --git a/.gitignore b/.gitignore index f9c6030..e4ff98a 100644 --- a/.gitignore +++ b/.gitignore @@ -122,6 +122,9 @@ dist # Stores VSCode versions used for testing VSCode extensions .vscode-test +# PNPM +pnpm-lock.yaml + # yarn v2 .yarn/cache .yarn/unplugged diff --git a/README.md b/README.md index ed6f26c..9594037 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ To run the script you need to: - USE_SNIPE_LIST (buy only tokens listed in snipe-list.txt) - SNIPE_LIST_REFRESH_INTERVAL (how often snipe list should be refreshed in milliseconds) - CHECK_IF_MINT_IS_RENOUNCED (script will buy only if mint is renounced) + - MIN_POOL_SIZE (EXPERIMENTAL) (script will buy only if pool size is greater than specified amount) + - set to 0 to disable pool size check - Install dependencies by typing: `npm install` - Run the script by typing: `npm run buy` in terminal diff --git a/buy.ts b/buy.ts index 4921e2d..a0b496c 100644 --- a/buy.ts +++ b/buy.ts @@ -47,6 +47,7 @@ import { RPC_WEBSOCKET_ENDPOINT, SNIPE_LIST_REFRESH_INTERVAL, USE_SNIPE_LIST, + MIN_POOL_SIZE, } from './constants'; const solanaConnection = new Connection(RPC_ENDPOINT, { @@ -58,7 +59,7 @@ export interface MinimalTokenAccountData { address: PublicKey; poolKeys?: LiquidityPoolKeys; market?: MinimalMarketLayoutV3; -}; +} const existingLiquidityPools: Set = new Set(); const existingOpenBookMarkets: Set = new Set(); @@ -68,6 +69,7 @@ let wallet: Keypair; let quoteToken: Token; let quoteTokenAssociatedAddress: PublicKey; let quoteAmount: TokenAmount; +let quoteMinPoolSizeAmount: TokenAmount; let snipeList: string[] = []; @@ -83,6 +85,7 @@ async function init(): Promise { case 'WSOL': { quoteToken = Token.WSOL; quoteAmount = new TokenAmount(Token.WSOL, QUOTE_AMOUNT, false); + quoteMinPoolSizeAmount = new TokenAmount(quoteToken, MIN_POOL_SIZE, false); break; } case 'USDC': { @@ -94,6 +97,7 @@ async function init(): Promise { 'USDC', ); quoteAmount = new TokenAmount(quoteToken, QUOTE_AMOUNT, false); + quoteMinPoolSizeAmount = new TokenAmount(quoteToken, MIN_POOL_SIZE, false); break; } default: { @@ -101,9 +105,14 @@ async function init(): Promise { } } + logger.info(`Snipe list: ${USE_SNIPE_LIST}`); + logger.info(`Check mint renounced: ${CHECK_IF_MINT_IS_RENOUNCED}`); logger.info( - `Script will buy all new tokens using ${QUOTE_MINT}. Amount that will be used to buy each token is: ${quoteAmount.toFixed().toString()}`, + `Min pool size: ${quoteMinPoolSizeAmount.isZero() ? 'false' : quoteMinPoolSizeAmount.toFixed()} ${quoteToken.symbol}`, ); + logger.info(`Buy amount: ${quoteAmount.toFixed()} ${quoteToken.symbol}`); + logger.info(`Auto sell: ${AUTO_SELL}`); + logger.info(`Sell delay: ${AUTO_SELL_DELAY === 0 ? 'false' : AUTO_SELL_DELAY}`); // check existing wallet for associated token account of quote mint const tokenAccounts = await getTokenAccounts(solanaConnection, wallet.publicKey, COMMITMENT_LEVEL); @@ -147,6 +156,23 @@ export async function processRaydiumPool(id: PublicKey, poolState: LiquidityStat return; } + if (!quoteMinPoolSizeAmount.isZero()) { + const poolSize = new TokenAmount(quoteToken, poolState.swapQuoteInAmount, true); + logger.info(`Processing pool: ${id.toString()} with ${poolSize.toFixed()} ${quoteToken.symbol} in liquidity`); + + if (poolSize.lt(quoteMinPoolSizeAmount)) { + logger.warn( + { + mint: poolState.baseMint, + pooled: `${poolSize.toFixed()} ${quoteToken.symbol}`, + }, + `Skipping pool, smaller than ${quoteMinPoolSizeAmount.toFixed()} ${quoteToken.symbol}`, + `Swap quote in amount: ${poolSize.toFixed()}`, + ); + return; + } + } + if (CHECK_IF_MINT_IS_RENOUNCED) { const mintOption = await checkMintable(poolState.baseMint); @@ -355,6 +381,8 @@ async function sell(accountId: PublicKey, mint: PublicKey, amount: BigNumberish) ); sold = true; } catch (e: any) { + // wait for a bit before retrying + await new Promise((resolve) => setTimeout(resolve, 100)); retries++; logger.debug(e); logger.error({ mint }, `Failed to sell token, retry: ${retries}/${MAX_SELL_RETRIES}`); diff --git a/constants/constants.ts b/constants/constants.ts index c0eceb3..32ae760 100644 --- a/constants/constants.ts +++ b/constants/constants.ts @@ -14,4 +14,6 @@ export const MAX_SELL_RETRIES = Number(retrieveEnvVariable('MAX_SELL_RETRIES', l export const AUTO_SELL_DELAY = Number(retrieveEnvVariable('AUTO_SELL_DELAY', logger)); export const PRIVATE_KEY = retrieveEnvVariable('PRIVATE_KEY', logger); export const QUOTE_MINT = retrieveEnvVariable('QUOTE_MINT', logger); -export const QUOTE_AMOUNT = retrieveEnvVariable('QUOTE_AMOUNT', logger); \ No newline at end of file +export const QUOTE_AMOUNT = retrieveEnvVariable('QUOTE_AMOUNT', logger); +export const MIN_POOL_SIZE = retrieveEnvVariable('MIN_POOL_SIZE', logger); +