mirror of
https://github.com/fdundjer/solana-sniper-bot.git
synced 2025-11-10 04:22:05 +10:00
feat: real time filtering
This commit is contained in:
15
.env.copy
15
.env.copy
@ -24,22 +24,25 @@ QUOTE_MINT=WSOL
|
|||||||
QUOTE_AMOUNT=0.001
|
QUOTE_AMOUNT=0.001
|
||||||
AUTO_BUY_DELAY=0
|
AUTO_BUY_DELAY=0
|
||||||
MAX_BUY_RETRIES=10
|
MAX_BUY_RETRIES=10
|
||||||
BUY_SLIPPAGE=5
|
BUY_SLIPPAGE=20
|
||||||
|
|
||||||
# Sell
|
# Sell
|
||||||
AUTO_SELL=true
|
AUTO_SELL=true
|
||||||
MAX_SELL_RETRIES=10
|
MAX_SELL_RETRIES=10
|
||||||
AUTO_SELL_DELAY=0
|
AUTO_SELL_DELAY=0
|
||||||
PRICE_CHECK_INTERVAL=2000
|
PRICE_CHECK_INTERVAL=2000
|
||||||
PRICE_CHECK_DURATION=60000
|
PRICE_CHECK_DURATION=600000
|
||||||
TAKE_PROFIT=20
|
TAKE_PROFIT=40
|
||||||
STOP_LOSS=15
|
STOP_LOSS=20
|
||||||
SELL_SLIPPAGE=5
|
SELL_SLIPPAGE=20
|
||||||
|
|
||||||
# Filters
|
# Filters
|
||||||
USE_SNIPE_LIST=false
|
USE_SNIPE_LIST=false
|
||||||
SNIPE_LIST_REFRESH_INTERVAL=30000
|
SNIPE_LIST_REFRESH_INTERVAL=30000
|
||||||
|
FILTER_CHECK_DURATION=60000
|
||||||
|
FILTER_CHECK_INTERVAL=2000
|
||||||
|
CONSECUTIVE_FILTER_MATCHES=3
|
||||||
CHECK_IF_MINT_IS_RENOUNCED=true
|
CHECK_IF_MINT_IS_RENOUNCED=true
|
||||||
CHECK_IF_BURNED=false
|
CHECK_IF_BURNED=true
|
||||||
MIN_POOL_SIZE=5
|
MIN_POOL_SIZE=5
|
||||||
MAX_POOL_SIZE=50
|
MAX_POOL_SIZE=50
|
||||||
24
README.md
24
README.md
@ -1,11 +1,9 @@
|
|||||||
|
|
||||||
# Solana Sniper Bot (Poc)
|
# Solana Trading Bot (Beta)
|
||||||
This code is written as proof of concept to demonstrate how we can buy new tokens immediately after the liquidity pool is open for trading.
|
The Solana Trading Bot is a software tool designed to automate the buying and selling of tokens on the Solana blockchain.
|
||||||
|
It is configured to execute trades based on predefined parameters and strategies set by the user.
|
||||||
|
|
||||||
Script listens to new Raydium USDC or SOL pools and buys tokens for a fixed amount in USDC/SOL.
|
The bot can monitor market conditions in real-time, such as pool burn, mint renounced and other factors, and it will execute trades when these conditions are fulfilled.
|
||||||
Depending on the speed of the RPC node, the purchase usually happens before the token is available on Raydium UI for swapping.
|
|
||||||
|
|
||||||
This is provided as is, for learning purposes.
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
To run the script you need to:
|
To run the script you need to:
|
||||||
@ -55,11 +53,14 @@ You should see the following output:
|
|||||||
|
|
||||||
#### Sell
|
#### Sell
|
||||||
- `AUTO_SELL` - Set to `true` to enable automatic selling of tokens.
|
- `AUTO_SELL` - Set to `true` to enable automatic selling of tokens.
|
||||||
|
- If you want to manually sell bought tokens, disable this option.
|
||||||
- `MAX_SELL_RETRIES` - Maximum number of retries for selling a token.
|
- `MAX_SELL_RETRIES` - Maximum number of retries for selling a token.
|
||||||
- `AUTO_SELL_DELAY` - Delay in milliseconds before auto-selling a token.
|
- `AUTO_SELL_DELAY` - Delay in milliseconds before auto-selling a token.
|
||||||
- `PRICE_CHECK_INTERVAL` - Interval in milliseconds for checking the take profit and stop loss conditions.
|
- `PRICE_CHECK_INTERVAL` - Interval in milliseconds for checking the take profit and stop loss conditions.
|
||||||
|
- Set to zero to disable take profit and stop loss.
|
||||||
- `PRICE_CHECK_DURATION` - Time in milliseconds to wait for stop loss/take profit conditions.
|
- `PRICE_CHECK_DURATION` - Time in milliseconds to wait for stop loss/take profit conditions.
|
||||||
- If you don't reach profit or loss bot will auto sell after this time.
|
- If you don't reach profit or loss bot will auto sell after this time.
|
||||||
|
- Set to zero to disable take profit and stop loss.
|
||||||
- `TAKE_PROFIT` - Percentage profit at which to take profit.
|
- `TAKE_PROFIT` - Percentage profit at which to take profit.
|
||||||
- Take profit is calculated based on quote mint.
|
- Take profit is calculated based on quote mint.
|
||||||
- `STOP_LOSS` - Percentage loss at which to stop the loss.
|
- `STOP_LOSS` - Percentage loss at which to stop the loss.
|
||||||
@ -67,6 +68,13 @@ You should see the following output:
|
|||||||
- `SELL_SLIPPAGE` - Slippage %.
|
- `SELL_SLIPPAGE` - Slippage %.
|
||||||
|
|
||||||
#### Filters
|
#### Filters
|
||||||
|
- `FILTER_CHECK_INTERVAL` - Interval in milliseconds for checking if pool match the filters.
|
||||||
|
- Set to zero to disable filters.
|
||||||
|
- `FILTER_CHECK_DURATION` - Time in milliseconds to wait for pool to match the filters.
|
||||||
|
- If pool doesn't match the filter buy will not happen.
|
||||||
|
- Set to zero to disable filters.
|
||||||
|
- `CONSECUTIVE_FILTER_MATCHES` - How many times in a row pool needs to match the filters.
|
||||||
|
- This is useful because when pool is burned (and rugged), other filters may not report the same behavior because of distributed RPC endpoints (eg. helius network)
|
||||||
- `USE_SNIPE_LIST` - Set to `true` to enable buying only tokens listed in `snipe-list.txt`.
|
- `USE_SNIPE_LIST` - Set to `true` to enable buying only tokens listed in `snipe-list.txt`.
|
||||||
- Pool must not exist before the script starts.
|
- Pool must not exist before the script starts.
|
||||||
- `SNIPE_LIST_REFRESH_INTERVAL` - Interval in milliseconds to refresh the snipe list.
|
- `SNIPE_LIST_REFRESH_INTERVAL` - Interval in milliseconds to refresh the snipe list.
|
||||||
@ -123,4 +131,6 @@ To collect more information on an issue, please change `LOG_LEVEL` to `debug`.
|
|||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
Use this script at your own risk.
|
The Solana Trading Bot is provided as is, for learning purposes.
|
||||||
|
Trading cryptocurrencies and tokens involves risk, and past performance is not indicative of future results.
|
||||||
|
The use of this bot is at your own risk, and we are not responsible for any losses incurred while using the bot.
|
||||||
61
bot.ts
61
bot.ts
@ -47,6 +47,9 @@ export interface BotConfig {
|
|||||||
sellSlippage: number;
|
sellSlippage: number;
|
||||||
priceCheckInterval: number;
|
priceCheckInterval: number;
|
||||||
priceCheckDuration: number;
|
priceCheckDuration: number;
|
||||||
|
filterCheckInterval: number;
|
||||||
|
filterCheckDuration: number;
|
||||||
|
consecutiveMatchCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Bot {
|
export class Bot {
|
||||||
@ -120,15 +123,6 @@ export class Bot {
|
|||||||
await this.mutex.acquire();
|
await this.mutex.acquire();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
const shouldBuy = await this.poolFilters.execute(poolState);
|
|
||||||
|
|
||||||
if (!shouldBuy) {
|
|
||||||
logger.debug({ mint: poolState.baseMint.toString() }, `Skipping buy because pool doesn't match filters`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < this.config.maxBuyRetries; i++) {
|
|
||||||
try {
|
try {
|
||||||
const [market, mintAta] = await Promise.all([
|
const [market, mintAta] = await Promise.all([
|
||||||
this.marketStorage.get(poolState.marketId.toString()),
|
this.marketStorage.get(poolState.marketId.toString()),
|
||||||
@ -136,6 +130,15 @@ export class Bot {
|
|||||||
]);
|
]);
|
||||||
const poolKeys: LiquidityPoolKeysV4 = createPoolKeys(accountId, poolState, market);
|
const poolKeys: LiquidityPoolKeysV4 = createPoolKeys(accountId, poolState, market);
|
||||||
|
|
||||||
|
const match = await this.filterMatch(poolKeys);
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
logger.trace({ mint: poolKeys.baseMint.toString() }, `Skipping buy because pool doesn't match filters`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < this.config.maxBuyRetries; i++) {
|
||||||
|
try {
|
||||||
logger.info(
|
logger.info(
|
||||||
{ mint: poolState.baseMint.toString() },
|
{ mint: poolState.baseMint.toString() },
|
||||||
`Send buy transaction attempt: ${i + 1}/${this.config.maxBuyRetries}`,
|
`Send buy transaction attempt: ${i + 1}/${this.config.maxBuyRetries}`,
|
||||||
@ -214,13 +217,13 @@ export class Bot {
|
|||||||
await sleep(this.config.autoSellDelay);
|
await sleep(this.config.autoSellDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < this.config.maxSellRetries; i++) {
|
|
||||||
try {
|
|
||||||
const market = await this.marketStorage.get(poolData.state.marketId.toString());
|
const market = await this.marketStorage.get(poolData.state.marketId.toString());
|
||||||
const poolKeys: LiquidityPoolKeysV4 = createPoolKeys(new PublicKey(poolData.id), poolData.state, market);
|
const poolKeys: LiquidityPoolKeysV4 = createPoolKeys(new PublicKey(poolData.id), poolData.state, market);
|
||||||
|
|
||||||
await this.priceMatch(tokenAmountIn, poolKeys);
|
await this.priceMatch(tokenAmountIn, poolKeys);
|
||||||
|
|
||||||
|
for (let i = 0; i < this.config.maxSellRetries; i++) {
|
||||||
|
try {
|
||||||
logger.info(
|
logger.info(
|
||||||
{ mint: rawAccount.mint },
|
{ mint: rawAccount.mint },
|
||||||
`Send sell transaction attempt: ${i + 1}/${this.config.maxSellRetries}`,
|
`Send sell transaction attempt: ${i + 1}/${this.config.maxSellRetries}`,
|
||||||
@ -342,6 +345,42 @@ export class Bot {
|
|||||||
return this.txExecutor.executeAndConfirm(transaction, wallet, latestBlockhash);
|
return this.txExecutor.executeAndConfirm(transaction, wallet, latestBlockhash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async filterMatch(poolKeys: LiquidityPoolKeysV4) {
|
||||||
|
if (this.config.filterCheckInterval === 0 || this.config.filterCheckDuration === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timesToCheck = this.config.filterCheckDuration / this.config.filterCheckInterval;
|
||||||
|
let timesChecked = 0;
|
||||||
|
let matchCount = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
const shouldBuy = await this.poolFilters.execute(poolKeys);
|
||||||
|
|
||||||
|
if (shouldBuy) {
|
||||||
|
matchCount++;
|
||||||
|
|
||||||
|
if (this.config.consecutiveMatchCount <= matchCount) {
|
||||||
|
logger.debug(
|
||||||
|
{ mint: poolKeys.baseMint.toString() },
|
||||||
|
`Filter match ${matchCount}/${this.config.consecutiveMatchCount}`,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
matchCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
await sleep(this.config.filterCheckInterval);
|
||||||
|
} finally {
|
||||||
|
timesChecked++;
|
||||||
|
}
|
||||||
|
} while (timesChecked < timesToCheck);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private async priceMatch(amountIn: TokenAmount, poolKeys: LiquidityPoolKeysV4) {
|
private async priceMatch(amountIn: TokenAmount, poolKeys: LiquidityPoolKeysV4) {
|
||||||
if (this.config.priceCheckDuration === 0 || this.config.priceCheckInterval === 0) {
|
if (this.config.priceCheckDuration === 0 || this.config.priceCheckInterval === 0) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import { Filter, FilterResult } from './pool-filters';
|
import { Filter, FilterResult } from './pool-filters';
|
||||||
import { Connection } from '@solana/web3.js';
|
import { Connection } from '@solana/web3.js';
|
||||||
import { LiquidityStateV4 } from '@raydium-io/raydium-sdk';
|
import { LiquidityPoolKeysV4 } from '@raydium-io/raydium-sdk';
|
||||||
import { logger } from '../helpers';
|
import { logger } from '../helpers';
|
||||||
|
|
||||||
export class BurnFilter implements Filter {
|
export class BurnFilter implements Filter {
|
||||||
constructor(private readonly connection: Connection) {}
|
constructor(private readonly connection: Connection) {}
|
||||||
|
|
||||||
async execute(poolState: LiquidityStateV4): Promise<FilterResult> {
|
async execute(poolKeys: LiquidityPoolKeysV4): Promise<FilterResult> {
|
||||||
try {
|
try {
|
||||||
const amount = await this.connection.getTokenSupply(poolState.lpMint, this.connection.commitment);
|
const amount = await this.connection.getTokenSupply(poolKeys.lpMint, this.connection.commitment);
|
||||||
const burned = amount.value.uiAmount === 0;
|
const burned = amount.value.uiAmount === 0;
|
||||||
return { ok: burned, message: burned ? undefined : "Burned -> Creator didn't burn LP" };
|
return { ok: burned, message: burned ? undefined : "Burned -> Creator didn't burn LP" };
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@ -16,7 +16,7 @@ export class BurnFilter implements Filter {
|
|||||||
return { ok: true };
|
return { ok: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.error({ mint: poolState.baseMint }, `Failed to check if LP is burned`);
|
logger.error({ mint: poolKeys.baseMint }, `Failed to check if LP is burned`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ok: false, message: 'Failed to check if LP is burned' };
|
return { ok: false, message: 'Failed to check if LP is burned' };
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { Connection } from '@solana/web3.js';
|
import { Connection } from '@solana/web3.js';
|
||||||
import { LiquidityStateV4, Token, TokenAmount } from '@raydium-io/raydium-sdk';
|
import { LiquidityPoolKeysV4, Token, TokenAmount } from '@raydium-io/raydium-sdk';
|
||||||
import { BurnFilter } from './burn.filter';
|
import { BurnFilter } from './burn.filter';
|
||||||
import { RenouncedFilter } from './renounced.filter';
|
import { RenouncedFilter } from './renounced.filter';
|
||||||
import { PoolSizeFilter } from './pool-size.filter';
|
import { PoolSizeFilter } from './pool-size.filter';
|
||||||
import { CHECK_IF_BURNED, CHECK_IF_MINT_IS_RENOUNCED, logger } from '../helpers';
|
import { CHECK_IF_BURNED, CHECK_IF_MINT_IS_RENOUNCED, logger } from '../helpers';
|
||||||
|
|
||||||
export interface Filter {
|
export interface Filter {
|
||||||
execute(poolState: LiquidityStateV4): Promise<FilterResult>;
|
execute(poolKeysV4: LiquidityPoolKeysV4): Promise<FilterResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FilterResult {
|
export interface FilterResult {
|
||||||
@ -40,12 +40,12 @@ export class PoolFilters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async execute(poolState: LiquidityStateV4): Promise<boolean> {
|
public async execute(poolKeys: LiquidityPoolKeysV4): Promise<boolean> {
|
||||||
if (this.filters.length === 0) {
|
if (this.filters.length === 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await Promise.all(this.filters.map((f) => f.execute(poolState)));
|
const result = await Promise.all(this.filters.map((f) => f.execute(poolKeys)));
|
||||||
const pass = result.every((r) => r.ok);
|
const pass = result.every((r) => r.ok);
|
||||||
|
|
||||||
if (pass) {
|
if (pass) {
|
||||||
@ -53,7 +53,7 @@ export class PoolFilters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const filterResult of result.filter((r) => !r.ok)) {
|
for (const filterResult of result.filter((r) => !r.ok)) {
|
||||||
logger.info(filterResult.message);
|
logger.trace(filterResult.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Filter, FilterResult } from './pool-filters';
|
import { Filter, FilterResult } from './pool-filters';
|
||||||
import { LiquidityStateV4, Token, TokenAmount } from '@raydium-io/raydium-sdk';
|
import { LiquidityPoolKeysV4, Token, TokenAmount } from '@raydium-io/raydium-sdk';
|
||||||
import { Connection } from '@solana/web3.js';
|
import { Connection } from '@solana/web3.js';
|
||||||
import { logger } from '../helpers';
|
import { logger } from '../helpers';
|
||||||
|
|
||||||
@ -11,9 +11,9 @@ export class PoolSizeFilter implements Filter {
|
|||||||
private readonly maxPoolSize: TokenAmount,
|
private readonly maxPoolSize: TokenAmount,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(poolState: LiquidityStateV4): Promise<FilterResult> {
|
async execute(poolKeys: LiquidityPoolKeysV4): Promise<FilterResult> {
|
||||||
try {
|
try {
|
||||||
const response = await this.connection.getTokenAccountBalance(poolState.quoteVault, this.connection.commitment);
|
const response = await this.connection.getTokenAccountBalance(poolKeys.quoteVault, this.connection.commitment);
|
||||||
const poolSize = new TokenAmount(this.quoteToken, response.value.amount, true);
|
const poolSize = new TokenAmount(this.quoteToken, response.value.amount, true);
|
||||||
let inRange = true;
|
let inRange = true;
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ export class PoolSizeFilter implements Filter {
|
|||||||
|
|
||||||
return { ok: inRange };
|
return { ok: inRange };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error({ mint: poolState.baseMint }, `Failed to check pool size`);
|
logger.error({ mint: poolKeys.baseMint }, `Failed to check pool size`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ok: false, message: 'PoolSize -> Failed to check pool size' };
|
return { ok: false, message: 'PoolSize -> Failed to check pool size' };
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
import { Filter, FilterResult } from './pool-filters';
|
import { Filter, FilterResult } from './pool-filters';
|
||||||
import { MintLayout } from '@solana/spl-token';
|
import { MintLayout } from '@solana/spl-token';
|
||||||
import { Connection } from '@solana/web3.js';
|
import { Connection } from '@solana/web3.js';
|
||||||
import { LiquidityStateV4 } from '@raydium-io/raydium-sdk';
|
import { LiquidityPoolKeysV4 } from '@raydium-io/raydium-sdk';
|
||||||
import { logger } from '../helpers';
|
import { logger } from '../helpers';
|
||||||
|
|
||||||
export class RenouncedFilter implements Filter {
|
export class RenouncedFilter implements Filter {
|
||||||
constructor(private readonly connection: Connection) {}
|
constructor(private readonly connection: Connection) {}
|
||||||
|
|
||||||
async execute(poolState: LiquidityStateV4): Promise<FilterResult> {
|
async execute(poolKeys: LiquidityPoolKeysV4): Promise<FilterResult> {
|
||||||
try {
|
try {
|
||||||
const accountInfo = await this.connection.getAccountInfo(poolState.baseMint, this.connection.commitment);
|
const accountInfo = await this.connection.getAccountInfo(poolKeys.baseMint, this.connection.commitment);
|
||||||
if (!accountInfo?.data) {
|
if (!accountInfo?.data) {
|
||||||
return { ok: false, message: 'Renounced -> Failed to fetch account data' };
|
return { ok: false, message: 'Renounced -> Failed to fetch account data' };
|
||||||
}
|
}
|
||||||
@ -18,7 +18,7 @@ export class RenouncedFilter implements Filter {
|
|||||||
const renounced = deserialize.mintAuthorityOption === 0;
|
const renounced = deserialize.mintAuthorityOption === 0;
|
||||||
return { ok: renounced, message: renounced ? undefined : 'Renounced -> Creator can mint more tokens' };
|
return { ok: renounced, message: renounced ? undefined : 'Renounced -> Creator can mint more tokens' };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error({ mint: poolState.baseMint }, `Failed to check if mint is renounced`);
|
logger.error({ mint: poolKeys.baseMint }, `Failed to check if mint is renounced`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ok: false, message: 'Renounced -> Failed to check if mint is renounced' };
|
return { ok: false, message: 'Renounced -> Failed to check if mint is renounced' };
|
||||||
|
|||||||
@ -51,6 +51,9 @@ export const PRICE_CHECK_DURATION = Number(retrieveEnvVariable('PRICE_CHECK_DURA
|
|||||||
export const SELL_SLIPPAGE = Number(retrieveEnvVariable('SELL_SLIPPAGE', logger));
|
export const SELL_SLIPPAGE = Number(retrieveEnvVariable('SELL_SLIPPAGE', logger));
|
||||||
|
|
||||||
// Filters
|
// Filters
|
||||||
|
export const FILTER_CHECK_INTERVAL = Number(retrieveEnvVariable('FILTER_CHECK_INTERVAL', logger));
|
||||||
|
export const FILTER_CHECK_DURATION = Number(retrieveEnvVariable('FILTER_CHECK_DURATION', logger));
|
||||||
|
export const CONSECUTIVE_FILTER_MATCHES = Number(retrieveEnvVariable('CONSECUTIVE_FILTER_MATCHES', logger));
|
||||||
export const CHECK_IF_MINT_IS_RENOUNCED = retrieveEnvVariable('CHECK_IF_MINT_IS_RENOUNCED', logger) === 'true';
|
export const CHECK_IF_MINT_IS_RENOUNCED = retrieveEnvVariable('CHECK_IF_MINT_IS_RENOUNCED', logger) === 'true';
|
||||||
export const CHECK_IF_BURNED = retrieveEnvVariable('CHECK_IF_BURNED', logger) === 'true';
|
export const CHECK_IF_BURNED = retrieveEnvVariable('CHECK_IF_BURNED', logger) === 'true';
|
||||||
export const MIN_POOL_SIZE = retrieveEnvVariable('MIN_POOL_SIZE', logger);
|
export const MIN_POOL_SIZE = retrieveEnvVariable('MIN_POOL_SIZE', logger);
|
||||||
|
|||||||
13
index.ts
13
index.ts
@ -40,6 +40,9 @@ import {
|
|||||||
SNIPE_LIST_REFRESH_INTERVAL,
|
SNIPE_LIST_REFRESH_INTERVAL,
|
||||||
TRANSACTION_EXECUTOR,
|
TRANSACTION_EXECUTOR,
|
||||||
WARP_FEE,
|
WARP_FEE,
|
||||||
|
FILTER_CHECK_INTERVAL,
|
||||||
|
FILTER_CHECK_DURATION,
|
||||||
|
CONSECUTIVE_FILTER_MATCHES,
|
||||||
} from './helpers';
|
} from './helpers';
|
||||||
import { version } from './package.json';
|
import { version } from './package.json';
|
||||||
import { WarpTransactionExecutor } from './transactions/warp-transaction-executor';
|
import { WarpTransactionExecutor } from './transactions/warp-transaction-executor';
|
||||||
@ -78,8 +81,7 @@ function printDetails(wallet: Keypair, quoteToken: Token, bot: Bot) {
|
|||||||
logger.info(`Using warp: ${bot.isWarp}`);
|
logger.info(`Using warp: ${bot.isWarp}`);
|
||||||
if (bot.isWarp) {
|
if (bot.isWarp) {
|
||||||
logger.info(`Warp fee: ${WARP_FEE}`);
|
logger.info(`Warp fee: ${WARP_FEE}`);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
logger.info(`Compute Unit limit: ${botConfig.unitLimit}`);
|
logger.info(`Compute Unit limit: ${botConfig.unitLimit}`);
|
||||||
logger.info(`Compute Unit price (micro lamports): ${botConfig.unitPrice}`);
|
logger.info(`Compute Unit price (micro lamports): ${botConfig.unitPrice}`);
|
||||||
}
|
}
|
||||||
@ -109,6 +111,9 @@ function printDetails(wallet: Keypair, quoteToken: Token, bot: Bot) {
|
|||||||
logger.info('- Filters -');
|
logger.info('- Filters -');
|
||||||
logger.info(`Snipe list: ${botConfig.useSnipeList}`);
|
logger.info(`Snipe list: ${botConfig.useSnipeList}`);
|
||||||
logger.info(`Snipe list refresh interval: ${SNIPE_LIST_REFRESH_INTERVAL} ms`);
|
logger.info(`Snipe list refresh interval: ${SNIPE_LIST_REFRESH_INTERVAL} ms`);
|
||||||
|
logger.info(`Filter check interval: ${botConfig.filterCheckInterval} ms`);
|
||||||
|
logger.info(`Filter check duration: ${botConfig.filterCheckDuration} ms`);
|
||||||
|
logger.info(`Consecutive filter matches: ${botConfig.consecutiveMatchCount} ms`);
|
||||||
logger.info(`Check renounced: ${botConfig.checkRenounced}`);
|
logger.info(`Check renounced: ${botConfig.checkRenounced}`);
|
||||||
logger.info(`Check burned: ${botConfig.checkBurned}`);
|
logger.info(`Check burned: ${botConfig.checkBurned}`);
|
||||||
logger.info(`Min pool size: ${botConfig.minPoolSize.toFixed()}`);
|
logger.info(`Min pool size: ${botConfig.minPoolSize.toFixed()}`);
|
||||||
@ -151,6 +156,7 @@ const runListener = async () => {
|
|||||||
quoteAmount: new TokenAmount(quoteToken, QUOTE_AMOUNT, false),
|
quoteAmount: new TokenAmount(quoteToken, QUOTE_AMOUNT, false),
|
||||||
oneTokenAtATime: ONE_TOKEN_AT_A_TIME,
|
oneTokenAtATime: ONE_TOKEN_AT_A_TIME,
|
||||||
useSnipeList: USE_SNIPE_LIST,
|
useSnipeList: USE_SNIPE_LIST,
|
||||||
|
autoSell: AUTO_SELL,
|
||||||
autoSellDelay: AUTO_SELL_DELAY,
|
autoSellDelay: AUTO_SELL_DELAY,
|
||||||
maxSellRetries: MAX_SELL_RETRIES,
|
maxSellRetries: MAX_SELL_RETRIES,
|
||||||
autoBuyDelay: AUTO_BUY_DELAY,
|
autoBuyDelay: AUTO_BUY_DELAY,
|
||||||
@ -163,6 +169,9 @@ const runListener = async () => {
|
|||||||
sellSlippage: SELL_SLIPPAGE,
|
sellSlippage: SELL_SLIPPAGE,
|
||||||
priceCheckInterval: PRICE_CHECK_INTERVAL,
|
priceCheckInterval: PRICE_CHECK_INTERVAL,
|
||||||
priceCheckDuration: PRICE_CHECK_DURATION,
|
priceCheckDuration: PRICE_CHECK_DURATION,
|
||||||
|
filterCheckInterval: FILTER_CHECK_INTERVAL,
|
||||||
|
filterCheckDuration: FILTER_CHECK_DURATION,
|
||||||
|
consecutiveMatchCount: CONSECUTIVE_FILTER_MATCHES,
|
||||||
};
|
};
|
||||||
|
|
||||||
const bot = new Bot(connection, marketCache, poolCache, txExecutor, botConfig);
|
const bot = new Bot(connection, marketCache, poolCache, txExecutor, botConfig);
|
||||||
|
|||||||
Reference in New Issue
Block a user