浏览代码

Merge pull request #71 from NonVideri/master

Refactor project
Filip Dunđer 1 年之前
父节点
当前提交
6470305506
共有 9 个文件被更改,包括 76 次插入57 次删除
  1. 4 4
      README.md
  2. 34 52
      buy.ts
  3. 17 0
      constants/constants.ts
  4. 1 0
      constants/index.ts
  5. 2 1
      package.json
  6. 0 0
      readme/output.png
  7. 0 0
      readme/wsol.png
  8. 1 0
      utils/index.ts
  9. 17 0
      utils/logger.ts

+ 4 - 4
README.md

@@ -27,7 +27,7 @@ To run the script you need to:
 - Run the script by typing: `npm run buy` in terminal
 - Run the script by typing: `npm run buy` in terminal
 
 
 You should see the following output:  
 You should see the following output:  
-![output](output.png)
+![output](readme/output.png)
 
 
 ## Snipe list
 ## Snipe list
 By default, script buys each token which has a new liquidity pool created and open for trading. 
 By default, script buys each token which has a new liquidity pool created and open for trading. 
@@ -47,10 +47,10 @@ It will buy only when new pool is open for trading. If you want to buy token tha
 By default, auto sell is enabled. If you want to disable it, you need to:
 By default, auto sell is enabled. If you want to disable it, you need to:
 - Change variable `AUTO_SELL` to `false`
 - Change variable `AUTO_SELL` to `false`
 - Update `MAX_SELL_RETRIES` to set the maximum number of retries for selling token
 - Update `MAX_SELL_RETRIES` to set the maximum number of retries for selling token
-- Update `SELL_DELAY` to the number of milliseconds you want to wait before selling the token
+- Update `AUTO_SELL_DELAY` to the number of milliseconds you want to wait before selling the token
   - This will sell the token after the specified delay. (+- RPC node speed)
   - This will sell the token after the specified delay. (+- RPC node speed)
 
 
-If you set SELL_DELAY to 0, token will be sold immediately after it is bought.
+If you set AUTO_SELL_DELAY to 0, token will be sold immediately after it is bought.
 
 
 There is no guarantee that the token will be sold at a profit or even sold at all. The developer is not responsible for any losses incurred by using this feature.
 There is no guarantee that the token will be sold at a profit or even sold at all. The developer is not responsible for any losses incurred by using this feature.
 
 
@@ -73,7 +73,7 @@ To collect more information on an issue, please change `LOG_LEVEL` to `debug`.
   it means that wallet you provided doesn't have USDC/WSOL token account.
   it means that wallet you provided doesn't have USDC/WSOL token account.
   - FIX: Go to dex and swap some SOL to USDC/WSOL. For example when you swap sol to wsol you should see it in wallet as shown below:
   - FIX: Go to dex and swap some SOL to USDC/WSOL. For example when you swap sol to wsol you should see it in wallet as shown below:
 
 
