Merge pull request #78 from Journeytojah/master

Small improvements
This commit is contained in:
Alexandru Higyedi
2024-04-02 21:00:50 +07:00
committed by GitHub
4 changed files with 53 additions and 5 deletions

View File

@ -11,4 +11,6 @@ AUTO_SELL=true
MAX_SELL_RETRIES=5 MAX_SELL_RETRIES=5
AUTO_SELL_DELAY=1000 AUTO_SELL_DELAY=1000
LOG_LEVEL=info LOG_LEVEL=info
MIN_POOL_SIZE=10 MIN_POOL_SIZE=10
MAX_POOL_SIZE=50
ONE_TOKEN_AT_A_TIME=true

5
.gitignore vendored
View File

@ -133,4 +133,7 @@ pnpm-lock.yaml
.pnp.* .pnp.*
# JetBrains # JetBrains
.idea .idea
# Visual Studio Code
*.code-workspace

46
buy.ts
View File

@ -48,6 +48,8 @@ import {
SNIPE_LIST_REFRESH_INTERVAL, SNIPE_LIST_REFRESH_INTERVAL,
USE_SNIPE_LIST, USE_SNIPE_LIST,
MIN_POOL_SIZE, MIN_POOL_SIZE,
MAX_POOL_SIZE,
ONE_TOKEN_AT_A_TIME,
} from './constants'; } from './constants';
const solanaConnection = new Connection(RPC_ENDPOINT, { const solanaConnection = new Connection(RPC_ENDPOINT, {
@ -70,6 +72,10 @@ let quoteToken: Token;
let quoteTokenAssociatedAddress: PublicKey; let quoteTokenAssociatedAddress: PublicKey;
let quoteAmount: TokenAmount; let quoteAmount: TokenAmount;
let quoteMinPoolSizeAmount: TokenAmount; let quoteMinPoolSizeAmount: TokenAmount;
let quoteMaxPoolSizeAmount: TokenAmount;
let processingToken: Boolean = false;
let snipeList: string[] = []; let snipeList: string[] = [];
@ -86,6 +92,7 @@ async function init(): Promise<void> {
quoteToken = Token.WSOL; quoteToken = Token.WSOL;
quoteAmount = new TokenAmount(Token.WSOL, QUOTE_AMOUNT, false); quoteAmount = new TokenAmount(Token.WSOL, QUOTE_AMOUNT, false);
quoteMinPoolSizeAmount = new TokenAmount(quoteToken, MIN_POOL_SIZE, false); quoteMinPoolSizeAmount = new TokenAmount(quoteToken, MIN_POOL_SIZE, false);
quoteMaxPoolSizeAmount = new TokenAmount(quoteToken, MAX_POOL_SIZE, false);
break; break;
} }
case 'USDC': { case 'USDC': {
@ -98,6 +105,7 @@ async function init(): Promise<void> {
); );
quoteAmount = new TokenAmount(quoteToken, QUOTE_AMOUNT, false); quoteAmount = new TokenAmount(quoteToken, QUOTE_AMOUNT, false);
quoteMinPoolSizeAmount = new TokenAmount(quoteToken, MIN_POOL_SIZE, false); quoteMinPoolSizeAmount = new TokenAmount(quoteToken, MIN_POOL_SIZE, false);
quoteMaxPoolSizeAmount = new TokenAmount(quoteToken, MAX_POOL_SIZE, false);
break; break;
} }
default: { default: {
@ -110,6 +118,10 @@ async function init(): Promise<void> {
logger.info( logger.info(
`Min pool size: ${quoteMinPoolSizeAmount.isZero() ? 'false' : quoteMinPoolSizeAmount.toFixed()} ${quoteToken.symbol}`, `Min pool size: ${quoteMinPoolSizeAmount.isZero() ? 'false' : quoteMinPoolSizeAmount.toFixed()} ${quoteToken.symbol}`,
); );
logger.info(
`Max pool size: ${quoteMaxPoolSizeAmount.isZero() ? 'false' : quoteMaxPoolSizeAmount.toFixed()} ${quoteToken.symbol}`,
);
logger.info(`One token at a time: ${ONE_TOKEN_AT_A_TIME}`);
logger.info(`Buy amount: ${quoteAmount.toFixed()} ${quoteToken.symbol}`); logger.info(`Buy amount: ${quoteAmount.toFixed()} ${quoteToken.symbol}`);
logger.info(`Auto sell: ${AUTO_SELL}`); logger.info(`Auto sell: ${AUTO_SELL}`);
logger.info(`Sell delay: ${AUTO_SELL_DELAY === 0 ? 'false' : AUTO_SELL_DELAY}`); logger.info(`Sell delay: ${AUTO_SELL_DELAY === 0 ? 'false' : AUTO_SELL_DELAY}`);
@ -169,6 +181,24 @@ export async function processRaydiumPool(id: PublicKey, poolState: LiquidityStat
`Skipping pool, smaller than ${quoteMinPoolSizeAmount.toFixed()} ${quoteToken.symbol}`, `Skipping pool, smaller than ${quoteMinPoolSizeAmount.toFixed()} ${quoteToken.symbol}`,
`Swap quote in amount: ${poolSize.toFixed()}`, `Swap quote in amount: ${poolSize.toFixed()}`,
); );
logger.info(`-------------------🤖🔧------------------- \n`);
return;
}
}
if (!quoteMaxPoolSizeAmount.isZero()) {
const poolSize = new TokenAmount(quoteToken, poolState.swapQuoteInAmount, true);
if (poolSize.gt(quoteMaxPoolSizeAmount)) {
logger.warn(
{
mint: poolState.baseMint,
pooled: `${poolSize.toFixed()} ${quoteToken.symbol}`,
},
`Skipping pool, bigger than ${quoteMaxPoolSizeAmount.toFixed()} ${quoteToken.symbol}`,
`Swap quote in amount: ${poolSize.toFixed()}`,
);
logger.info(`-------------------🤖🔧------------------- \n`);
return; return;
} }
} }
@ -265,6 +295,8 @@ async function buy(accountId: PublicKey, accountData: LiquidityStateV4): Promise
preflightCommitment: COMMITMENT_LEVEL, preflightCommitment: COMMITMENT_LEVEL,
}); });
logger.info({ mint: accountData.baseMint, signature }, `Sent buy tx`); logger.info({ mint: accountData.baseMint, signature }, `Sent buy tx`);
processingToken = true;
const confirmation = await solanaConnection.confirmTransaction( const confirmation = await solanaConnection.confirmTransaction(
{ {
signature, signature,
@ -274,6 +306,7 @@ async function buy(accountId: PublicKey, accountData: LiquidityStateV4): Promise
COMMITMENT_LEVEL, COMMITMENT_LEVEL,
); );
if (!confirmation.value.err) { if (!confirmation.value.err) {
logger.info(`-------------------🟢------------------- `);
logger.info( logger.info(
{ {
mint: accountData.baseMint, mint: accountData.baseMint,
@ -288,6 +321,7 @@ async function buy(accountId: PublicKey, accountData: LiquidityStateV4): Promise
} }
} catch (e) { } catch (e) {
logger.debug(e); logger.debug(e);
processingToken = false;
logger.error({ mint: accountData.baseMint }, `Failed to buy token`); logger.error({ mint: accountData.baseMint }, `Failed to buy token`);
} }
} }
@ -369,7 +403,7 @@ async function sell(accountId: PublicKey, mint: PublicKey, amount: BigNumberish)
logger.info({ mint, signature }, `Error confirming sell tx`); logger.info({ mint, signature }, `Error confirming sell tx`);
continue; continue;
} }
logger.info(`-------------------🔴------------------- `);
logger.info( logger.info(
{ {
dex: `https://dexscreener.com/solana/${mint}?maker=${wallet.publicKey}`, dex: `https://dexscreener.com/solana/${mint}?maker=${wallet.publicKey}`,
@ -380,6 +414,7 @@ async function sell(accountId: PublicKey, mint: PublicKey, amount: BigNumberish)
`Confirmed sell tx`, `Confirmed sell tx`,
); );
sold = true; sold = true;
processingToken = false;
} catch (e: any) { } catch (e: any) {
// wait for a bit before retrying // wait for a bit before retrying
await new Promise((resolve) => setTimeout(resolve, 100)); await new Promise((resolve) => setTimeout(resolve, 100));
@ -388,6 +423,7 @@ async function sell(accountId: PublicKey, mint: PublicKey, amount: BigNumberish)
logger.error({ mint }, `Failed to sell token, retry: ${retries}/${MAX_SELL_RETRIES}`); logger.error({ mint }, `Failed to sell token, retry: ${retries}/${MAX_SELL_RETRIES}`);
} }
} while (!sold && retries < MAX_SELL_RETRIES); } while (!sold && retries < MAX_SELL_RETRIES);
processingToken = false;
} }
function loadSnipeList() { function loadSnipeList() {
@ -408,7 +444,9 @@ function loadSnipeList() {
} }
function shouldBuy(key: string): boolean { function shouldBuy(key: string): boolean {
return USE_SNIPE_LIST ? snipeList.includes(key) : true; logger.info(`-------------------🤖🔧------------------- `);
logger.info(`Processing token: ${processingToken}`)
return USE_SNIPE_LIST ? snipeList.includes(key) : ONE_TOKEN_AT_A_TIME ? !processingToken : true
} }
const runListener = async () => { const runListener = async () => {
@ -505,6 +543,10 @@ const runListener = async () => {
logger.info(`Listening for raydium changes: ${raydiumSubscriptionId}`); logger.info(`Listening for raydium changes: ${raydiumSubscriptionId}`);
logger.info(`Listening for open book changes: ${openBookSubscriptionId}`); logger.info(`Listening for open book changes: ${openBookSubscriptionId}`);
logger.info('------------------- 🚀 ---------------------');
logger.info('Bot is running! Press CTRL + C to stop it.');
logger.info('------------------- 🚀 ---------------------');
if (USE_SNIPE_LIST) { if (USE_SNIPE_LIST) {
setInterval(loadSnipeList, SNIPE_LIST_REFRESH_INTERVAL); setInterval(loadSnipeList, SNIPE_LIST_REFRESH_INTERVAL);
} }

View File

@ -16,4 +16,5 @@ export const PRIVATE_KEY = retrieveEnvVariable('PRIVATE_KEY', logger);
export const QUOTE_MINT = retrieveEnvVariable('QUOTE_MINT', logger); export const QUOTE_MINT = retrieveEnvVariable('QUOTE_MINT', logger);
export const QUOTE_AMOUNT = retrieveEnvVariable('QUOTE_AMOUNT', logger); export const QUOTE_AMOUNT = retrieveEnvVariable('QUOTE_AMOUNT', logger);
export const MIN_POOL_SIZE = retrieveEnvVariable('MIN_POOL_SIZE', logger); export const MIN_POOL_SIZE = retrieveEnvVariable('MIN_POOL_SIZE', logger);
export const MAX_POOL_SIZE = retrieveEnvVariable('MAX_POOL_SIZE', logger);
export const ONE_TOKEN_AT_A_TIME = retrieveEnvVariable('ONE_TOKEN_AT_A_TIME', logger) === 'true';