-![wsol](wsol.png)
+![wsol](readme/wsol.png)
 
 
 ## Contact
 ## Contact
 [![](https://img.shields.io/discord/1201826085655023616?color=5865F2&logo=Discord&style=flat-square)](https://discord.gg/xYUETCA2aP)
 [![](https://img.shields.io/discord/1201826085655023616?color=5865F2&logo=Discord&style=flat-square)](https://discord.gg/xYUETCA2aP)

+ 34 - 52
buy.ts

@@ -24,65 +24,50 @@ import {
   KeyedAccountInfo,
   KeyedAccountInfo,
   TransactionMessage,
   TransactionMessage,
   VersionedTransaction,
   VersionedTransaction,
-  Commitment,
 } from '@solana/web3.js';
 } from '@solana/web3.js';
 import { getTokenAccounts, RAYDIUM_LIQUIDITY_PROGRAM_ID_V4, OPENBOOK_PROGRAM_ID, createPoolKeys } from './liquidity';
 import { getTokenAccounts, RAYDIUM_LIQUIDITY_PROGRAM_ID_V4, OPENBOOK_PROGRAM_ID, createPoolKeys } from './liquidity';
-import { retrieveEnvVariable } from './utils';
+import { logger } from './utils';
 import { getMinimalMarketV3, MinimalMarketLayoutV3 } from './market';
 import { getMinimalMarketV3, MinimalMarketLayoutV3 } from './market';
 import { MintLayout } from './types';
 import { MintLayout } from './types';
-import pino from 'pino';
 import bs58 from 'bs58';
 import bs58 from 'bs58';
 import * as fs from 'fs';
 import * as fs from 'fs';
 import * as path from 'path';
 import * as path from 'path';
-
-const transport = pino.transport({
-  target: 'pino-pretty',
-});
-
-export const logger = pino(
-  {
-    level: 'info',
-    redact: ['poolKeys'],
-    serializers: {
-      error: pino.stdSerializers.err,
-    },
-    base: undefined,
-  },
-  transport,
-);
-
-const network = 'mainnet-beta';
-const RPC_ENDPOINT = retrieveEnvVariable('RPC_ENDPOINT', logger);
-const RPC_WEBSOCKET_ENDPOINT = retrieveEnvVariable('RPC_WEBSOCKET_ENDPOINT', logger);
-const LOG_LEVEL = retrieveEnvVariable('LOG_LEVEL', logger);
+import {
+  AUTO_SELL,
+  AUTO_SELL_DELAY,
+  CHECK_IF_MINT_IS_RENOUNCED,
+  COMMITMENT_LEVEL,
+  LOG_LEVEL,
+  MAX_SELL_RETRIES,
+  NETWORK,
+  PRIVATE_KEY,
+  QUOTE_AMOUNT,
+  QUOTE_MINT,
+  RPC_ENDPOINT,
+  RPC_WEBSOCKET_ENDPOINT,
+  SNIPE_LIST_REFRESH_INTERVAL,
+  USE_SNIPE_LIST,
+} from './constants';
 
 
 const solanaConnection = new Connection(RPC_ENDPOINT, {
 const solanaConnection = new Connection(RPC_ENDPOINT, {
   wsEndpoint: RPC_WEBSOCKET_ENDPOINT,
   wsEndpoint: RPC_WEBSOCKET_ENDPOINT,
 });
 });
 
 
-export type MinimalTokenAccountData = {
+export interface MinimalTokenAccountData {
   mint: PublicKey;
   mint: PublicKey;
   address: PublicKey;
   address: PublicKey;
   poolKeys?: LiquidityPoolKeys;
   poolKeys?: LiquidityPoolKeys;
   market?: MinimalMarketLayoutV3;
   market?: MinimalMarketLayoutV3;
 };
 };
 
 
-let existingLiquidityPools: Set<string> = new Set<string>();
-let existingOpenBookMarkets: Set<string> = new Set<string>();
-let existingTokenAccounts: Map<string, MinimalTokenAccountData> = new Map<string, MinimalTokenAccountData>();
+const existingLiquidityPools: Set<string> = new Set<string>();
+const existingOpenBookMarkets: Set<string> = new Set<string>();
+const existingTokenAccounts: Map<string, MinimalTokenAccountData> = new Map<string, MinimalTokenAccountData>();
 
 
 let wallet: Keypair;
 let wallet: Keypair;
 let quoteToken: Token;
 let quoteToken: Token;
 let quoteTokenAssociatedAddress: PublicKey;
 let quoteTokenAssociatedAddress: PublicKey;
 let quoteAmount: TokenAmount;
 let quoteAmount: TokenAmount;
-let commitment: Commitment = retrieveEnvVariable('COMMITMENT_LEVEL', logger) as Commitment;
-
-const CHECK_IF_MINT_IS_RENOUNCED = retrieveEnvVariable('CHECK_IF_MINT_IS_RENOUNCED', logger) === 'true';
-const USE_SNIPE_LIST = retrieveEnvVariable('USE_SNIPE_LIST', logger) === 'true';
-const SNIPE_LIST_REFRESH_INTERVAL = Number(retrieveEnvVariable('SNIPE_LIST_REFRESH_INTERVAL', logger));
-const AUTO_SELL = retrieveEnvVariable('AUTO_SELL', logger) === 'true';
-const MAX_SELL_RETRIES = Number(retrieveEnvVariable('MAX_SELL_RETRIES', logger));
-const AUTO_SELL_DELAY = Number(retrieveEnvVariable('AUTO_SELL_DELAY', logger));
 
 
 let snipeList: string[] = [];
 let snipeList: string[] = [];
 
 
@@ -90,13 +75,10 @@ async function init(): Promise<void> {
   logger.level = LOG_LEVEL;
   logger.level = LOG_LEVEL;
 
 
   // get wallet
   // get wallet
-  const PRIVATE_KEY = retrieveEnvVariable('PRIVATE_KEY', logger);
   wallet = Keypair.fromSecretKey(bs58.decode(PRIVATE_KEY));
   wallet = Keypair.fromSecretKey(bs58.decode(PRIVATE_KEY));
   logger.info(`Wallet Address: ${wallet.publicKey}`);
   logger.info(`Wallet Address: ${wallet.publicKey}`);
 
 
   // get quote mint and amount
   // get quote mint and amount
-  const QUOTE_MINT = retrieveEnvVariable('QUOTE_MINT', logger);
-  const QUOTE_AMOUNT = retrieveEnvVariable('QUOTE_AMOUNT', logger);
   switch (QUOTE_MINT) {
   switch (QUOTE_MINT) {
     case 'WSOL': {
     case 'WSOL': {
       quoteToken = Token.WSOL;
       quoteToken = Token.WSOL;
@@ -124,7 +106,7 @@ async function init(): Promise<void> {
   );
   );
 
 
   // check existing wallet for associated token account of quote mint
   // check existing wallet for associated token account of quote mint
-  const tokenAccounts = await getTokenAccounts(solanaConnection, wallet.publicKey, commitment);
+  const tokenAccounts = await getTokenAccounts(solanaConnection, wallet.publicKey, COMMITMENT_LEVEL);
 
 
   for (const ta of tokenAccounts) {
   for (const ta of tokenAccounts) {
     existingTokenAccounts.set(ta.accountInfo.mint.toString(), <MinimalTokenAccountData>{
     existingTokenAccounts.set(ta.accountInfo.mint.toString(), <MinimalTokenAccountData>{
@@ -214,7 +196,7 @@ async function buy(accountId: PublicKey, accountData: LiquidityStateV4): Promise
 
 
     if (!tokenAccount) {
     if (!tokenAccount) {
       // it's possible that we didn't have time to fetch open book data
       // it's possible that we didn't have time to fetch open book data
-      const market = await getMinimalMarketV3(solanaConnection, accountData.marketId, commitment);
+      const market = await getMinimalMarketV3(solanaConnection, accountData.marketId, COMMITMENT_LEVEL);
       tokenAccount = saveTokenAccount(accountData.baseMint, market);
       tokenAccount = saveTokenAccount(accountData.baseMint, market);
     }
     }
 
 
@@ -234,7 +216,7 @@ async function buy(accountId: PublicKey, accountData: LiquidityStateV4): Promise
     );
     );
 
 
     const latestBlockhash = await solanaConnection.getLatestBlockhash({
     const latestBlockhash = await solanaConnection.getLatestBlockhash({
-      commitment: commitment,
+      commitment: COMMITMENT_LEVEL,
     });
     });
     const messageV0 = new TransactionMessage({
     const messageV0 = new TransactionMessage({
       payerKey: wallet.publicKey,
       payerKey: wallet.publicKey,
@@ -254,7 +236,7 @@ async function buy(accountId: PublicKey, accountData: LiquidityStateV4): Promise
     const transaction = new VersionedTransaction(messageV0);
     const transaction = new VersionedTransaction(messageV0);
     transaction.sign([wallet, ...innerTransaction.signers]);
     transaction.sign([wallet, ...innerTransaction.signers]);
     const signature = await solanaConnection.sendRawTransaction(transaction.serialize(), {
     const signature = await solanaConnection.sendRawTransaction(transaction.serialize(), {
-      preflightCommitment: commitment,
+      preflightCommitment: COMMITMENT_LEVEL,
     });
     });
     logger.info({ mint: accountData.baseMint, signature }, `Sent buy tx`);
     logger.info({ mint: accountData.baseMint, signature }, `Sent buy tx`);
     const confirmation = await solanaConnection.confirmTransaction(
     const confirmation = await solanaConnection.confirmTransaction(
@@ -263,14 +245,14 @@ async function buy(accountId: PublicKey, accountData: LiquidityStateV4): Promise
         lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
         lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
         blockhash: latestBlockhash.blockhash,
         blockhash: latestBlockhash.blockhash,
       },
       },
-      commitment,
+      COMMITMENT_LEVEL,
     );
     );
     if (!confirmation.value.err) {
     if (!confirmation.value.err) {
       logger.info(
       logger.info(
         {
         {
           mint: accountData.baseMint,
           mint: accountData.baseMint,
           signature,
           signature,
-          url: `https://solscan.io/tx/${signature}?cluster=${network}`,
+          url: `https://solscan.io/tx/${signature}?cluster=${NETWORK}`,
         },
         },
         `Confirmed buy tx`,
         `Confirmed buy tx`,
       );
       );
@@ -330,7 +312,7 @@ async function sell(accountId: PublicKey, mint: PublicKey, amount: BigNumberish)
       );
       );
 
 
       const latestBlockhash = await solanaConnection.getLatestBlockhash({
       const latestBlockhash = await solanaConnection.getLatestBlockhash({
-        commitment: commitment,
+        commitment: COMMITMENT_LEVEL,
       });
       });
       const messageV0 = new TransactionMessage({
       const messageV0 = new TransactionMessage({
         payerKey: wallet.publicKey,
         payerKey: wallet.publicKey,
@@ -345,7 +327,7 @@ async function sell(accountId: PublicKey, mint: PublicKey, amount: BigNumberish)
       const transaction = new VersionedTransaction(messageV0);
       const transaction = new VersionedTransaction(messageV0);
       transaction.sign([wallet, ...innerTransaction.signers]);
       transaction.sign([wallet, ...innerTransaction.signers]);
       const signature = await solanaConnection.sendRawTransaction(transaction.serialize(), {
       const signature = await solanaConnection.sendRawTransaction(transaction.serialize(), {
-        preflightCommitment: commitment,
+        preflightCommitment: COMMITMENT_LEVEL,
       });
       });
       logger.info({ mint, signature }, `Sent sell tx`);
       logger.info({ mint, signature }, `Sent sell tx`);
       const confirmation = await solanaConnection.confirmTransaction(
       const confirmation = await solanaConnection.confirmTransaction(
@@ -354,7 +336,7 @@ async function sell(accountId: PublicKey, mint: PublicKey, amount: BigNumberish)
           lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
           lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
           blockhash: latestBlockhash.blockhash,
           blockhash: latestBlockhash.blockhash,
         },
         },
-        commitment,
+        COMMITMENT_LEVEL,
       );
       );
       if (confirmation.value.err) {
       if (confirmation.value.err) {
         logger.debug(confirmation.value.err);
         logger.debug(confirmation.value.err);
@@ -367,7 +349,7 @@ async function sell(accountId: PublicKey, mint: PublicKey, amount: BigNumberish)
           dex: `https://dexscreener.com/solana/${mint}?maker=${wallet.publicKey}`,
           dex: `https://dexscreener.com/solana/${mint}?maker=${wallet.publicKey}`,
           mint,
           mint,
           signature,
           signature,
-          url: `https://solscan.io/tx/${signature}?cluster=${network}`,
+          url: `https://solscan.io/tx/${signature}?cluster=${NETWORK}`,
         },
         },
         `Confirmed sell tx`,
         `Confirmed sell tx`,
       );
       );
@@ -417,7 +399,7 @@ const runListener = async () => {
         const _ = processRaydiumPool(updatedAccountInfo.accountId, poolState);
         const _ = processRaydiumPool(updatedAccountInfo.accountId, poolState);
       }
       }
     },
     },
-    commitment,
+    COMMITMENT_LEVEL,
     [
     [
       { dataSize: LIQUIDITY_STATE_LAYOUT_V4.span },
       { dataSize: LIQUIDITY_STATE_LAYOUT_V4.span },
       {
       {
@@ -451,7 +433,7 @@ const runListener = async () => {
         const _ = processOpenBookMarket(updatedAccountInfo);
         const _ = processOpenBookMarket(updatedAccountInfo);
       }
       }
     },
     },
-    commitment,
+    COMMITMENT_LEVEL,
     [
     [
       { dataSize: MARKET_STATE_LAYOUT_V3.span },
       { dataSize: MARKET_STATE_LAYOUT_V3.span },
       {
       {
@@ -475,7 +457,7 @@ const runListener = async () => {
 
 
         const _ = sell(updatedAccountInfo.accountId, accountData.mint, accountData.amount);
         const _ = sell(updatedAccountInfo.accountId, accountData.mint, accountData.amount);
       },
       },
-      commitment,
+      COMMITMENT_LEVEL,
       [
       [
         {
         {
           dataSize: 165,
           dataSize: 165,

+ 17 - 0
constants/constants.ts

@@ -0,0 +1,17 @@
+import { Commitment } from "@solana/web3.js";
+import { logger, retrieveEnvVariable } from "../utils";
+
+export const NETWORK = 'mainnet-beta';
+export const COMMITMENT_LEVEL: Commitment = retrieveEnvVariable('COMMITMENT_LEVEL', logger) as Commitment;
+export const RPC_ENDPOINT = retrieveEnvVariable('RPC_ENDPOINT', logger);
+export const RPC_WEBSOCKET_ENDPOINT = retrieveEnvVariable('RPC_WEBSOCKET_ENDPOINT', logger);
+export const LOG_LEVEL = retrieveEnvVariable('LOG_LEVEL', logger);
+export const CHECK_IF_MINT_IS_RENOUNCED = retrieveEnvVariable('CHECK_IF_MINT_IS_RENOUNCED', logger) === 'true';
+export const USE_SNIPE_LIST = retrieveEnvVariable('USE_SNIPE_LIST', logger) === 'true';
+export const SNIPE_LIST_REFRESH_INTERVAL = Number(retrieveEnvVariable('SNIPE_LIST_REFRESH_INTERVAL', logger));
+export const AUTO_SELL = retrieveEnvVariable('AUTO_SELL', logger) === 'true';
+export const MAX_SELL_RETRIES = Number(retrieveEnvVariable('MAX_SELL_RETRIES', logger));
+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);

+ 1 - 0
constants/index.ts

@@ -0,0 +1 @@
+export * from './constants';

+ 2 - 1
package.json

@@ -2,7 +2,8 @@
   "name": "solana-sniper-bot",
   "name": "solana-sniper-bot",
   "author": "Filip Dundjer",
   "author": "Filip Dundjer",
   "scripts": {
   "scripts": {
-    "buy": "ts-node buy.ts"
+    "buy": "ts-node buy.ts",
+    "tsc": "tsc --noEmit"
   },
   },
   "dependencies": {
   "dependencies": {
     "@raydium-io/raydium-sdk": "^1.3.1-beta.47",
     "@raydium-io/raydium-sdk": "^1.3.1-beta.47",

+ 0 - 0
output.png → readme/output.png


+ 0 - 0
wsol.png → readme/wsol.png


+ 1 - 0
utils/index.ts

@@ -1 +1,2 @@
 export * from './utils';
 export * from './utils';
+export * from './logger';

+ 17 - 0
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,
+);