├── .idea
├── shelf
│ ├── _2024_11_23_03_02____.xml
│ └── 在进行更新之前于_2024_11_23_03_02_取消提交了更改_[更改]
│ │ └── shelved.patch
└── workspace.xml
├── Bot原版
├── Bot Solana Sniper Main
│ ├── .env.copy
│ ├── .gitignore
│ ├── .prettierrc
│ ├── LICENSE.md
│ ├── README.md
│ ├── bot.ts
│ ├── cache
│ │ ├── index.ts
│ │ ├── market.cache.ts
│ │ ├── pool.cache.ts
│ │ └── snipe-list.cache.ts
│ ├── filters
│ │ ├── burn.filter.ts
│ │ ├── index.ts
│ │ ├── mutable.filter.ts
│ │ ├── pool-filters.ts
│ │ ├── pool-size.filter.ts
│ │ └── renounced.filter.ts
│ ├── helpers
│ │ ├── constants.ts
│ │ ├── index.ts
│ │ ├── liquidity.ts
│ │ ├── logger.ts
│ │ ├── market.ts
│ │ ├── promises.ts
│ │ ├── token.ts
│ │ └── wallet.ts
│ ├── index.ts
│ ├── listeners
│ │ ├── index.ts
│ │ └── listeners.ts
│ ├── package-lock.json
│ ├── package.json
│ ├── snipe-list.txt
│ ├── transactions
│ │ ├── default-transaction-executor.ts
│ │ ├── index.ts
│ │ ├── jito-rpc-transaction-executor.ts
│ │ ├── transaction-executor.interface.ts
│ │ └── warp-transaction-executor.ts
│ └── tsconfig.json
└── Bot Spam Sniper
│ ├── .gitignore
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── strategy1
│ ├── formatAmmKeysById.js
│ ├── start1.js
│ └── swap1.js
│ ├── strategy2
│ ├── derivePoolKeys.js
│ ├── start2.js
│ └── swap2.js
│ └── utils
│ ├── config.js
│ ├── decoderaylog.js
│ └── util.js
├── Bot汉化
├── bot Solana Sniper Main
│ ├── .env.copy
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── bot.ts
│ ├── cache
│ │ ├── index.ts
│ │ ├── market.cache.ts
│ │ ├── pool.cache.ts
│ │ └── snipe-list.cache.ts
│ ├── filters
│ │ ├── burn.filter.ts
│ │ ├── index.ts
│ │ ├── mutable.filter.ts
│ │ ├── pool-filters.ts
│ │ ├── pool-size.filter.ts
│ │ └── renounced.filter.ts
│ ├── helpers
│ │ ├── constants.ts
│ │ ├── index.ts
│ │ ├── liquidity.ts
│ │ ├── logger.ts
│ │ ├── market.ts
│ │ ├── promises.ts
│ │ ├── token.ts
│ │ └── wallet.ts
│ ├── index.ts
│ ├── listeners
│ │ ├── index.ts
│ │ └── listeners.ts
│ ├── package-lock.json
│ ├── package.json
│ ├── snipe-list.txt
│ ├── transactions
│ │ ├── default-transaction-executor.ts
│ │ ├── index.ts
│ │ ├── jito-rpc-transaction-executor.ts
│ │ ├── transaction-executor.interface.ts
│ │ └── warp-transaction-executor.ts
│ └── tsconfig.json
└── bot Spam Sniper
│ ├── .gitignore
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── strategy1
│ ├── formatAmmKeysById.js
│ ├── start1.js
│ └── swap1.js
│ ├── strategy2
│ ├── derivePoolKeys.js
│ ├── start2.js
│ └── swap2.js
│ └── utils
│ ├── config.js
│ ├── decoderaylog.js
│ └── util.js
└── README.md
/.idea/shelf/_2024_11_23_03_02____.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/.env.copy:
--------------------------------------------------------------------------------
1 | # Wallet
2 | PRIVATE_KEY=
3 |
4 | # Connection
5 | RPC_ENDPOINT=https://solana-mainnet.rpc.extrnode.com/5b667693-6518-4921-8ea1-4f65ff09c463
6 | RPC_WEBSOCKET_ENDPOINT=wss://solana-mainnet.rpc.extrnode.com/5b667693-6518-4921-8ea1-4f65ff09c463
7 | COMMITMENT_LEVEL=confirmed
8 |
9 | # Bot
10 | LOG_LEVEL=trace
11 | ONE_TOKEN_AT_A_TIME=true
12 | PRE_LOAD_EXISTING_MARKETS=false
13 | CACHE_NEW_MARKETS=false
14 | # default or warp or jito
15 | TRANSACTION_EXECUTOR=jito
16 | # if using default executor, fee below will be applied
17 | COMPUTE_UNIT_LIMIT=101337
18 | COMPUTE_UNIT_PRICE=421197
19 | # if using warp or jito executor, fee below will be applied
20 | CUSTOM_FEE=0.01
21 |
22 | # Buy
23 | QUOTE_MINT=WSOL
24 | QUOTE_AMOUNT=0.001
25 | AUTO_BUY_DELAY=0
26 | MAX_BUY_RETRIES=10
27 | BUY_SLIPPAGE=100
28 |
29 | # Sell
30 | AUTO_SELL=true
31 | MAX_SELL_RETRIES=10
32 | AUTO_SELL_DELAY=0
33 | PRICE_CHECK_INTERVAL=2000
34 | PRICE_CHECK_DURATION=600000
35 | TAKE_PROFIT=100
36 | STOP_LOSS=20
37 | SELL_SLIPPAGE=100
38 |
39 | # Filters
40 | USE_SNIPE_LIST=false
41 | SNIPE_LIST_REFRESH_INTERVAL=30000
42 | FILTER_CHECK_DURATION=60000
43 | FILTER_CHECK_INTERVAL=2000
44 | CONSECUTIVE_FILTER_MATCHES=3
45 | CHECK_IF_MUTABLE=false
46 | CHECK_IF_MINT_IS_RENOUNCED=true
47 | CHECK_IF_FREEZABLE=false
48 | CHECK_IF_BURNED=true
49 | MIN_POOL_SIZE=3
50 | MAX_POOL_SIZE=20
51 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 | .pnpm-debug.log*
9 |
10 | # Diagnostic reports (https://nodejs.org/api/report.html)
11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12 |
13 | # Runtime data
14 | pids
15 | *.pid
16 | *.seed
17 | *.pid.lock
18 |
19 | # Directory for instrumented libs generated by jscoverage/JSCover
20 | lib-cov
21 |
22 | # Coverage directory used by tools like istanbul
23 | coverage
24 | *.lcov
25 |
26 | # nyc test coverage
27 | .nyc_output
28 |
29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30 | .grunt
31 |
32 | # Bower dependency directory (https://bower.io/)
33 | bower_components
34 |
35 | # node-waf configuration
36 | .lock-wscript
37 |
38 | # Compiled binary addons (https://nodejs.org/api/addons.html)
39 | build/Release
40 |
41 | # Dependency directories
42 | node_modules/
43 | jspm_packages/
44 |
45 | # Snowpack dependency directory (https://snowpack.dev/)
46 | web_modules/
47 |
48 | # TypeScript cache
49 | *.tsbuildinfo
50 |
51 | # Optional npm cache directory
52 | .npm
53 |
54 | # Optional eslint cache
55 | .eslintcache
56 |
57 | # Optional stylelint cache
58 | .stylelintcache
59 |
60 | # Microbundle cache
61 | .rpt2_cache/
62 | .rts2_cache_cjs/
63 | .rts2_cache_es/
64 | .rts2_cache_umd/
65 |
66 | # Optional REPL history
67 | .node_repl_history
68 |
69 | # Output of 'npm pack'
70 | *.tgz
71 |
72 | # Yarn Integrity file
73 | .yarn-integrity
74 |
75 | # dotenv environment variable files
76 | .env
77 | .env.development.local
78 | .env.test.local
79 | .env.production.local
80 | .env.local
81 |
82 | # parcel-bundler cache (https://parceljs.org/)
83 | .cache
84 | .parcel-cache
85 |
86 | # Next.js build output
87 | .next
88 | out
89 |
90 | # Nuxt.js build / generate output
91 | .nuxt
92 | dist
93 |
94 | # Gatsby files
95 | .cache/
96 | # Comment in the public line in if your project uses Gatsby and not Next.js
97 | # https://nextjs.org/blog/next-9-1#public-directory-support
98 | # public
99 |
100 | # vuepress build output
101 | .vuepress/dist
102 |
103 | # vuepress v2.x temp and cache directory
104 | .temp
105 | .cache
106 |
107 | # Docusaurus cache and generated files
108 | .docusaurus
109 |
110 | # Serverless directories
111 | .serverless/
112 |
113 | # FuseBox cache
114 | .fusebox/
115 |
116 | # DynamoDB Local files
117 | .dynamodb/
118 |
119 | # TernJS port file
120 | .tern-port
121 |
122 | # Stores VSCode versions used for testing VSCode extensions
123 | .vscode-test
124 |
125 | # PNPM
126 | pnpm-lock.yaml
127 |
128 | # yarn v2
129 | .yarn/cache
130 | .yarn/unplugged
131 | .yarn/build-state.yml
132 | .yarn/install-state.gz
133 | .pnp.*
134 |
135 | # JetBrains
136 | .idea
137 |
138 | # Visual Studio Code
139 | *.code-workspace
140 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all",
4 | "printWidth": 120
5 | }
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/LICENSE.md:
--------------------------------------------------------------------------------
1 | AXISBOT CO
2 |
3 | Disclaimer:
4 | The AxisBot Solana Sniper is a code presented to simplify many routine trading tasks,
5 | which combines many useful utilities.
6 | Trading cryptocurrencies involves substantial risk, including the potential loss of principal.
7 | The bot does not guarantee profits or specific outcomes.
8 | Users are solely responsible for any risks associated with using this tool.
9 | Always conduct your research, exercise caution, and consider your risk tolerance before engaging in any trading activities,
10 | automated or otherwise.
11 | The creators and contributors of this bot bear no responsibility for any financial losses incurred while using this tool.
12 | By using the Axis Sniper Bot, you acknowledge and accept the risks associated with cryptocurrency trading,
13 | and you agree that the creators and contributors are not liable for any damages or losses resulting from its use.
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/README.md:
--------------------------------------------------------------------------------
1 | # AxisBot Solana Sniper v1.0
2 |
3 | AxisBot - snipe and sell SPL tokens at lightning speed. Our sniping bot helps you maintain a higher level of security while also giving you the fastest sniping speed possible. Built by Traders for Traders.
4 |
5 | ## Setup
6 |
7 | To run the script you need to:
8 |
9 | - Create a new empty Solana wallet
10 | - Transfer some SOL to it.
11 | - Convert some SOL to USDC or WSOL.
12 | - You need USDC or WSOL depending on the configuration set below.
13 | - Configure the script by updating `.env.copy` file (remove the .copy from the file name when done).
14 | - Check [Configuration](#configuration) section bellow
15 | - Install dependencies by typing: `npm install`
16 | - Run the script by typing: `npm run start` in terminal
17 |
18 | ### Configuration
19 |
20 | #### Wallet
21 |
22 | - `PRIVATE_KEY` - Your wallet's private key.
23 |
24 | #### Connection
25 |
26 | - `RPC_ENDPOINT` - HTTPS RPC endpoint for interacting with the Solana network.
27 | - `RPC_WEBSOCKET_ENDPOINT` - WebSocket RPC endpoint for real-time updates from the Solana network.
28 | - `COMMITMENT_LEVEL`- The commitment level of transactions (e.g., "finalized" for the highest level of security).
29 |
30 | #### Bot
31 |
32 | - `LOG_LEVEL` - Set logging level, e.g., `info`, `debug`, `trace`, etc.
33 | - `ONE_TOKEN_AT_A_TIME` - Set to `true` to process buying one token at a time.
34 | - `COMPUTE_UNIT_LIMIT` - Compute limit used to calculate fees.
35 | - `COMPUTE_UNIT_PRICE` - Compute price used to calculate fees.
36 | - `PRE_LOAD_EXISTING_MARKETS` - Bot will load all existing markets in memory on start.
37 | - This option should not be used with public RPC.
38 | - `CACHE_NEW_MARKETS` - Set to `true` to cache new markets.
39 | - This option should not be used with public RPC.
40 | - `TRANSACTION_EXECUTOR` - Set to jito to use JSON-RPC jito executer
41 | - `CUSTOM_FEE` - If using warp or jito executors this value will be used for transaction fees instead of `COMPUTE_UNIT_LIMIT` and `COMPUTE_UNIT_LIMIT`
42 | - Minimum value is 0.0001 SOL, but we recommend using 0.01 SOL or above
43 | - On top of this fee, minimal solana network fee will be applied
44 |
45 | #### Buy
46 |
47 | - `QUOTE_MINT` - Which pools to snipe, USDC or WSOL.
48 | - `QUOTE_AMOUNT` - Amount used to buy each new token.
49 | - `AUTO_BUY_DELAY` - Delay in milliseconds before buying a token.
50 | - `MAX_BUY_RETRIES` - Maximum number of retries for buying a token.
51 | - `BUY_SLIPPAGE` - Slippage %
52 |
53 | #### Sell
54 |
55 | - `AUTO_SELL` - Set to `true` to enable automatic selling of tokens.
56 | - If you want to manually sell bought tokens, disable this option.
57 | - `MAX_SELL_RETRIES` - Maximum number of retries for selling a token.
58 | - `AUTO_SELL_DELAY` - Delay in milliseconds before auto-selling a token.
59 | - `PRICE_CHECK_INTERVAL` - Interval in milliseconds for checking the take profit and stop loss conditions.
60 | - Set to zero to disable take profit and stop loss.
61 | - `PRICE_CHECK_DURATION` - Time in milliseconds to wait for stop loss/take profit conditions.
62 | - If you don't reach profit or loss bot will auto sell after this time.
63 | - Set to zero to disable take profit and stop loss.
64 | - `TAKE_PROFIT` - Percentage profit at which to take profit.
65 | - Take profit is calculated based on quote mint.
66 | - `STOP_LOSS` - Percentage loss at which to stop the loss.
67 | - Stop loss is calculated based on quote mint.
68 | - `SELL_SLIPPAGE` - Slippage %.
69 |
70 | #### Snipe list
71 |
72 | - `USE_SNIPE_LIST` - Set to `true` to enable buying only tokens listed in `snipe-list.txt`.
73 | - Pool must not exist before the bot starts.
74 | - If token can be traded before bot starts nothing will happen. Bot will not buy the token.
75 | - `SNIPE_LIST_REFRESH_INTERVAL` - Interval in milliseconds to refresh the snipe list.
76 | - You can update snipe list while bot is running. It will pickup the new changes each time it does refresh.
77 |
78 | Note: When using snipe list filters below will be disabled.
79 |
80 | #### Filters
81 |
82 | - `FILTER_CHECK_INTERVAL` - Interval in milliseconds for checking if pool match the filters.
83 | - Set to zero to disable filters.
84 | - `FILTER_CHECK_DURATION` - Time in milliseconds to wait for pool to match the filters.
85 | - If pool doesn't match the filter buy will not happen.
86 | - Set to zero to disable filters.
87 | - `CONSECUTIVE_FILTER_MATCHES` - How many times in a row pool needs to match the filters.
88 | - This is useful because when pool is burned (and rugged), other filters may not report the same behavior. eg. pool size may still have old value
89 | - `CHECK_IF_MUTABLE` - Set to `true` to buy tokens only if their metadata are not mutable.
90 | - `CHECK_IF_MINT_IS_RENOUNCED` - Set to `true` to buy tokens only if their mint is renounced.
91 | - `CHECK_IF_FREEZABLE` - Set to `true` to buy tokens only if they are not freezable.
92 | - `CHECK_IF_BURNED` - Set to `true` to buy tokens only if their liquidity pool is burned.
93 | - `MIN_POOL_SIZE` - Bot will buy only if the pool size is greater than or equal the specified amount.
94 | - Set `0` to disable.
95 | - `MAX_POOL_SIZE` - Bot will buy only if the pool size is less than or equal the specified amount.
96 | - Set `0` to disable.
97 |
98 | ## Common issues
99 |
100 | If you have an error which is not listed here, please create a new issue in this repository.
101 | To collect more information on an issue, please change `LOG_LEVEL` to `debug`.
102 |
103 | ### No token account
104 |
105 | - If you see following error in your log file:
106 | `Error: No SOL token account found in wallet: `
107 | it means that wallet you provided doesn't have USDC/WSOL token account.
108 | - 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:
109 |
110 | ## Disclaimer
111 |
112 | Disclaimer:
113 | The AxisBot Solana Sniper is a code presented to simplify many routine trading tasks,
114 | which combines many useful utilities.
115 | Trading cryptocurrencies involves substantial risk, including the potential loss of principal.
116 | The bot does not guarantee profits or specific outcomes.
117 | Users are solely responsible for any risks associated with using this tool.
118 | Always conduct your research, exercise caution, and consider your risk tolerance before engaging in any trading activities,
119 | automated or otherwise.
120 | The creators and contributors of this bot bear no responsibility for any financial losses incurred while using this tool.
121 | By using the Axis Sniper Bot, you acknowledge and accept the risks associated with cryptocurrency trading,
122 | and you agree that the creators and contributors are not liable for any damages or losses resulting from its use.
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/cache/index.ts:
--------------------------------------------------------------------------------
1 | export * from './market.cache';
2 | export * from './pool.cache';
3 | export * from './snipe-list.cache';
4 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/cache/market.cache.ts:
--------------------------------------------------------------------------------
1 | import { Connection, PublicKey } from '@solana/web3.js';
2 | import { getMinimalMarketV3, logger, MINIMAL_MARKET_STATE_LAYOUT_V3, MinimalMarketLayoutV3 } from '../helpers';
3 | import { MAINNET_PROGRAM_ID, MARKET_STATE_LAYOUT_V3, Token } from '@raydium-io/raydium-sdk';
4 |
5 | export class MarketCache {
6 | private readonly keys: Map = new Map();
7 | constructor(private readonly connection: Connection) {}
8 |
9 | async init(config: { quoteToken: Token }) {
10 | logger.debug({}, `Fetching all existing ${config.quoteToken.symbol} markets...`);
11 |
12 | const accounts = await this.connection.getProgramAccounts(MAINNET_PROGRAM_ID.OPENBOOK_MARKET, {
13 | commitment: this.connection.commitment,
14 | dataSlice: {
15 | offset: MARKET_STATE_LAYOUT_V3.offsetOf('eventQueue'),
16 | length: MINIMAL_MARKET_STATE_LAYOUT_V3.span,
17 | },
18 | filters: [
19 | { dataSize: MARKET_STATE_LAYOUT_V3.span },
20 | {
21 | memcmp: {
22 | offset: MARKET_STATE_LAYOUT_V3.offsetOf('quoteMint'),
23 | bytes: config.quoteToken.mint.toBase58(),
24 | },
25 | },
26 | ],
27 | });
28 |
29 | for (const account of accounts) {
30 | const market = MINIMAL_MARKET_STATE_LAYOUT_V3.decode(account.account.data);
31 | this.keys.set(account.pubkey.toString(), market);
32 | }
33 |
34 | logger.debug({}, `Cached ${this.keys.size} markets`);
35 | }
36 |
37 | public save(marketId: string, keys: MinimalMarketLayoutV3) {
38 | if (!this.keys.has(marketId)) {
39 | logger.trace({}, `Caching new market: ${marketId}`);
40 | this.keys.set(marketId, keys);
41 | }
42 | }
43 |
44 | public async get(marketId: string): Promise {
45 | if (this.keys.has(marketId)) {
46 | return this.keys.get(marketId)!;
47 | }
48 |
49 | logger.trace({}, `Fetching new market keys for ${marketId}`);
50 | const market = await this.fetch(marketId);
51 | this.keys.set(marketId, market);
52 | return market;
53 | }
54 |
55 | private fetch(marketId: string): Promise {
56 | return getMinimalMarketV3(this.connection, new PublicKey(marketId), this.connection.commitment);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/cache/pool.cache.ts:
--------------------------------------------------------------------------------
1 | import { LiquidityStateV4 } from '@raydium-io/raydium-sdk';
2 | import { logger } from '../helpers';
3 |
4 | export class PoolCache {
5 | private readonly keys: Map = new Map<
6 | string,
7 | { id: string; state: LiquidityStateV4 }
8 | >();
9 |
10 | public save(id: string, state: LiquidityStateV4) {
11 | if (!this.keys.has(state.baseMint.toString())) {
12 | logger.trace(`Caching new pool for mint: ${state.baseMint.toString()}`);
13 | this.keys.set(state.baseMint.toString(), { id, state });
14 | }
15 | }
16 |
17 | public async get(mint: string): Promise<{ id: string; state: LiquidityStateV4 }> {
18 | return this.keys.get(mint)!;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/cache/snipe-list.cache.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import path from 'path';
3 | import { logger, SNIPE_LIST_REFRESH_INTERVAL } from '../helpers';
4 |
5 | export class SnipeListCache {
6 | private snipeList: string[] = [];
7 | private fileLocation = path.join(__dirname, '../snipe-list.txt');
8 |
9 | constructor() {
10 | setInterval(() => this.loadSnipeList(), SNIPE_LIST_REFRESH_INTERVAL);
11 | }
12 |
13 | public init() {
14 | this.loadSnipeList();
15 | }
16 |
17 | public isInList(mint: string) {
18 | return this.snipeList.includes(mint);
19 | }
20 |
21 | private loadSnipeList() {
22 | logger.trace(`Refreshing snipe list...`);
23 |
24 | const count = this.snipeList.length;
25 | const data = fs.readFileSync(this.fileLocation, 'utf-8');
26 | this.snipeList = data
27 | .split('\n')
28 | .map((a) => a.trim())
29 | .filter((a) => a);
30 |
31 | if (this.snipeList.length != count) {
32 | logger.info(`Loaded snipe list: ${this.snipeList.length}`);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/filters/burn.filter.ts:
--------------------------------------------------------------------------------
1 | import { Filter, FilterResult } from './pool-filters';
2 | import { Connection } from '@solana/web3.js';
3 | import { LiquidityPoolKeysV4 } from '@raydium-io/raydium-sdk';
4 | import { logger } from '../helpers';
5 |
6 | export class BurnFilter implements Filter {
7 | constructor(private readonly connection: Connection) {}
8 |
9 | async execute(poolKeys: LiquidityPoolKeysV4): Promise {
10 | try {
11 | const amount = await this.connection.getTokenSupply(poolKeys.lpMint, this.connection.commitment);
12 | const burned = amount.value.uiAmount === 0;
13 | return { ok: burned, message: burned ? undefined : "Burned -> Creator didn't burn LP" };
14 | } catch (e: any) {
15 | if (e.code == -32602) {
16 | return { ok: true };
17 | }
18 |
19 | logger.error({ mint: poolKeys.baseMint }, `Failed to check if LP is burned`);
20 | }
21 |
22 | return { ok: false, message: 'Failed to check if LP is burned' };
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/filters/index.ts:
--------------------------------------------------------------------------------
1 | export * from './burn.filter';
2 | export * from './mutable.filter';
3 | export * from './pool-filters';
4 | export * from './pool-size.filter';
5 | export * from './renounced.filter';
6 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/filters/mutable.filter.ts:
--------------------------------------------------------------------------------
1 | import { Filter, FilterResult } from './pool-filters';
2 | import { Connection, PublicKey } from '@solana/web3.js';
3 | import { LiquidityPoolKeysV4 } from '@raydium-io/raydium-sdk';
4 | import { getPdaMetadataKey } from '@raydium-io/raydium-sdk';
5 | import { getMetadataAccountDataSerializer, MetadataAccountData, MetadataAccountDataArgs } from '@metaplex-foundation/mpl-token-metadata';
6 | import { Serializer } from '@metaplex-foundation/umi/serializers';
7 | import { logger } from '../helpers';
8 |
9 | export class MutableFilter implements Filter {
10 | constructor(private readonly connection: Connection, private readonly metadataSerializer: Serializer) {}
11 |
12 | async execute(poolKeys: LiquidityPoolKeysV4): Promise {
13 | try {
14 | const metadataPDA = getPdaMetadataKey(poolKeys.baseMint);
15 | const metadataAccount = await this.connection.getAccountInfo(metadataPDA.publicKey);
16 | if (!metadataAccount?.data) {
17 | return { ok: false, message: 'Mutable -> Failed to fetch account data' };
18 | }
19 | const deserialize = this.metadataSerializer.deserialize(metadataAccount.data);
20 | const mutable = deserialize[0].isMutable;
21 |
22 | return { ok: !mutable, message: !mutable ? undefined : "Mutable -> Creator can change metadata" };
23 | } catch (e: any) {
24 | logger.error({ mint: poolKeys.baseMint }, `Mutable -> Failed to check if metadata are mutable`);
25 | }
26 |
27 | return { ok: false, message: 'Mutable -> Failed to check if metadata are mutable' };
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/filters/pool-filters.ts:
--------------------------------------------------------------------------------
1 | import { Connection } from '@solana/web3.js';
2 | import { LiquidityPoolKeysV4, Token, TokenAmount } from '@raydium-io/raydium-sdk';
3 | import { getMetadataAccountDataSerializer } from '@metaplex-foundation/mpl-token-metadata';
4 | import { BurnFilter } from './burn.filter';
5 | import { MutableFilter } from './mutable.filter';
6 | import { RenouncedFreezeFilter } from './renounced.filter';
7 | import { PoolSizeFilter } from './pool-size.filter';
8 | import { CHECK_IF_BURNED, CHECK_IF_FREEZABLE, CHECK_IF_MINT_IS_RENOUNCED, CHECK_IF_MUTABLE, logger } from '../helpers';
9 |
10 | export interface Filter {
11 | execute(poolKeysV4: LiquidityPoolKeysV4): Promise;
12 | }
13 |
14 | export interface FilterResult {
15 | ok: boolean;
16 | message?: string;
17 | }
18 |
19 | export interface PoolFilterArgs {
20 | minPoolSize: TokenAmount;
21 | maxPoolSize: TokenAmount;
22 | quoteToken: Token;
23 | }
24 |
25 | export class PoolFilters {
26 | private readonly filters: Filter[] = [];
27 |
28 | constructor(
29 | readonly connection: Connection,
30 | readonly args: PoolFilterArgs,
31 | ) {
32 | if (CHECK_IF_BURNED) {
33 | this.filters.push(new BurnFilter(connection));
34 | }
35 |
36 | if (CHECK_IF_MINT_IS_RENOUNCED || CHECK_IF_FREEZABLE) {
37 | this.filters.push(new RenouncedFreezeFilter(connection, CHECK_IF_MINT_IS_RENOUNCED, CHECK_IF_FREEZABLE));
38 | }
39 |
40 | if (CHECK_IF_MUTABLE) {
41 | this.filters.push(new MutableFilter(connection, getMetadataAccountDataSerializer()));
42 | }
43 |
44 | if (!args.minPoolSize.isZero() || !args.maxPoolSize.isZero()) {
45 | this.filters.push(new PoolSizeFilter(connection, args.quoteToken, args.minPoolSize, args.maxPoolSize));
46 | }
47 | }
48 |
49 | public async execute(poolKeys: LiquidityPoolKeysV4): Promise {
50 | if (this.filters.length === 0) {
51 | return true;
52 | }
53 |
54 | const result = await Promise.all(this.filters.map((f) => f.execute(poolKeys)));
55 | const pass = result.every((r) => r.ok);
56 |
57 | if (pass) {
58 | return true;
59 | }
60 |
61 | for (const filterResult of result.filter((r) => !r.ok)) {
62 | logger.trace(filterResult.message);
63 | }
64 |
65 | return false;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/filters/pool-size.filter.ts:
--------------------------------------------------------------------------------
1 | import { Filter, FilterResult } from './pool-filters';
2 | import { LiquidityPoolKeysV4, Token, TokenAmount } from '@raydium-io/raydium-sdk';
3 | import { Connection } from '@solana/web3.js';
4 | import { logger } from '../helpers';
5 |
6 | export class PoolSizeFilter implements Filter {
7 | constructor(
8 | private readonly connection: Connection,
9 | private readonly quoteToken: Token,
10 | private readonly minPoolSize: TokenAmount,
11 | private readonly maxPoolSize: TokenAmount,
12 | ) {}
13 |
14 | async execute(poolKeys: LiquidityPoolKeysV4): Promise {
15 | try {
16 | const response = await this.connection.getTokenAccountBalance(poolKeys.quoteVault, this.connection.commitment);
17 | const poolSize = new TokenAmount(this.quoteToken, response.value.amount, true);
18 | let inRange = true;
19 |
20 | if (!this.maxPoolSize?.isZero()) {
21 | inRange = poolSize.raw.lte(this.maxPoolSize.raw);
22 |
23 | if (!inRange) {
24 | return { ok: false, message: `PoolSize -> Pool size ${poolSize.toFixed()} > ${this.maxPoolSize.toFixed()}` };
25 | }
26 | }
27 |
28 | if (!this.minPoolSize?.isZero()) {
29 | inRange = poolSize.raw.gte(this.minPoolSize.raw);
30 |
31 | if (!inRange) {
32 | return { ok: false, message: `PoolSize -> Pool size ${poolSize.toFixed()} < ${this.minPoolSize.toFixed()}` };
33 | }
34 | }
35 |
36 | return { ok: inRange };
37 | } catch (error) {
38 | logger.error({ mint: poolKeys.baseMint }, `Failed to check pool size`);
39 | }
40 |
41 | return { ok: false, message: 'PoolSize -> Failed to check pool size' };
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/filters/renounced.filter.ts:
--------------------------------------------------------------------------------
1 | import { Filter, FilterResult } from './pool-filters';
2 | import { MintLayout } from '@solana/spl-token';
3 | import { Connection } from '@solana/web3.js';
4 | import { LiquidityPoolKeysV4 } from '@raydium-io/raydium-sdk';
5 | import { logger } from '../helpers';
6 |
7 | export class RenouncedFreezeFilter implements Filter {
8 | constructor(private readonly connection: Connection, private readonly checkRenounced: boolean, private readonly checkFreezable: boolean) {}
9 |
10 | async execute(poolKeys: LiquidityPoolKeysV4): Promise {
11 | const errorMessage = [ this.checkRenounced ? 'mint' : undefined, this.checkFreezable ? 'freeze' : undefined ].filter((e) => e !== undefined);
12 | try {
13 | const accountInfo = await this.connection.getAccountInfo(poolKeys.baseMint, this.connection.commitment);
14 | if (!accountInfo?.data) {
15 | return { ok: false, message: 'RenouncedFreeze -> Failed to fetch account data' };
16 | }
17 |
18 | const deserialize = MintLayout.decode(accountInfo.data);
19 | const renounced = !this.checkRenounced || deserialize.mintAuthorityOption === 0;
20 | const freezable = !this.checkFreezable || deserialize.freezeAuthorityOption !== 0;
21 |
22 | const message = [ renounced ? undefined : 'mint', !freezable ? undefined : 'freeze' ].filter((e) => e !== undefined);
23 | const ok = renounced && !freezable;
24 |
25 | return { ok: ok, message: ok ? undefined : `RenouncedFreeze -> Creator can ${message.join(' and ')} tokens` };
26 | } catch (e) {
27 | logger.error({ mint: poolKeys.baseMint }, `RenouncedFreeze -> Failed to check if creator can ${errorMessage.join(' and ')} tokens`);
28 | }
29 |
30 | return { ok: false, message: `RenouncedFreeze -> Failed to check if creator can ${errorMessage.join(' and ')} tokens` };
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/helpers/constants.ts:
--------------------------------------------------------------------------------
1 | import { Logger } from 'pino';
2 | import dotenv from 'dotenv';
3 | import { Commitment } from '@solana/web3.js';
4 | import { logger } from './logger';
5 |
6 | dotenv.config();
7 |
8 | const retrieveEnvVariable = (variableName: string, logger: Logger) => {
9 | const variable = process.env[variableName] || '';
10 | if (!variable) {
11 | logger.error(`${variableName} is not set`);
12 | process.exit(1);
13 | }
14 | return variable;
15 | };
16 |
17 | // Wallet
18 | export const PRIVATE_KEY = retrieveEnvVariable('PRIVATE_KEY', logger);
19 |
20 | // Connection
21 | export const NETWORK = 'mainnet-beta';
22 | export const COMMITMENT_LEVEL: Commitment = retrieveEnvVariable('COMMITMENT_LEVEL', logger) as Commitment;
23 | export const RPC_ENDPOINT = retrieveEnvVariable('RPC_ENDPOINT', logger);
24 | export const RPC_WEBSOCKET_ENDPOINT = retrieveEnvVariable('RPC_WEBSOCKET_ENDPOINT', logger);
25 |
26 | // Bot
27 | export const LOG_LEVEL = retrieveEnvVariable('LOG_LEVEL', logger);
28 | export const ONE_TOKEN_AT_A_TIME = retrieveEnvVariable('ONE_TOKEN_AT_A_TIME', logger) === 'true';
29 | export const COMPUTE_UNIT_LIMIT = Number(retrieveEnvVariable('COMPUTE_UNIT_LIMIT', logger));
30 | export const COMPUTE_UNIT_PRICE = Number(retrieveEnvVariable('COMPUTE_UNIT_PRICE', logger));
31 | export const PRE_LOAD_EXISTING_MARKETS = retrieveEnvVariable('PRE_LOAD_EXISTING_MARKETS', logger) === 'true';
32 | export const CACHE_NEW_MARKETS = retrieveEnvVariable('CACHE_NEW_MARKETS', logger) === 'true';
33 | export const TRANSACTION_EXECUTOR = retrieveEnvVariable('TRANSACTION_EXECUTOR', logger);
34 | export const CUSTOM_FEE = retrieveEnvVariable('CUSTOM_FEE', logger);
35 |
36 | // Buy
37 | export const AUTO_BUY_DELAY = Number(retrieveEnvVariable('AUTO_BUY_DELAY', logger));
38 | export const QUOTE_MINT = retrieveEnvVariable('QUOTE_MINT', logger);
39 | export const QUOTE_AMOUNT = retrieveEnvVariable('QUOTE_AMOUNT', logger);
40 | export const MAX_BUY_RETRIES = Number(retrieveEnvVariable('MAX_BUY_RETRIES', logger));
41 | export const BUY_SLIPPAGE = Number(retrieveEnvVariable('BUY_SLIPPAGE', logger));
42 |
43 | // Sell
44 | export const AUTO_SELL = retrieveEnvVariable('AUTO_SELL', logger) === 'true';
45 | export const AUTO_SELL_DELAY = Number(retrieveEnvVariable('AUTO_SELL_DELAY', logger));
46 | export const MAX_SELL_RETRIES = Number(retrieveEnvVariable('MAX_SELL_RETRIES', logger));
47 | export const TAKE_PROFIT = Number(retrieveEnvVariable('TAKE_PROFIT', logger));
48 | export const STOP_LOSS = Number(retrieveEnvVariable('STOP_LOSS', logger));
49 | export const PRICE_CHECK_INTERVAL = Number(retrieveEnvVariable('PRICE_CHECK_INTERVAL', logger));
50 | export const PRICE_CHECK_DURATION = Number(retrieveEnvVariable('PRICE_CHECK_DURATION', logger));
51 | export const SELL_SLIPPAGE = Number(retrieveEnvVariable('SELL_SLIPPAGE', logger));
52 |
53 | // Filters
54 | export const FILTER_CHECK_INTERVAL = Number(retrieveEnvVariable('FILTER_CHECK_INTERVAL', logger));
55 | export const FILTER_CHECK_DURATION = Number(retrieveEnvVariable('FILTER_CHECK_DURATION', logger));
56 | export const CONSECUTIVE_FILTER_MATCHES = Number(retrieveEnvVariable('CONSECUTIVE_FILTER_MATCHES', logger));
57 | export const CHECK_IF_MUTABLE = retrieveEnvVariable('CHECK_IF_MUTABLE', logger) === 'true';
58 | export const CHECK_IF_MINT_IS_RENOUNCED = retrieveEnvVariable('CHECK_IF_MINT_IS_RENOUNCED', logger) === 'true';
59 | export const CHECK_IF_FREEZABLE = retrieveEnvVariable('CHECK_IF_FREEZABLE', logger) === 'true';
60 | export const CHECK_IF_BURNED = retrieveEnvVariable('CHECK_IF_BURNED', logger) === 'true';
61 | export const MIN_POOL_SIZE = retrieveEnvVariable('MIN_POOL_SIZE', logger);
62 | export const MAX_POOL_SIZE = retrieveEnvVariable('MAX_POOL_SIZE', logger);
63 | export const USE_SNIPE_LIST = retrieveEnvVariable('USE_SNIPE_LIST', logger) === 'true';
64 | export const SNIPE_LIST_REFRESH_INTERVAL = Number(retrieveEnvVariable('SNIPE_LIST_REFRESH_INTERVAL', logger));
65 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/helpers/index.ts:
--------------------------------------------------------------------------------
1 | export * from './market';
2 | export * from './liquidity';
3 | export * from './logger';
4 | export * from './constants';
5 | export * from './token';
6 | export * from './wallet';
7 | export * from './promises'
8 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/helpers/liquidity.ts:
--------------------------------------------------------------------------------
1 | import { PublicKey } from '@solana/web3.js';
2 | import { Liquidity, LiquidityPoolKeys, LiquidityStateV4, MAINNET_PROGRAM_ID, Market } from '@raydium-io/raydium-sdk';
3 | import { MinimalMarketLayoutV3 } from './market';
4 |
5 | export function createPoolKeys(
6 | id: PublicKey,
7 | accountData: LiquidityStateV4,
8 | minimalMarketLayoutV3: MinimalMarketLayoutV3,
9 | ): LiquidityPoolKeys {
10 | return {
11 | id,
12 | baseMint: accountData.baseMint,
13 | quoteMint: accountData.quoteMint,
14 | lpMint: accountData.lpMint,
15 | baseDecimals: accountData.baseDecimal.toNumber(),
16 | quoteDecimals: accountData.quoteDecimal.toNumber(),
17 | lpDecimals: 5,
18 | version: 4,
19 | programId: MAINNET_PROGRAM_ID.AmmV4,
20 | authority: Liquidity.getAssociatedAuthority({
21 | programId: MAINNET_PROGRAM_ID.AmmV4,
22 | }).publicKey,
23 | openOrders: accountData.openOrders,
24 | targetOrders: accountData.targetOrders,
25 | baseVault: accountData.baseVault,
26 | quoteVault: accountData.quoteVault,
27 | marketVersion: 3,
28 | marketProgramId: accountData.marketProgramId,
29 | marketId: accountData.marketId,
30 | marketAuthority: Market.getAssociatedAuthority({
31 | programId: accountData.marketProgramId,
32 | marketId: accountData.marketId,
33 | }).publicKey,
34 | marketBaseVault: accountData.baseVault,
35 | marketQuoteVault: accountData.quoteVault,
36 | marketBids: minimalMarketLayoutV3.bids,
37 | marketAsks: minimalMarketLayoutV3.asks,
38 | marketEventQueue: minimalMarketLayoutV3.eventQueue,
39 | withdrawQueue: accountData.withdrawQueue,
40 | lpVault: accountData.lpVault,
41 | lookupTableAccount: PublicKey.default,
42 | };
43 | }
44 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/helpers/logger.ts:
--------------------------------------------------------------------------------
1 | import pino from 'pino';
2 |
3 | const transport = pino.transport({
4 | target: 'pino-pretty',
5 | });
6 |
7 | export const logger = pino(
8 | {
9 | level: 'info',
10 | redact: ['poolKeys'],
11 | serializers: {
12 | error: pino.stdSerializers.err,
13 | },
14 | base: undefined,
15 | },
16 | transport,
17 | );
18 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/helpers/market.ts:
--------------------------------------------------------------------------------
1 | import { Commitment, Connection, PublicKey } from '@solana/web3.js';
2 | import { GetStructureSchema, MARKET_STATE_LAYOUT_V3, publicKey, struct } from '@raydium-io/raydium-sdk';
3 |
4 | export const MINIMAL_MARKET_STATE_LAYOUT_V3 = struct([publicKey('eventQueue'), publicKey('bids'), publicKey('asks')]);
5 | export type MinimalMarketStateLayoutV3 = typeof MINIMAL_MARKET_STATE_LAYOUT_V3;
6 | export type MinimalMarketLayoutV3 = GetStructureSchema;
7 |
8 | export async function getMinimalMarketV3(
9 | connection: Connection,
10 | marketId: PublicKey,
11 | commitment?: Commitment,
12 | ): Promise {
13 | const marketInfo = await connection.getAccountInfo(marketId, {
14 | commitment,
15 | dataSlice: {
16 | offset: MARKET_STATE_LAYOUT_V3.offsetOf('eventQueue'),
17 | length: 32 * 3,
18 | },
19 | });
20 |
21 | return MINIMAL_MARKET_STATE_LAYOUT_V3.decode(marketInfo!.data);
22 | }
23 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/helpers/promises.ts:
--------------------------------------------------------------------------------
1 | export const sleep = (ms = 0) => new Promise((resolve) => setTimeout(resolve, ms));
2 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/helpers/token.ts:
--------------------------------------------------------------------------------
1 | import { Token } from '@raydium-io/raydium-sdk';
2 | import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
3 | import { PublicKey } from '@solana/web3.js';
4 |
5 | export function getToken(token: string) {
6 | switch (token) {
7 | case 'WSOL': {
8 | return Token.WSOL;
9 | }
10 | case 'USDC': {
11 | return new Token(
12 | TOKEN_PROGRAM_ID,
13 | new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
14 | 6,
15 | 'USDC',
16 | 'USDC',
17 | );
18 | }
19 | default: {
20 | throw new Error(`Unsupported quote mint "${token}". Supported values are USDC and WSOL`);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/helpers/wallet.ts:
--------------------------------------------------------------------------------
1 | import { Keypair } from '@solana/web3.js';
2 | import bs58 from 'bs58';
3 | import { mnemonicToSeedSync } from 'bip39';
4 | import { derivePath } from 'ed25519-hd-key';
5 |
6 | export function getWallet(wallet: string): Keypair {
7 | // most likely someone pasted the private key in binary format
8 | if (wallet.startsWith('[')) {
9 | return Keypair.fromSecretKey(JSON.parse(wallet));
10 | }
11 |
12 | // most likely someone pasted mnemonic
13 | if (wallet.split(' ').length > 1) {
14 | const seed = mnemonicToSeedSync(wallet, '');
15 | const path = `m/44'/501'/0'/0'`; // we assume it's first path
16 | return Keypair.fromSeed(derivePath(path, seed.toString('hex')).key);
17 | }
18 |
19 | // most likely someone pasted base58 encoded private key
20 | return Keypair.fromSecretKey(bs58.decode(wallet));
21 | }
22 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/index.ts:
--------------------------------------------------------------------------------
1 | import { MarketCache, PoolCache } from './cache';
2 | import { Listeners } from './listeners';
3 | import { Connection, KeyedAccountInfo, Keypair } from '@solana/web3.js';
4 | import { LIQUIDITY_STATE_LAYOUT_V4, MARKET_STATE_LAYOUT_V3, Token, TokenAmount } from '@raydium-io/raydium-sdk';
5 | import { AccountLayout, getAssociatedTokenAddressSync } from '@solana/spl-token';
6 | import { Bot, BotConfig } from './bot';
7 | import { DefaultTransactionExecutor, TransactionExecutor } from './transactions';
8 | import {
9 | getToken,
10 | getWallet,
11 | logger,
12 | COMMITMENT_LEVEL,
13 | RPC_ENDPOINT,
14 | RPC_WEBSOCKET_ENDPOINT,
15 | PRE_LOAD_EXISTING_MARKETS,
16 | LOG_LEVEL,
17 | CHECK_IF_MUTABLE,
18 | CHECK_IF_MINT_IS_RENOUNCED,
19 | CHECK_IF_FREEZABLE,
20 | CHECK_IF_BURNED,
21 | QUOTE_MINT,
22 | MAX_POOL_SIZE,
23 | MIN_POOL_SIZE,
24 | QUOTE_AMOUNT,
25 | PRIVATE_KEY,
26 | USE_SNIPE_LIST,
27 | ONE_TOKEN_AT_A_TIME,
28 | AUTO_SELL_DELAY,
29 | MAX_SELL_RETRIES,
30 | AUTO_SELL,
31 | MAX_BUY_RETRIES,
32 | AUTO_BUY_DELAY,
33 | COMPUTE_UNIT_LIMIT,
34 | COMPUTE_UNIT_PRICE,
35 | CACHE_NEW_MARKETS,
36 | TAKE_PROFIT,
37 | STOP_LOSS,
38 | BUY_SLIPPAGE,
39 | SELL_SLIPPAGE,
40 | PRICE_CHECK_DURATION,
41 | PRICE_CHECK_INTERVAL,
42 | SNIPE_LIST_REFRESH_INTERVAL,
43 | TRANSACTION_EXECUTOR,
44 | CUSTOM_FEE,
45 | FILTER_CHECK_INTERVAL,
46 | FILTER_CHECK_DURATION,
47 | CONSECUTIVE_FILTER_MATCHES,
48 | } from './helpers';
49 | import { version } from './package.json';
50 | import { WarpTransactionExecutor } from './transactions/warp-transaction-executor';
51 | import { JitoTransactionExecutor } from './transactions/jito-rpc-transaction-executor';
52 |
53 | const connection = new Connection(RPC_ENDPOINT, {
54 | wsEndpoint: RPC_WEBSOCKET_ENDPOINT,
55 | commitment: COMMITMENT_LEVEL,
56 | });
57 |
58 | function printDetails(wallet: Keypair, quoteToken: Token, bot: Bot) {
59 | logger.info(`
60 |
61 | █████╗ ██╗ ██╗██╗███████╗██████╗ ██████╗ ████████╗
62 | ██╔══██╗╚██╗██╔╝██║██╔════╝██╔══██╗██╔═══██╗╚══██╔══╝
63 | ███████║ ╚███╔╝ ██║███████╗██████╔╝██║ ██║ ██║
64 | ██╔══██║ ██╔██╗ ██║╚════██║██╔══██╗██║ ██║ ██║
65 | ██║ ██║██╔╝ ██╗██║███████║██████╔╝╚██████╔╝ ██║
66 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚══════╝╚═════╝ ╚═════╝ ╚═╝
67 |
68 | AxisBot Solana Sniper v1.0
69 | Made by AxisBot Team
70 | Version: ${version}
71 | `);
72 |
73 | const botConfig = bot.config;
74 |
75 | logger.info('------- CONFIGURATION START -------');
76 | logger.info(`Wallet: ${wallet.publicKey.toString()}`);
77 |
78 | logger.info('- Bot -');
79 |
80 | logger.info(
81 | `Using ${TRANSACTION_EXECUTOR} executer: ${bot.isWarp || bot.isJito || (TRANSACTION_EXECUTOR === 'default' ? true : false)}`,
82 | );
83 | if (bot.isWarp || bot.isJito) {
84 | logger.info(`${TRANSACTION_EXECUTOR} fee: ${CUSTOM_FEE}`);
85 | } else {
86 | logger.info(`Compute Unit limit: ${botConfig.unitLimit}`);
87 | logger.info(`Compute Unit price (micro lamports): ${botConfig.unitPrice}`);
88 | }
89 |
90 | logger.info(`Single token at the time: ${botConfig.oneTokenAtATime}`);
91 | logger.info(`Pre load existing markets: ${PRE_LOAD_EXISTING_MARKETS}`);
92 | logger.info(`Cache new markets: ${CACHE_NEW_MARKETS}`);
93 | logger.info(`Log level: ${LOG_LEVEL}`);
94 |
95 | logger.info('- Buy -');
96 | logger.info(`Buy amount: ${botConfig.quoteAmount.toFixed()} ${botConfig.quoteToken.name}`);
97 | logger.info(`Auto buy delay: ${botConfig.autoBuyDelay} ms`);
98 | logger.info(`Max buy retries: ${botConfig.maxBuyRetries}`);
99 | logger.info(`Buy amount (${quoteToken.symbol}): ${botConfig.quoteAmount.toFixed()}`);
100 | logger.info(`Buy slippage: ${botConfig.buySlippage}%`);
101 |
102 | logger.info('- Sell -');
103 | logger.info(`Auto sell: ${AUTO_SELL}`);
104 | logger.info(`Auto sell delay: ${botConfig.autoSellDelay} ms`);
105 | logger.info(`Max sell retries: ${botConfig.maxSellRetries}`);
106 | logger.info(`Sell slippage: ${botConfig.sellSlippage}%`);
107 | logger.info(`Price check interval: ${botConfig.priceCheckInterval} ms`);
108 | logger.info(`Price check duration: ${botConfig.priceCheckDuration} ms`);
109 | logger.info(`Take profit: ${botConfig.takeProfit}%`);
110 | logger.info(`Stop loss: ${botConfig.stopLoss}%`);
111 |
112 | logger.info('- Snipe list -');
113 | logger.info(`Snipe list: ${botConfig.useSnipeList}`);
114 | logger.info(`Snipe list refresh interval: ${SNIPE_LIST_REFRESH_INTERVAL} ms`);
115 |
116 | if (botConfig.useSnipeList) {
117 | logger.info('- Filters -');
118 | logger.info(`Filters are disabled when snipe list is on`);
119 | } else {
120 | logger.info('- Filters -');
121 | logger.info(`Filter check interval: ${botConfig.filterCheckInterval} ms`);
122 | logger.info(`Filter check duration: ${botConfig.filterCheckDuration} ms`);
123 | logger.info(`Consecutive filter matches: ${botConfig.consecutiveMatchCount}`);
124 | logger.info(`Check renounced: ${botConfig.checkRenounced}`);
125 | logger.info(`Check freezable: ${botConfig.checkFreezable}`);
126 | logger.info(`Check burned: ${botConfig.checkBurned}`);
127 | logger.info(`Min pool size: ${botConfig.minPoolSize.toFixed()}`);
128 | logger.info(`Max pool size: ${botConfig.maxPoolSize.toFixed()}`);
129 | }
130 |
131 | logger.info('------- CONFIGURATION END -------');
132 |
133 | logger.info('Bot is running! Press CTRL + C to stop it.');
134 | }
135 |
136 | const runListener = async () => {
137 | logger.level = LOG_LEVEL;
138 | logger.info('Bot is starting...');
139 |
140 | const marketCache = new MarketCache(connection);
141 | const poolCache = new PoolCache();
142 | let txExecutor: TransactionExecutor;
143 |
144 | switch (TRANSACTION_EXECUTOR) {
145 | case 'warp': {
146 | txExecutor = new WarpTransactionExecutor(CUSTOM_FEE);
147 | break;
148 | }
149 | case 'jito': {
150 | txExecutor = new JitoTransactionExecutor(CUSTOM_FEE, connection);
151 | break;
152 | }
153 | default: {
154 | txExecutor = new DefaultTransactionExecutor(connection);
155 | break;
156 | }
157 | }
158 |
159 | const wallet = getWallet(PRIVATE_KEY.trim());
160 | const quoteToken = getToken(QUOTE_MINT);
161 | const botConfig = {
162 | wallet,
163 | quoteAta: getAssociatedTokenAddressSync(quoteToken.mint, wallet.publicKey),
164 | checkRenounced: CHECK_IF_MINT_IS_RENOUNCED,
165 | checkFreezable: CHECK_IF_FREEZABLE,
166 | checkBurned: CHECK_IF_BURNED,
167 | minPoolSize: new TokenAmount(quoteToken, MIN_POOL_SIZE, false),
168 | maxPoolSize: new TokenAmount(quoteToken, MAX_POOL_SIZE, false),
169 | quoteToken,
170 | quoteAmount: new TokenAmount(quoteToken, QUOTE_AMOUNT, false),
171 | oneTokenAtATime: ONE_TOKEN_AT_A_TIME,
172 | useSnipeList: USE_SNIPE_LIST,
173 | autoSell: AUTO_SELL,
174 | autoSellDelay: AUTO_SELL_DELAY,
175 | maxSellRetries: MAX_SELL_RETRIES,
176 | autoBuyDelay: AUTO_BUY_DELAY,
177 | maxBuyRetries: MAX_BUY_RETRIES,
178 | unitLimit: COMPUTE_UNIT_LIMIT,
179 | unitPrice: COMPUTE_UNIT_PRICE,
180 | takeProfit: TAKE_PROFIT,
181 | stopLoss: STOP_LOSS,
182 | buySlippage: BUY_SLIPPAGE,
183 | sellSlippage: SELL_SLIPPAGE,
184 | priceCheckInterval: PRICE_CHECK_INTERVAL,
185 | priceCheckDuration: PRICE_CHECK_DURATION,
186 | filterCheckInterval: FILTER_CHECK_INTERVAL,
187 | filterCheckDuration: FILTER_CHECK_DURATION,
188 | consecutiveMatchCount: CONSECUTIVE_FILTER_MATCHES,
189 | };
190 |
191 | const bot = new Bot(connection, marketCache, poolCache, txExecutor, botConfig);
192 | const valid = await bot.validate();
193 |
194 | if (!valid) {
195 | logger.info('Bot is exiting...');
196 | process.exit(1);
197 | }
198 |
199 | if (PRE_LOAD_EXISTING_MARKETS) {
200 | await marketCache.init({ quoteToken });
201 | }
202 |
203 | const runTimestamp = Math.floor(new Date().getTime() / 1000);
204 | const listeners = new Listeners(connection);
205 | await listeners.start({
206 | walletPublicKey: wallet.publicKey,
207 | quoteToken,
208 | autoSell: AUTO_SELL,
209 | cacheNewMarkets: CACHE_NEW_MARKETS,
210 | });
211 |
212 | listeners.on('market', (updatedAccountInfo: KeyedAccountInfo) => {
213 | const marketState = MARKET_STATE_LAYOUT_V3.decode(updatedAccountInfo.accountInfo.data);
214 | marketCache.save(updatedAccountInfo.accountId.toString(), marketState);
215 | });
216 |
217 | listeners.on('pool', async (updatedAccountInfo: KeyedAccountInfo) => {
218 | const poolState = LIQUIDITY_STATE_LAYOUT_V4.decode(updatedAccountInfo.accountInfo.data);
219 | const poolOpenTime = parseInt(poolState.poolOpenTime.toString());
220 | const exists = await poolCache.get(poolState.baseMint.toString());
221 |
222 | if (!exists && poolOpenTime > runTimestamp) {
223 | poolCache.save(updatedAccountInfo.accountId.toString(), poolState);
224 | await bot.buy(updatedAccountInfo.accountId, poolState);
225 | }
226 | });
227 |
228 | listeners.on('wallet', async (updatedAccountInfo: KeyedAccountInfo) => {
229 | const accountData = AccountLayout.decode(updatedAccountInfo.accountInfo.data);
230 |
231 | if (accountData.mint.equals(quoteToken.mint)) {
232 | return;
233 | }
234 |
235 | await bot.sell(updatedAccountInfo.accountId, accountData);
236 | });
237 |
238 | printDetails(wallet, quoteToken, bot);
239 | };
240 |
241 | runListener();
242 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/listeners/index.ts:
--------------------------------------------------------------------------------
1 | export * from './listeners';
2 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/listeners/listeners.ts:
--------------------------------------------------------------------------------
1 | import { LIQUIDITY_STATE_LAYOUT_V4, MAINNET_PROGRAM_ID, MARKET_STATE_LAYOUT_V3, Token } from '@raydium-io/raydium-sdk';
2 | import bs58 from 'bs58';
3 | import { Connection, PublicKey } from '@solana/web3.js';
4 | import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
5 | import { EventEmitter } from 'events';
6 |
7 | export class Listeners extends EventEmitter {
8 | private subscriptions: number[] = [];
9 |
10 | constructor(private readonly connection: Connection) {
11 | super();
12 | }
13 |
14 | public async start(config: {
15 | walletPublicKey: PublicKey;
16 | quoteToken: Token;
17 | autoSell: boolean;
18 | cacheNewMarkets: boolean;
19 | }) {
20 | if (config.cacheNewMarkets) {
21 | const openBookSubscription = await this.subscribeToOpenBookMarkets(config);
22 | this.subscriptions.push(openBookSubscription);
23 | }
24 |
25 | const raydiumSubscription = await this.subscribeToRaydiumPools(config);
26 | this.subscriptions.push(raydiumSubscription);
27 |
28 | if (config.autoSell) {
29 | const walletSubscription = await this.subscribeToWalletChanges(config);
30 | this.subscriptions.push(walletSubscription);
31 | }
32 | }
33 |
34 | private async subscribeToOpenBookMarkets(config: { quoteToken: Token }) {
35 | return this.connection.onProgramAccountChange(
36 | MAINNET_PROGRAM_ID.OPENBOOK_MARKET,
37 | async (updatedAccountInfo) => {
38 | this.emit('market', updatedAccountInfo);
39 | },
40 | this.connection.commitment,
41 | [
42 | { dataSize: MARKET_STATE_LAYOUT_V3.span },
43 | {
44 | memcmp: {
45 | offset: MARKET_STATE_LAYOUT_V3.offsetOf('quoteMint'),
46 | bytes: config.quoteToken.mint.toBase58(),
47 | },
48 | },
49 | ],
50 | );
51 | }
52 |
53 | private async subscribeToRaydiumPools(config: { quoteToken: Token }) {
54 | return this.connection.onProgramAccountChange(
55 | MAINNET_PROGRAM_ID.AmmV4,
56 | async (updatedAccountInfo) => {
57 | this.emit('pool', updatedAccountInfo);
58 | },
59 | this.connection.commitment,
60 | [
61 | { dataSize: LIQUIDITY_STATE_LAYOUT_V4.span },
62 | {
63 | memcmp: {
64 | offset: LIQUIDITY_STATE_LAYOUT_V4.offsetOf('quoteMint'),
65 | bytes: config.quoteToken.mint.toBase58(),
66 | },
67 | },
68 | {
69 | memcmp: {
70 | offset: LIQUIDITY_STATE_LAYOUT_V4.offsetOf('marketProgramId'),
71 | bytes: MAINNET_PROGRAM_ID.OPENBOOK_MARKET.toBase58(),
72 | },
73 | },
74 | {
75 | memcmp: {
76 | offset: LIQUIDITY_STATE_LAYOUT_V4.offsetOf('status'),
77 | bytes: bs58.encode([6, 0, 0, 0, 0, 0, 0, 0]),
78 | },
79 | },
80 | ],
81 | );
82 | }
83 |
84 | private async subscribeToWalletChanges(config: { walletPublicKey: PublicKey }) {
85 | return this.connection.onProgramAccountChange(
86 | TOKEN_PROGRAM_ID,
87 | async (updatedAccountInfo) => {
88 | this.emit('wallet', updatedAccountInfo);
89 | },
90 | this.connection.commitment,
91 | [
92 | {
93 | dataSize: 165,
94 | },
95 | {
96 | memcmp: {
97 | offset: 32,
98 | bytes: config.walletPublicKey.toBase58(),
99 | },
100 | },
101 | ],
102 | );
103 | }
104 |
105 | public async stop() {
106 | for (let i = this.subscriptions.length; i >= 0; --i) {
107 | const subscription = this.subscriptions[i];
108 | await this.connection.removeAccountChangeListener(subscription);
109 | this.subscriptions.splice(i, 1);
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "axisbot-solana-sniper",
3 | "author": "AxisBot",
4 | "homepage": "https://axisbot.xyz",
5 | "version": "1.0.1",
6 | "scripts": {
7 | "start": "ts-node index.ts",
8 | "tsc": "tsc --noEmit"
9 | },
10 | "dependencies": {
11 | "@metaplex-foundation/mpl-token-metadata": "^3.2.1",
12 | "@raydium-io/raydium-sdk": "^1.3.1-beta.47",
13 | "@solana/spl-token": "^0.4.0",
14 | "@solana/web3.js": "^1.89.1",
15 | "async-mutex": "^0.5.0",
16 | "axios": "^1.6.8",
17 | "bigint-buffer": "^1.1.5",
18 | "bip39": "^3.1.0",
19 | "bn.js": "^5.2.1",
20 | "bs58": "^5.0.0",
21 | "dotenv": "^16.4.1",
22 | "ed25519-hd-key": "^1.3.0",
23 | "i": "^0.3.7",
24 | "npm": "^10.5.2",
25 | "pino": "^8.18.0",
26 | "pino-pretty": "^10.3.1",
27 | "pino-std-serializers": "^6.2.2"
28 | },
29 | "devDependencies": {
30 | "@types/bn.js": "^5.1.5",
31 | "prettier": "^3.2.4",
32 | "ts-node": "^10.9.2",
33 | "typescript": "^5.3.3"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/snipe-list.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kent7j/cc7/5513027b90ac474b4b05670e891c19d11580de2e/Bot原版/Bot Solana Sniper Main/snipe-list.txt
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/transactions/default-transaction-executor.ts:
--------------------------------------------------------------------------------
1 | import {
2 | BlockhashWithExpiryBlockHeight,
3 | Connection,
4 | Keypair,
5 | Transaction,
6 | VersionedTransaction,
7 | } from '@solana/web3.js';
8 | import { TransactionExecutor } from './transaction-executor.interface';
9 | import { logger } from '../helpers';
10 |
11 | export class DefaultTransactionExecutor implements TransactionExecutor {
12 | constructor(private readonly connection: Connection) {}
13 |
14 | public async executeAndConfirm(
15 | transaction: VersionedTransaction,
16 | payer: Keypair,
17 | latestBlockhash: BlockhashWithExpiryBlockHeight,
18 | ): Promise<{ confirmed: boolean; signature?: string }> {
19 | logger.debug('Executing transaction...');
20 | const signature = await this.execute(transaction);
21 |
22 | logger.debug({ signature }, 'Confirming transaction...');
23 | return this.confirm(signature, latestBlockhash);
24 | }
25 |
26 | private async execute(transaction: Transaction | VersionedTransaction) {
27 | return this.connection.sendRawTransaction(transaction.serialize(), {
28 | preflightCommitment: this.connection.commitment,
29 | });
30 | }
31 |
32 | private async confirm(signature: string, latestBlockhash: BlockhashWithExpiryBlockHeight) {
33 | const confirmation = await this.connection.confirmTransaction(
34 | {
35 | signature,
36 | lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
37 | blockhash: latestBlockhash.blockhash,
38 | },
39 | this.connection.commitment,
40 | );
41 |
42 | return { confirmed: !confirmation.value.err, signature };
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/transactions/index.ts:
--------------------------------------------------------------------------------
1 | export * from './default-transaction-executor';
2 | export * from './transaction-executor.interface';
3 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/transactions/jito-rpc-transaction-executor.ts:
--------------------------------------------------------------------------------
1 | import {
2 | BlockhashWithExpiryBlockHeight,
3 | Keypair,
4 | PublicKey,
5 | SystemProgram,
6 | Connection,
7 | TransactionMessage,
8 | VersionedTransaction,
9 | } from '@solana/web3.js';
10 | import { TransactionExecutor } from './transaction-executor.interface';
11 | import { logger } from '../helpers';
12 | import axios, { AxiosError } from 'axios';
13 | import bs58 from 'bs58';
14 | import { Currency, CurrencyAmount } from '@raydium-io/raydium-sdk';
15 |
16 | export class JitoTransactionExecutor implements TransactionExecutor {
17 | // https://jito-labs.gitbook.io/mev/searcher-resources/json-rpc-api-reference/bundles/gettipaccounts
18 | private jitpTipAccounts = [
19 | 'Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY',
20 | 'DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL',
21 | '96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5',
22 | '3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT',
23 | 'HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe',
24 | 'ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49',
25 | 'ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt',
26 | 'DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh',
27 | ];
28 |
29 | private JitoFeeWallet: PublicKey;
30 |
31 | constructor(
32 | private readonly jitoFee: string,
33 | private readonly connection: Connection,
34 | ) {
35 | this.JitoFeeWallet = this.getRandomValidatorKey();
36 | }
37 |
38 | private getRandomValidatorKey(): PublicKey {
39 | const randomValidator = this.jitpTipAccounts[Math.floor(Math.random() * this.jitpTipAccounts.length)];
40 | return new PublicKey(randomValidator);
41 | }
42 |
43 | public async executeAndConfirm(
44 | transaction: VersionedTransaction,
45 | payer: Keypair,
46 | latestBlockhash: BlockhashWithExpiryBlockHeight,
47 | ): Promise<{ confirmed: boolean; signature?: string }> {
48 | logger.debug('Starting Jito transaction execution...');
49 | this.JitoFeeWallet = this.getRandomValidatorKey(); // Update wallet key each execution
50 | logger.trace(`Selected Jito fee wallet: ${this.JitoFeeWallet.toBase58()}`);
51 |
52 | try {
53 | const fee = new CurrencyAmount(Currency.SOL, this.jitoFee, false).raw.toNumber();
54 | logger.trace(`Calculated fee: ${fee} lamports`);
55 |
56 | const jitTipTxFeeMessage = new TransactionMessage({
57 | payerKey: payer.publicKey,
58 | recentBlockhash: latestBlockhash.blockhash,
59 | instructions: [
60 | SystemProgram.transfer({
61 | fromPubkey: payer.publicKey,
62 | toPubkey: this.JitoFeeWallet,
63 | lamports: fee,
64 | }),
65 | ],
66 | }).compileToV0Message();
67 |
68 | const jitoFeeTx = new VersionedTransaction(jitTipTxFeeMessage);
69 | jitoFeeTx.sign([payer]);
70 |
71 | const jitoTxsignature = bs58.encode(jitoFeeTx.signatures[0]);
72 |
73 | // Serialize the transactions once here
74 | const serializedjitoFeeTx = bs58.encode(jitoFeeTx.serialize());
75 | const serializedTransaction = bs58.encode(transaction.serialize());
76 | const serializedTransactions = [serializedjitoFeeTx, serializedTransaction];
77 |
78 | // https://jito-labs.gitbook.io/mev/searcher-resources/json-rpc-api-reference/url
79 | const endpoints = [
80 | 'https://mainnet.block-engine.jito.wtf/api/v1/bundles',
81 | 'https://amsterdam.mainnet.block-engine.jito.wtf/api/v1/bundles',
82 | 'https://frankfurt.mainnet.block-engine.jito.wtf/api/v1/bundles',
83 | 'https://ny.mainnet.block-engine.jito.wtf/api/v1/bundles',
84 | 'https://tokyo.mainnet.block-engine.jito.wtf/api/v1/bundles',
85 | ];
86 |
87 | const requests = endpoints.map((url) =>
88 | axios.post(url, {
89 | jsonrpc: '2.0',
90 | id: 1,
91 | method: 'sendBundle',
92 | params: [serializedTransactions],
93 | }),
94 | );
95 |
96 | logger.trace('Sending transactions to endpoints...');
97 | const results = await Promise.all(requests.map((p) => p.catch((e) => e)));
98 |
99 | const successfulResults = results.filter((result) => !(result instanceof Error));
100 |
101 | if (successfulResults.length > 0) {
102 | logger.trace(`At least one successful response`);
103 | logger.debug(`Confirming jito transaction...`);
104 | return await this.confirm(jitoTxsignature, latestBlockhash);
105 | } else {
106 | logger.debug(`No successful responses received for jito`);
107 | }
108 |
109 | return { confirmed: false };
110 | } catch (error) {
111 | if (error instanceof AxiosError) {
112 | logger.trace({ error: error.response?.data }, 'Failed to execute jito transaction');
113 | }
114 | logger.error('Error during transaction execution', error);
115 | return { confirmed: false };
116 | }
117 | }
118 |
119 | private async confirm(signature: string, latestBlockhash: BlockhashWithExpiryBlockHeight) {
120 | const confirmation = await this.connection.confirmTransaction(
121 | {
122 | signature,
123 | lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
124 | blockhash: latestBlockhash.blockhash,
125 | },
126 | this.connection.commitment,
127 | );
128 |
129 | return { confirmed: !confirmation.value.err, signature };
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/transactions/transaction-executor.interface.ts:
--------------------------------------------------------------------------------
1 | import { BlockhashWithExpiryBlockHeight, Keypair, VersionedTransaction } from '@solana/web3.js';
2 |
3 | export interface TransactionExecutor {
4 | executeAndConfirm(
5 | transaction: VersionedTransaction,
6 | payer: Keypair,
7 | latestBlockHash: BlockhashWithExpiryBlockHeight,
8 | ): Promise<{ confirmed: boolean; signature?: string, error?: string }>;
9 | }
10 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/transactions/warp-transaction-executor.ts:
--------------------------------------------------------------------------------
1 | import {
2 | BlockhashWithExpiryBlockHeight,
3 | Keypair,
4 | PublicKey,
5 | SystemProgram,
6 | TransactionMessage,
7 | VersionedTransaction,
8 | } from '@solana/web3.js';
9 | import { TransactionExecutor } from './transaction-executor.interface';
10 | import { logger } from '../helpers';
11 | import axios, { AxiosError } from 'axios';
12 | import bs58 from 'bs58';
13 | import { Currency, CurrencyAmount } from '@raydium-io/raydium-sdk';
14 |
15 | export class WarpTransactionExecutor implements TransactionExecutor {
16 | private readonly warpFeeWallet = new PublicKey('AXSBTx227eh6ZtEu5kHrKCWviW6R1JJV7oDJ63tX9GiH');
17 |
18 | constructor(private readonly warpFee: string) {}
19 |
20 | public async executeAndConfirm(
21 | transaction: VersionedTransaction,
22 | payer: Keypair,
23 | latestBlockhash: BlockhashWithExpiryBlockHeight,
24 | ): Promise<{ confirmed: boolean; signature?: string }> {
25 | logger.debug('Executing transaction...');
26 |
27 | try {
28 | const fee = new CurrencyAmount(Currency.SOL, this.warpFee, false).raw.toNumber();
29 | const warpFeeMessage = new TransactionMessage({
30 | payerKey: payer.publicKey,
31 | recentBlockhash: latestBlockhash.blockhash,
32 | instructions: [
33 | SystemProgram.transfer({
34 | fromPubkey: payer.publicKey,
35 | toPubkey: this.warpFeeWallet,
36 | lamports: fee,
37 | }),
38 | ],
39 | }).compileToV0Message();
40 |
41 | const warpFeeTx = new VersionedTransaction(warpFeeMessage);
42 | warpFeeTx.sign([payer]);
43 |
44 | const response = await axios.post<{ confirmed: boolean; signature: string, error?: string }>(
45 | 'https://tx.warp.id/transaction/execute',
46 | {
47 | transactions: [bs58.encode(warpFeeTx.serialize()), bs58.encode(transaction.serialize())],
48 | latestBlockhash,
49 | },
50 | {
51 | timeout: 100000,
52 | },
53 | );
54 |
55 | return response.data;
56 | } catch (error) {
57 | if (error instanceof AxiosError) {
58 | logger.trace({ error: error.response?.data }, 'Failed to execute warp transaction');
59 | }
60 | }
61 |
62 | return { confirmed: false };
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Bot原版/Bot Solana Sniper Main/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig to read more about this file */
4 |
5 | /* Projects */
6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12 |
13 | /* Language and Environment */
14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16 | // "jsx": "preserve", /* Specify what JSX code is generated. */
17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
26 |
27 | /* Modules */
28 | "module": "commonjs", /* Specify what module code is generated. */
29 | // "rootDir": "./", /* Specify the root folder within your source files. */
30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */
36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
42 | "resolveJsonModule": true, /* Enable importing .json files. */
43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
45 |
46 | /* JavaScript Support */
47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
50 |
51 | /* Emit */
52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */
54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
57 | // "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. */
58 | // "outDir": "./", /* Specify an output folder for all emitted files. */
59 | // "removeComments": true, /* Disable emitting comments. */
60 | // "noEmit": true, /* Disable emitting files from a compilation. */
61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
68 | // "newLine": "crlf", /* Set the newline character for emitting files. */
69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
75 |
76 | /* Interop Constraints */
77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
78 | // "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. */
79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
83 |
84 | /* Type Checking */
85 | "strict": true, /* Enable all strict type-checking options. */
86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
104 |
105 | /* Completeness */
106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/.gitignore:
--------------------------------------------------------------------------------
1 | **/node_modules
2 | .DS_Store
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/README.md:
--------------------------------------------------------------------------------
1 | # AxisBot Solana Spam Sniper
2 | ## Overview
3 | This project is Solana SPL-Token sniper which aims to swap (purchase) new Raydium liquidity pairs within the first price candle by scanning Solana blockchain transactions.
4 | ## How the program works
5 | * Scans the Solana blockchain for an "initialize market" transaction which is decoded for all necessary liquidity pool keys and related information.
6 | * Begins sending/retrying the "swap" transaction until the liquidity pool is live, minimizing the time between the transaction and the creation of the LP.
7 | * Upon sending a valid transaction, begins to track the users position with current price/percent gain by scanning and decoding on-chain liquidity pool information in order to get the most accurate data.
8 | npm 18.17.0 or lower
9 | ## Setup
10 | Use the following instructions to install and run the program (assume node is installed):
11 | 1. Create a Solana wallet and obtain public and private keys (Phantom wallet recommended).
12 | 2. Obtain a Solana RPC/websocket connection, `https://solana-mainnet.rpc.extrnode.com/5b667693-6518-4921-8ea1-4f65ff09c463` and `wss://solana-mainnet.rpc.extrnode.com/5b667693-6518-4921-8ea1-4f65ff09c463` for testing purposes.
13 | 3. Run `npm install`.
14 | 4. Inside the `utils/config.js` file, enter public key, private key, and both RPC connections. Also include amount of SOL to use per swap.
15 | ## Running the scripts
16 | This project contains two different strategies for sniping new liquidity pairs:\
17 | ### **Strategy #1:**
18 | * The first strategy obtains necessary liquidity pool keys from the transaction which creates the LP. To run this script with `node strategy1/start1.js`. The transaction may fail multiple times before succeeding as Solana transactions can be dropped with certain RPC nodes.
19 | * **NOTE:** this script is slower as it must wait for the "add liquidity" transaction to reach "confirmed" status before obtaining pool data. This results in ~30 seconds between the pool creation and swap transaction.
20 | ### **Strategy #2:**
21 | * The second strategy obtains necessary liquidity pool keys from the "initialize market" transaction which typically occurs ~2 minutes before the LP is live on Raydium. This allows for all pool keys to be precomputed. This script also retries the swap transaction multiple times per second which allows for the swap to be sent during the "processed" state of the "add liquidity" transaction instead of "confirmed", greatly reducing the time between the creation of the LP and the swap transaction. This script can be run with `node strategy2/start2.js`.
22 | *Both scripts utilize the same swapping/position management system found in `./swap/swap1.js` and `/swap/swap2.js`.*
23 | ### **Additional Notes:**
24 | * Once the program is started, an output will only be displayed once a new market id/pool is found.
25 | * "the amm account owner is not match with this program + error 0x1b": This error occurs when the program sends a swap tx to a pool that doesn't have liquidity yet. The tx spam is part of the sniping strategy and the error will occur until the swap to the pool goes through (moment liquidity is added).
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@openbook-dex/openbook": "^0.0.9",
4 | "@raydium-io/raydium-sdk": "^1.3.1-beta.46",
5 | "@solana/spl-token": "^0.3.11",
6 | "@solana/web3.js": "^1.87.6",
7 | "borsh": "^2.0.0",
8 | "bs64": "^0.1.0",
9 | "node": "^21.2.0"
10 | },
11 | "name": "solana",
12 | "version": "1.0.0",
13 | "main": "tx.js",
14 | "scripts": {
15 | "test": "echo \"Error: no test specified\" && exit 1"
16 | },
17 | "author": "",
18 | "license": "ISC",
19 | "description": ""
20 | }
21 |
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/strategy1/formatAmmKeysById.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | Object.defineProperty(exports, "__esModule", { value: true });
12 | exports.formatAmmKeysById = void 0;
13 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
14 | const web3_js_1 = require("@solana/web3.js");
15 | const config_1 = require("../utils/config.js");
16 | function formatAmmKeysById(id) {
17 | return __awaiter(this, void 0, void 0, function* () {
18 | const account = yield config_1.connection.getAccountInfo(new web3_js_1.PublicKey(id));
19 | if (account === null)
20 | throw Error(' get id info error ');
21 | const info = raydium_sdk_1.LIQUIDITY_STATE_LAYOUT_V4.decode(account.data);
22 | const marketId = info.marketId;
23 | const marketAccount = yield config_1.connection.getAccountInfo(marketId);
24 | if (marketAccount === null)
25 | throw Error(' get market info error');
26 | const marketInfo = raydium_sdk_1.MARKET_STATE_LAYOUT_V3.decode(marketAccount.data);
27 | const lpMint = info.lpMint;
28 | const lpMintAccount = yield config_1.connection.getAccountInfo(lpMint);
29 | if (lpMintAccount === null)
30 | throw Error(' get lp mint info error');
31 | const lpMintInfo = raydium_sdk_1.SPL_MINT_LAYOUT.decode(lpMintAccount.data);
32 | return {
33 | id,
34 | baseMint: info.baseMint.toString(),
35 | quoteMint: info.quoteMint.toString(),
36 | lpMint: info.lpMint.toString(),
37 | baseDecimals: info.baseDecimal.toNumber(),
38 | quoteDecimals: info.quoteDecimal.toNumber(),
39 | // lpDecimals: lpMintInfo.decimals,
40 | lpDecimals: info.baseDecimal.toNumber(),
41 | version: 4,
42 | programId: account.owner.toString(),
43 | authority: raydium_sdk_1.Liquidity.getAssociatedAuthority({ programId: account.owner }).publicKey.toString(),
44 | openOrders: info.openOrders.toString(),
45 | targetOrders: info.targetOrders.toString(),
46 | baseVault: info.baseVault.toString(),
47 | quoteVault: info.quoteVault.toString(),
48 | withdrawQueue: info.withdrawQueue.toString(),
49 | lpVault: info.lpVault.toString(),
50 | marketVersion: 3,
51 | marketProgramId: info.marketProgramId.toString(),
52 | marketId: info.marketId.toString(),
53 | marketAuthority: raydium_sdk_1.Market.getAssociatedAuthority({ programId: info.marketProgramId, marketId: info.marketId }).publicKey.toString(),
54 | marketBaseVault: marketInfo.baseVault.toString(),
55 | marketQuoteVault: marketInfo.quoteVault.toString(),
56 | marketBids: marketInfo.bids.toString(),
57 | marketAsks: marketInfo.asks.toString(),
58 | marketEventQueue: marketInfo.eventQueue.toString(),
59 | lookupTableAccount: web3_js_1.PublicKey.default.toString()
60 | };
61 | });
62 | }
63 | exports.formatAmmKeysById = formatAmmKeysById;
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/strategy1/start1.js:
--------------------------------------------------------------------------------
1 | const web3 = require('@solana/web3.js')
2 | const WebSocket = require('ws')
3 | const swap = require('./swap1.js')
4 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
5 | const config = require('../utils/config.js');
6 |
7 | const connection = config.connection;
8 | const ws = new WebSocket(config.websocketConnection)
9 | ws.onopen = () => {
10 | ws.send(
11 | JSON.stringify({
12 | jsonrpc: '2.0',
13 | id: 1,
14 | method: 'blockSubscribe',
15 | params: [{"mentionsAccountOrProgram": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"}, {"commitment": "confirmed", "maxSupportedTransactionVersion": 0, "encoding": "jsonParsed"}]
16 | })
17 | )
18 | }
19 |
20 | ws.on('message', (evt) => {
21 | try {
22 | const buffer = evt.toString('utf8');
23 | parseBlock(JSON.parse(buffer));
24 | return;
25 | } catch (e) {
26 | console.log(e)
27 | }
28 | })
29 |
30 | function isStatusError(status){
31 | if(status.hasOwnProperty('Err')){
32 | return true;
33 | }
34 | else if(status.hasOwnProperty('Ok')){
35 | return false;
36 | }
37 | }
38 |
39 | async function getTx(tx){
40 | return await connection.getTransaction(tx, {
41 | "commitment": "confirmed",
42 | "maxSupportedTransactionVersion": 0,
43 | "encoded": "jsonParsed"
44 | })
45 | }
46 |
47 | let swapped = false;
48 | function parseBlock(transaction){
49 | try{
50 | const tx = transaction.params.result.value.block.transactions;
51 | for(let i = 0; i < tx.length; i++){
52 | if(tx[i].meta.innerInstructions !== undefined && tx[i].meta.innerInstructions.length !== 0){
53 | if(tx[i].meta.innerInstructions[0].instructions.length === 32 && !isStatusError(tx[i].meta.status)){
54 | const signature = tx[i].transaction.signatures[0];
55 | console.log(tx[i].transaction.signatures);
56 | if(swapped === false){
57 | swapped = true;
58 | let now = new Date();
59 | let utcString = now.toUTCString();
60 | console.log(utcString);
61 | ws.close();
62 | }
63 | }
64 | }
65 | }
66 | } catch(error){
67 | console.log("searching...")
68 | }
69 | }
70 |
71 | async function getJsonPoolInfo(tx){
72 | // market account
73 | const marketAccount = await connection.getAccountInfo(new web3.PublicKey(tx.transaction.message.accountKeys[19].pubkey));
74 | const marketInfo = raydium_sdk_1.MARKET_STATE_LAYOUT_V3.decode(marketAccount.data);
75 | // get decimals
76 | const getTokenAccount = await connection.getParsedAccountInfo(new web3.PublicKey(tx.transaction.message.accountKeys[17].pubkey));
77 | const decimals = getTokenAccount.value.data.parsed.info.decimals;
78 | // create poolKeys object
79 | const keys = {
80 | id: tx.transaction.message.accountKeys[2].pubkey,
81 | baseMint: tx.transaction.message.accountKeys[17].pubkey,
82 | quoteMint: 'So11111111111111111111111111111111111111112',
83 | lpMint: tx.transaction.message.accountKeys[4].pubkey,
84 | baseDecimals: decimals,
85 | quoteDecimals: 9,
86 | lpDecimals: decimals,
87 | version: 4,
88 | programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',
89 | authority: '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1',
90 | openOrders: tx.transaction.message.accountKeys[3].pubkey,
91 | targetOrders: tx.transaction.message.accountKeys[7].pubkey,
92 | baseVault: tx.transaction.message.accountKeys[5].pubkey,
93 | quoteVault: tx.transaction.message.accountKeys[6].pubkey,
94 | withdrawQueue: '11111111111111111111111111111111',
95 | lpVault: '11111111111111111111111111111111',
96 | marketVersion: 3,
97 | marketProgramId: tx.transaction.message.accountKeys[22].pubkey,
98 | marketId: tx.transaction.message.accountKeys[19].pubkey,
99 | marketAuthority: raydium_sdk_1.Market.getAssociatedAuthority({ programId: new web3.PublicKey(tx.transaction.message.accountKeys[22].pubkey), marketId: new web3.PublicKey(tx.transaction.message.accountKeys[19].pubkey) }).publicKey.toString(),
100 | marketBaseVault: marketInfo.baseVault.toString(),
101 | marketQuoteVault: marketInfo.quoteVault.toString(),
102 | marketBids: marketInfo.bids.toString(),
103 | marketAsks: marketInfo.asks.toString(),
104 | marketEventQueue: marketInfo.eventQueue.toString(),
105 | lookupTableAccount: '11111111111111111111111111111111'
106 | }
107 | // convert poolKeys object to JSON
108 | const jsonPoolKeys = raydium_sdk_1.jsonInfo2PoolKeys(keys);
109 | swap.swap(jsonPoolKeys, tx.transaction.message.accountKeys[17].pubkey);
110 | }
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/strategy1/swap1.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | var __importDefault = (this && this.__importDefault) || function (mod) {
12 | return (mod && mod.__esModule) ? mod : { "default": mod };
13 | };
14 | Object.defineProperty(exports, "__esModule", { value: true });
15 | const assert_1 = __importDefault(require("assert"));
16 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
17 | const config_1 = require("../utils/config.js");
18 | const formatAmmKeysById_1 = require("./formatAmmKeysById.js");
19 | const util_1 = require("../utils/util.js");
20 | const { LAMPORTS_PER_SOL } = require("@solana/web3.js");
21 | const web3 = require("@solana/web3.js");
22 | const connection = config_1.connection;
23 | function swapOnlyAmm(input) {
24 | return __awaiter(this, void 0, void 0, function* () {
25 | const outputToken = new raydium_sdk_1.Token(raydium_sdk_1.TOKEN_PROGRAM_ID, new web3.PublicKey(input.tokenAddress), input.poolKeys.lpDecimals);
26 | const { innerTransactions } = yield raydium_sdk_1.Liquidity.makeSwapInstructionSimple({
27 | connection: config_1.connection,
28 | poolKeys: input.poolKeys,
29 | userKeys: {
30 | tokenAccounts: input.walletTokenAccounts,
31 | owner: input.wallet.publicKey,
32 | },
33 | amountIn: input.inputTokenAmount,
34 | amountOut: new raydium_sdk_1.TokenAmount(outputToken, 1),
35 | fixedSide: 'in',
36 | makeTxVersion: config_1.makeTxVersion,
37 | });
38 | return { txids: yield (0, util_1.buildAndSendTx)(innerTransactions) };
39 | });
40 | }
41 |
42 | const buyAmtSol = config_1.amtBuySol;
43 | function swap(poolKeys, tokenAddress) {
44 | return __awaiter(this, void 0, void 0, function* () {
45 | const ownerAddress = config_1.ownerAddress;
46 | const inputToken = new raydium_sdk_1.Token(raydium_sdk_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey('So11111111111111111111111111111111111111112'), 9, 'WSOL', 'WSOL'); // WSOL
47 | const inputTokenAmount = new raydium_sdk_1.TokenAmount(inputToken, LAMPORTS_PER_SOL * buyAmtSol);
48 | const slippage = new raydium_sdk_1.Percent(1, 100);
49 | const walletTokenAccounts = yield (0, util_1.getWalletTokenAccount)(config_1.connection, config_1.wallet.publicKey);
50 | swapOnlyAmm({
51 | poolKeys,
52 | tokenAddress,
53 | inputTokenAmount,
54 | slippage,
55 | walletTokenAccounts,
56 | wallet: config_1.wallet,
57 | }).then(({ txids }) => {
58 | /** continue with txids */
59 | console.log('txids', txids);
60 | if(txids.length === 1){
61 | monitorTokenSell(txids[0], tokenAddress, ownerAddress, poolKeys.baseVault.toString(), poolKeys.quoteVault.toString());
62 | }
63 | }).catch(error => {
64 | console.log(error);
65 | swap(poolKeys, tokenAddress);
66 | })
67 | });
68 | }
69 | exports.swap = swap
70 |
71 | async function getTx(tx){
72 | return await connection.getTransaction(tx, {
73 | maxSupportedTransactionVersion: 0,
74 | commitment: "confirmed"
75 | })
76 | }
77 |
78 | async function getBalances(tx, tokenAddress, ownerAddress){
79 | let validTx = await getTx(tx);
80 | while(validTx === null){
81 | validTx = await getTx(tx);
82 | if(validTx !== null){
83 | for(const account of validTx.meta.postTokenBalances){
84 | if(account.mint === tokenAddress && account.owner === ownerAddress){
85 | return account.uiTokenAmount.uiAmount;
86 | }
87 | }
88 | }
89 | }
90 | }
91 |
92 | async function getTokenPriceInSol(baseVault, quoteVault){
93 | const baseVaultAccount = await connection.getTokenAccountBalance(new web3.PublicKey(baseVault));
94 | const quoteVaultAccount = await connection.getTokenAccountBalance(new web3.PublicKey(quoteVault));
95 | const baseVaultAccountAmount = baseVaultAccount.value.uiAmount;
96 | const quoteVaultAccountAmount = quoteVaultAccount.value.uiAmount;
97 | return (quoteVaultAccountAmount / baseVaultAccountAmount);
98 | }
99 |
100 | async function monitorTokenSell(tx, tokenAddress, ownerAddress, baseVault, quoteVault){
101 | const tokenBalance = await getBalances(tx, tokenAddress, ownerAddress);
102 | const buyPrice = (buyAmtSol / tokenBalance);
103 | monitorToken(buyPrice, baseVault, quoteVault);
104 | }
105 |
106 | async function monitorToken(buyPrice, baseVault, quoteVault){
107 | let interval = setInterval(async () => {
108 | const currentPrice = await getTokenPriceInSol(baseVault, quoteVault);
109 | console.log("buy price: " + buyPrice + " current price: " + currentPrice);
110 | const percentIncrease = ((buyPrice - currentPrice) / buyPrice) * 100;
111 | console.log("percent increase: " + percentIncrease);
112 | }, 500)
113 | }
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/strategy2/derivePoolKeys.js:
--------------------------------------------------------------------------------
1 | const web3 = require('@solana/web3.js');
2 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
3 | const spl = require('@solana/spl-token');
4 | const {Market} = require('@openbook-dex/openbook');
5 | const config = require('../utils/config.js');
6 |
7 | const connection = config.connection;
8 |
9 | const wsolAddress = 'So11111111111111111111111111111111111111112';
10 | const openbookProgramId = new web3.PublicKey('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX');
11 |
12 | const rayProgram = new web3.PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8');
13 | const myAccount = new web3.PublicKey(config.ownerAddress);
14 |
15 | async function derivePoolKeys(id){
16 | console.log(id);
17 | const marketId = new web3.PublicKey(id);
18 |
19 | const marketInfo = await getMarketInfo(marketId);
20 | const marketDeco = await getDecodedData(marketInfo);
21 |
22 | const baseMint = marketDeco.baseMint;
23 | const baseMintData = await getMintData(baseMint);
24 | const baseDecimals = await getDecimals(baseMintData);
25 | const ownerBaseAta = await getOwnerAta(baseMint, myAccount);
26 |
27 | const quoteMint = marketDeco.quoteMint;
28 | const quoteMintData = await getMintData(quoteMint);
29 | const quoteDecimals = await getDecimals(quoteMintData);
30 | const ownerQuoteAta = await getOwnerAta(quoteMint, myAccount);
31 |
32 | const authority = (raydium_sdk_1.findProgramAddress([Buffer.from([97, 109, 109, 32, 97, 117, 116, 104, 111, 114, 105, 116, 121])], rayProgram))['publicKey'];
33 | // const marketAuthority = getVaultSigner(marketId, marketDeco);
34 |
35 | const poolKeys = {
36 | id: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('amm_associated_seed', 'utf-8')], rayProgram)['publicKey'],
37 | baseMint: baseMint,
38 | quoteMint, quoteMint,
39 | lpMint: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('lp_mint_associated_seed', 'utf-8')], rayProgram)['publicKey'],
40 | baseDecimals: baseDecimals,
41 | quoteDecimals: quoteDecimals,
42 | lpDecimals: baseDecimals,
43 | version: 4,
44 | programId: rayProgram,
45 | authority: authority,
46 | openOrders: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('open_order_associated_seed', 'utf-8')], rayProgram)['publicKey'],
47 | targetOrders: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('target_associated_seed', 'utf-8')], rayProgram)['publicKey'],
48 | baseVault: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('coin_vault_associated_seed', 'utf-8')], rayProgram)['publicKey'],
49 | quoteVault: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('pc_vault_associated_seed', 'utf-8')], rayProgram)['publicKey'],
50 | // withdrawQueue: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('withdraw_associated_seed', 'utf-8')], rayProgram)['publicKey'],
51 | // lpVault: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('temp_lp_token_associated_seed', 'utf-8')], rayProgram)['publicKey'],
52 | withdrawQueue: new web3.PublicKey('11111111111111111111111111111111'),
53 | lpVault: new web3.PublicKey('11111111111111111111111111111111'),
54 | marketVersion: 3,
55 | marketProgramId: openbookProgramId,
56 | // marketProgramId: new web3.PublicKey('9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin'),
57 | marketId: marketId,
58 | marketAuthority: raydium_sdk_1.Market.getAssociatedAuthority({ programId: new web3.PublicKey('9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin'), marketId: marketId }).publicKey,
59 | marketBaseVault: marketDeco.baseVault,
60 | marketQuoteVault: marketDeco.quoteVault,
61 | marketBids: marketDeco.bids,
62 | marketAsks: marketDeco.asks,
63 | marketEventQueue: marketDeco.eventQueue,
64 | // ownerBaseAta: ownerBaseAta,
65 | // ownerQuoteAta: ownerQuoteAta,
66 | // marketAuthority: marketAuthority,
67 | // coinVault: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('pc_vault_associated_seed', 'utf-8')], rayProgram)['publicKey'],
68 | lookupTableAccount: web3.PublicKey.default
69 | };
70 | return poolKeys;
71 | }
72 | exports.derivePoolKeys = derivePoolKeys;
73 |
74 | async function getMarketInfo(marketId){
75 | const marketInfo = await connection.getAccountInfo(marketId);
76 | return marketInfo;
77 | }
78 |
79 | async function getDecodedData(marketInfo){
80 | return await Market.getLayout(openbookProgramId).decode(marketInfo.data);
81 | }
82 |
83 | async function getMintData(mint){
84 | return await connection.getAccountInfo(mint);
85 | }
86 |
87 | async function getDecimals(mintData){
88 | return raydium_sdk_1.SPL_MINT_LAYOUT.decode(mintData.data).decimals;
89 | }
90 |
91 | async function getOwnerAta(mint, publicKey){
92 | const foundAta = web3.PublicKey.findProgramAddressSync([publicKey.toBuffer(), spl.TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()], spl.ASSOCIATED_TOKEN_PROGRAM_ID)[0];
93 | return foundAta;
94 | }
95 |
96 | function getVaultSigner(marketId, marketDeco){
97 | const seeds = [marketId.toBuffer()];
98 | const seedsWithNonce = seeds.concat(Buffer.from([Number(marketDeco.vaultSignerNonce.toString())]), Buffer.alloc(7));
99 | return web3.PublicKey.createProgramAddressSync(seedsWithNonce, openbookProgramId);
100 | }
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/strategy2/start2.js:
--------------------------------------------------------------------------------
1 | const web3 = require('@solana/web3.js');
2 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
3 | const WebSocket = require('ws');
4 | const derivePoolKeys = require('./derivePoolKeys.js');
5 | const swap = require('./swap2.js');
6 | const config = require('../utils/config.js');
7 |
8 | const connection = config.connection;
9 |
10 | const ws = new WebSocket(config.websocketConnection)
11 | ws.onopen = () => {
12 | ws.send(
13 | JSON.stringify({
14 | jsonrpc: '2.0',
15 | id: 1,
16 | method: 'blockSubscribe',
17 | params: [{"mentionsAccountOrProgram": "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX"}, {"commitment": "confirmed", "maxSupportedTransactionVersion": 0, "encoding": "jsonParsed"}]
18 | })
19 | )
20 | }
21 |
22 | ws.on('message', (evt) => {
23 | try {
24 | const buffer = evt.toString('utf8');
25 | parseTxs(JSON.parse(buffer));
26 | return;
27 | } catch (e) {
28 | console.log(e)
29 | }
30 | })
31 |
32 | function parseTxs(txsFromBlock){
33 | if(txsFromBlock.params === undefined){
34 | return;
35 | }
36 | const allTx = txsFromBlock.params.result.value.block.transactions;
37 | for(const tx of allTx){
38 | if(parseLogs(tx.meta.logMessages) && tx.transaction.message.accountKeys.length === 13 && tx.transaction.message.instructions.length === 6){
39 | ws.close();
40 | console.log(tx.transaction.signatures)
41 | parseAccountKeys(tx.transaction.message.accountKeys, tx.transaction.signatures);
42 | }
43 | }
44 | }
45 |
46 | function parseLogs(logs){
47 | let invoke = 0;
48 | let consumed = 0;
49 | let success = 0;
50 | for(const log of logs){
51 | if(log.includes("Program srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX invoke")){
52 | invoke += 1;
53 | }
54 | if(log.includes("Program srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX consumed")){
55 | consumed += 1;
56 | }
57 | if(log.includes("Program srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX success")){
58 | success += 1;
59 | }
60 | }
61 | if(invoke === 1 && consumed === 1 && success === 1){
62 | return true;
63 | } else{
64 | return false;
65 | }
66 | }
67 |
68 | async function parseAccountKeys(keys, signature){
69 | let marketId = null;
70 | for(const key of keys){
71 | console.log(key);
72 | const keyData = await connection.getAccountInfo(new web3.PublicKey(key.pubkey));
73 | if(keyData !== null && keyData.data.length === 388){
74 | marketId = key.pubkey;
75 | }
76 | }
77 | if(marketId === null){
78 | parseAccountKeys(keys);
79 | } else{
80 | const poolKeys = await derivePoolKeys.derivePoolKeys(marketId);
81 | swap.swap(poolKeys, signature);
82 | }
83 | }
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/strategy2/swap2.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | var __importDefault = (this && this.__importDefault) || function (mod) {
12 | return (mod && mod.__esModule) ? mod : { "default": mod };
13 | };
14 | Object.defineProperty(exports, "__esModule", { value: true });
15 | const assert_1 = __importDefault(require("assert"));
16 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
17 | const config_1 = require("../utils/config.js");
18 | const util_1 = require("../utils/util.js");
19 | const { LAMPORTS_PER_SOL } = require("@solana/web3.js");
20 | const web3 = require("@solana/web3.js");
21 | const connection = config_1.connection;
22 | function swapOnlyAmm(input) {
23 | return __awaiter(this, void 0, void 0, function* () {
24 | const outputToken = new raydium_sdk_1.Token(raydium_sdk_1.TOKEN_PROGRAM_ID, new web3.PublicKey(input.tokenAddress), input.poolKeys.lpDecimals);
25 | const { innerTransactions } = yield raydium_sdk_1.Liquidity.makeSwapInstructionSimple({
26 | connection: config_1.connection,
27 | poolKeys: input.poolKeys,
28 | userKeys: {
29 | tokenAccounts: input.walletTokenAccounts,
30 | owner: input.wallet.publicKey,
31 | },
32 | amountIn: input.inputTokenAmount,
33 | amountOut: new raydium_sdk_1.TokenAmount(outputToken, 1),
34 | fixedSide: 'in',
35 | makeTxVersion: config_1.makeTxVersion,
36 | });
37 | return { txids: yield (0, util_1.buildAndSendTx)(innerTransactions) };
38 | });
39 | }
40 |
41 | const buyAmtSol = config_1.amtBuySol;
42 | function swap(poolKeys, signature) {
43 | return __awaiter(this, void 0, void 0, function* () {
44 | const ownerAddress = config_1.ownerAddress;
45 | const inputToken = new raydium_sdk_1.Token(raydium_sdk_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey('So11111111111111111111111111111111111111112'), 9, 'WSOL', 'WSOL'); // WSOL
46 | const inputTokenAmount = new raydium_sdk_1.TokenAmount(inputToken, LAMPORTS_PER_SOL * buyAmtSol);
47 | const slippage = new raydium_sdk_1.Percent(1, 100);
48 | const walletTokenAccounts = yield (0, util_1.getWalletTokenAccount)(config_1.connection, config_1.wallet.publicKey);
49 | swapOnlyAmm({
50 | poolKeys,
51 | tokenAddress: poolKeys.baseMint.toString(),
52 | inputTokenAmount,
53 | slippage,
54 | walletTokenAccounts,
55 | wallet: config_1.wallet,
56 | }).then(({ txids }) => {
57 | /** continue with txids */
58 | console.log('txids', txids);
59 | if(txids.length === 1){
60 | monitorTokenSell(txids[0], poolKeys.baseMint.toString(), ownerAddress, poolKeys.baseVault.toString(), poolKeys.quoteVault.toString());
61 | }
62 | }).catch(error => {
63 | console.log(signature);
64 | console.log(error);
65 | swap(poolKeys, poolKeys.baseMint.toString());
66 | })
67 | });
68 | }
69 | exports.swap = swap
70 |
71 | async function getTx(tx){
72 | return await connection.getTransaction(tx, {
73 | maxSupportedTransactionVersion: 0,
74 | commitment: "confirmed"
75 | })
76 | }
77 |
78 | async function getBalances(tx, tokenAddress, ownerAddress){
79 | let validTx = await getTx(tx);
80 | while(validTx === null){
81 | validTx = await getTx(tx);
82 | if(validTx !== null){
83 | for(const account of validTx.meta.postTokenBalances){
84 | if(account.mint === tokenAddress && account.owner === ownerAddress){
85 | return account.uiTokenAmount.uiAmount;
86 | }
87 | }
88 | }
89 | }
90 | }
91 |
92 | async function getTokenPriceInSol(baseVault, quoteVault){
93 | const baseVaultAccount = await connection.getTokenAccountBalance(new web3.PublicKey(baseVault));
94 | const quoteVaultAccount = await connection.getTokenAccountBalance(new web3.PublicKey(quoteVault));
95 | const baseVaultAccountAmount = baseVaultAccount.value.uiAmount;
96 | const quoteVaultAccountAmount = quoteVaultAccount.value.uiAmount;
97 | return (quoteVaultAccountAmount / baseVaultAccountAmount);
98 | }
99 |
100 | async function monitorTokenSell(tx, tokenAddress, ownerAddress, baseVault, quoteVault){
101 | const tokenBalance = await getBalances(tx, tokenAddress, ownerAddress);
102 | const buyPrice = (buyAmtSol / tokenBalance);
103 | monitorToken(buyPrice, baseVault, quoteVault);
104 | }
105 |
106 | async function monitorToken(buyPrice, baseVault, quoteVault){
107 | let interval = setInterval(async () => {
108 | const currentPrice = await getTokenPriceInSol(baseVault, quoteVault);
109 | console.log("buy price: " + buyPrice + " current price: " + currentPrice);
110 | const percentIncrease = ((buyPrice - currentPrice) / buyPrice) * 100;
111 | console.log("percent increase: " + percentIncrease);
112 | }, 500)
113 | }
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/utils/config.js:
--------------------------------------------------------------------------------
1 | const bs58 = require('bs58');
2 | "use strict";
3 | Object.defineProperty(exports, "__esModule", { value: true });
4 | exports.DEFAULT_TOKEN = exports.addLookupTableInfo = exports.makeTxVersion = exports.RAYDIUM_MAINNET_API = exports.ENDPOINT = exports.PROGRAMIDS = exports.connection = exports.wallet = exports.rpcToken = exports.rpcUrl = void 0;
5 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
6 | const web3_js_1 = require("@solana/web3.js");
7 | exports.ownerAddress = '';
8 | exports.wallet = web3_js_1.Keypair.fromSecretKey(bs58.decode(''));
9 | exports.connection = new web3_js_1.Connection('');
10 | exports.websocketConnection = '';
11 | exports.amtBuySol = '';
12 | exports.PROGRAMIDS = raydium_sdk_1.MAINNET_PROGRAM_ID;
13 | exports.ENDPOINT = raydium_sdk_1.ENDPOINT;
14 | exports.RAYDIUM_MAINNET_API = raydium_sdk_1.RAYDIUM_MAINNET;
15 | exports.makeTxVersion = raydium_sdk_1.TxVersion.V0; // LEGACY
16 | exports.addLookupTableInfo = raydium_sdk_1.LOOKUP_TABLE_CACHE;
17 |
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/utils/decoderaylog.js:
--------------------------------------------------------------------------------
1 | const web3 = require('@solana/web3.js');
2 | const WebSocket = require('ws');
3 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
4 | const bs64 = require('bs64');
5 | const config = require('./config');
6 |
7 | const connection = config.connection;
8 |
9 | const feeAddress = '7YttLkHDoNj9wyDur5pM1ejNaAvT9X4eqaYcHQqtj2G5'
10 | const rayProgram = new web3.PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8');
11 |
12 | const ws = new WebSocket(config.websocketConnection)
13 | ws.onopen = () => {
14 | ws.send(
15 | JSON.stringify({
16 | jsonrpc: '2.0',
17 | id: 1,
18 | method: 'logsSubscribe',
19 | params: [{"mentions": [feeAddress]}, {"commitment": "processed"}]
20 | })
21 | )
22 | }
23 |
24 | ws.on('message', (evt) => {
25 | try {
26 | const buffer = evt.toString('utf8');
27 | parseLogs(JSON.parse(buffer));
28 | return;
29 | } catch (e) {
30 | console.log(e)
31 | }
32 | })
33 |
34 | function parseLogs(buffer){
35 | if(buffer.params === undefined){
36 | return;
37 | }
38 | let now = new Date();
39 | let utcString = now.toUTCString();
40 | console.log(utcString);
41 | const allLogs = buffer.params.result.value.logs;
42 | for(const log of allLogs){
43 | if(log.includes("ray_log")){
44 | const rayLogSplit = log.split(" ");
45 | const rayLog = rayLogSplit[3];
46 | const logData = Buffer.from(rayLog, "base64");
47 | const market = new web3.PublicKey(logData.subarray(75 - 32), 75);
48 | console.log(market)
49 | const pool = raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), market.toBuffer(), Buffer.from('amm_associated_seed', 'utf-8')], rayProgram)['publicKey'];
50 | console.log(pool);
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/Bot原版/Bot Spam Sniper/utils/util.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | Object.defineProperty(exports, "__esModule", { value: true });
12 | exports.sleepTime = exports.getATAAddress = exports.buildAndSendTx = exports.getWalletTokenAccount = exports.sendTx = void 0;
13 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
14 | const web3_js_1 = require("@solana/web3.js");
15 | const config_1 = require("./config");
16 | function sendTx(connection, payer, txs, options) {
17 | return __awaiter(this, void 0, void 0, function* () {
18 | const txids = [];
19 | for (const iTx of txs) {
20 | if (iTx instanceof web3_js_1.VersionedTransaction) {
21 | iTx.sign([payer]);
22 | txids.push(yield connection.sendTransaction(iTx, options));
23 | }
24 | else {
25 | txids.push(yield connection.sendTransaction(iTx, [payer], options));
26 | }
27 | }
28 | return txids;
29 | });
30 | }
31 | exports.sendTx = sendTx;
32 | function getWalletTokenAccount(connection, wallet) {
33 | return __awaiter(this, void 0, void 0, function* () {
34 | const walletTokenAccount = yield connection.getTokenAccountsByOwner(wallet, {
35 | programId: raydium_sdk_1.TOKEN_PROGRAM_ID,
36 | });
37 | return walletTokenAccount.value.map((i) => ({
38 | pubkey: i.pubkey,
39 | programId: i.account.owner,
40 | accountInfo: raydium_sdk_1.SPL_ACCOUNT_LAYOUT.decode(i.account.data),
41 | }));
42 | });
43 | }
44 | exports.getWalletTokenAccount = getWalletTokenAccount;
45 | function buildAndSendTx(innerSimpleV0Transaction, options) {
46 | return __awaiter(this, void 0, void 0, function* () {
47 | const willSendTx = yield (0, raydium_sdk_1.buildSimpleTransaction)({
48 | connection: config_1.connection,
49 | makeTxVersion: config_1.makeTxVersion,
50 | payer: config_1.wallet.publicKey,
51 | innerTransactions: innerSimpleV0Transaction,
52 | addLookupTableInfo: config_1.addLookupTableInfo,
53 | });
54 | return yield sendTx(config_1.connection, config_1.wallet, willSendTx, options);
55 | });
56 | }
57 | exports.buildAndSendTx = buildAndSendTx;
58 | function getATAAddress(programId, owner, mint) {
59 | const { publicKey, nonce } = (0, raydium_sdk_1.findProgramAddress)([owner.toBuffer(), programId.toBuffer(), mint.toBuffer()], new web3_js_1.PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"));
60 | return { publicKey, nonce };
61 | }
62 | exports.getATAAddress = getATAAddress;
63 | function sleepTime(ms) {
64 | return __awaiter(this, void 0, void 0, function* () {
65 | console.log((new Date()).toLocaleString(), 'sleepTime', ms);
66 | return new Promise(resolve => setTimeout(resolve, ms));
67 | });
68 | }
69 | exports.sleepTime = sleepTime;
70 | //# sourceMappingURL=util.js.map
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/.env.copy:
--------------------------------------------------------------------------------
1 | # Wallet
2 | PRIVATE_KEY=
3 |
4 | # Connection
5 | RPC_ENDPOINT=https://solana-mainnet.rpc.extrnode.com/5b667693-6518-4921-8ea1-4f65ff09c463
6 | RPC_WEBSOCKET_ENDPOINT=wss://solana-mainnet.rpc.extrnode.com/5b667693-6518-4921-8ea1-4f65ff09c463
7 | COMMITMENT_LEVEL=confirmed
8 |
9 | # Bot
10 | LOG_LEVEL=trace
11 | ONE_TOKEN_AT_A_TIME=true
12 | PRE_LOAD_EXISTING_MARKETS=false
13 | CACHE_NEW_MARKETS=false
14 | # default or warp or jito
15 | TRANSACTION_EXECUTOR=jito
16 | # if using default executor, fee below will be applied
17 | COMPUTE_UNIT_LIMIT=101337
18 | COMPUTE_UNIT_PRICE=421197
19 | # if using warp or jito executor, fee below will be applied
20 | CUSTOM_FEE=0.01
21 |
22 | # Buy
23 | QUOTE_MINT=WSOL
24 | QUOTE_AMOUNT=0.001
25 | AUTO_BUY_DELAY=0
26 | MAX_BUY_RETRIES=10
27 | BUY_SLIPPAGE=100
28 |
29 | # Sell
30 | AUTO_SELL=true
31 | MAX_SELL_RETRIES=10
32 | AUTO_SELL_DELAY=0
33 | PRICE_CHECK_INTERVAL=2000
34 | PRICE_CHECK_DURATION=600000
35 | TAKE_PROFIT=100
36 | STOP_LOSS=20
37 | SELL_SLIPPAGE=100
38 |
39 | # Filters
40 | USE_SNIPE_LIST=false
41 | SNIPE_LIST_REFRESH_INTERVAL=30000
42 | FILTER_CHECK_DURATION=60000
43 | FILTER_CHECK_INTERVAL=2000
44 | CONSECUTIVE_FILTER_MATCHES=3
45 | CHECK_IF_MUTABLE=false
46 | CHECK_IF_MINT_IS_RENOUNCED=true
47 | CHECK_IF_FREEZABLE=false
48 | CHECK_IF_BURNED=true
49 | MIN_POOL_SIZE=3
50 | MAX_POOL_SIZE=20
51 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 | .pnpm-debug.log*
9 |
10 | # Diagnostic reports (https://nodejs.org/api/report.html)
11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12 |
13 | # Runtime data
14 | pids
15 | *.pid
16 | *.seed
17 | *.pid.lock
18 |
19 | # Directory for instrumented libs generated by jscoverage/JSCover
20 | lib-cov
21 |
22 | # Coverage directory used by tools like istanbul
23 | coverage
24 | *.lcov
25 |
26 | # nyc test coverage
27 | .nyc_output
28 |
29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30 | .grunt
31 |
32 | # Bower dependency directory (https://bower.io/)
33 | bower_components
34 |
35 | # node-waf configuration
36 | .lock-wscript
37 |
38 | # Compiled binary addons (https://nodejs.org/api/addons.html)
39 | build/Release
40 |
41 | # Dependency directories
42 | node_modules/
43 | jspm_packages/
44 |
45 | # Snowpack dependency directory (https://snowpack.dev/)
46 | web_modules/
47 |
48 | # TypeScript cache
49 | *.tsbuildinfo
50 |
51 | # Optional npm cache directory
52 | .npm
53 |
54 | # Optional eslint cache
55 | .eslintcache
56 |
57 | # Optional stylelint cache
58 | .stylelintcache
59 |
60 | # Microbundle cache
61 | .rpt2_cache/
62 | .rts2_cache_cjs/
63 | .rts2_cache_es/
64 | .rts2_cache_umd/
65 |
66 | # Optional REPL history
67 | .node_repl_history
68 |
69 | # Output of 'npm pack'
70 | *.tgz
71 |
72 | # Yarn Integrity file
73 | .yarn-integrity
74 |
75 | # dotenv environment variable files
76 | .env
77 | .env.development.local
78 | .env.test.local
79 | .env.production.local
80 | .env.local
81 |
82 | # parcel-bundler cache (https://parceljs.org/)
83 | .cache
84 | .parcel-cache
85 |
86 | # Next.js build output
87 | .next
88 | out
89 |
90 | # Nuxt.js build / generate output
91 | .nuxt
92 | dist
93 |
94 | # Gatsby files
95 | .cache/
96 | # Comment in the public line in if your project uses Gatsby and not Next.js
97 | # https://nextjs.org/blog/next-9-1#public-directory-support
98 | # public
99 |
100 | # vuepress build output
101 | .vuepress/dist
102 |
103 | # vuepress v2.x temp and cache directory
104 | .temp
105 | .cache
106 |
107 | # Docusaurus cache and generated files
108 | .docusaurus
109 |
110 | # Serverless directories
111 | .serverless/
112 |
113 | # FuseBox cache
114 | .fusebox/
115 |
116 | # DynamoDB Local files
117 | .dynamodb/
118 |
119 | # TernJS port file
120 | .tern-port
121 |
122 | # Stores VSCode versions used for testing VSCode extensions
123 | .vscode-test
124 |
125 | # PNPM
126 | pnpm-lock.yaml
127 |
128 | # yarn v2
129 | .yarn/cache
130 | .yarn/unplugged
131 | .yarn/build-state.yml
132 | .yarn/install-state.gz
133 | .pnp.*
134 |
135 | # JetBrains
136 | .idea
137 |
138 | # Visual Studio Code
139 | *.code-workspace
140 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all",
4 | "printWidth": 120
5 | }
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/README.md:
--------------------------------------------------------------------------------
1 | # AxisBot Solana Sniper v1.0
2 |
3 | ## 概述
4 | AxisBot 是一个高速狙击和出售 SPL 代币的工具,旨在帮助用户在保持较高安全性的同时,提供最快的狙击速度。由交易者为交易者打造。
5 |
6 | ## 设置步骤
7 |
8 | 要运行脚本,你需要:
9 |
10 | - 创建一个新的空 Solana 钱包
11 | - 向其转入一些 SOL
12 | - 将部分 SOL 转换为 USDC 或 WSOL(取决于配置)
13 | - 根据下面的配置选择 USDC 或 WSOL
14 | - 通过更新 `.env.copy` 文件来配置脚本(完成后移除 `.copy` 后缀)
15 | - 参考下方的 [配置](#configuration) 部分
16 | - 在终端中输入 `npm install` 安装依赖
17 | - 输入 `npm run start` 运行脚本
18 |
19 | ### 配置
20 |
21 | #### 钱包
22 | - `PRIVATE_KEY`:你钱包的私钥。
23 |
24 | #### 连接
25 | - `RPC_ENDPOINT`:与 Solana 网络交互的 HTTPS RPC 端点。
26 | - `RPC_WEBSOCKET_ENDPOINT`:从 Solana 网络实时接收更新的 WebSocket RPC 端点。
27 | - `COMMITMENT_LEVEL`:交易的承诺级别(如“finalized”表示最高安全级别)。
28 |
29 | #### 机器人配置
30 | - `LOG_LEVEL`:设置日志级别,如 `info`、`debug`、`trace` 等。
31 | - `ONE_TOKEN_AT_A_TIME`:设为 `true` 表示一次只处理一个代币的购买。
32 | - `COMPUTE_UNIT_LIMIT` 和 `COMPUTE_UNIT_PRICE`:用于计算交易费用。
33 | - `PRE_LOAD_EXISTING_MARKETS`:启动时预加载所有现有市场(不适用于公共 RPC)。
34 | - `CACHE_NEW_MARKETS`:设为 `true` 以缓存新市场(不适用于公共 RPC)。
35 | - `TRANSACTION_EXECUTOR`:设为 `jito` 以使用 JSON-RPC jito 执行器。
36 | - `CUSTOM_FEE`:如果使用 warp 或 jito 执行器,将使用此值作为交易费用,而不是 `COMPUTE_UNIT_LIMIT` 和 `COMPUTE_UNIT_PRICE`。
37 | - 最小值为 0.0001 SOL,建议使用 0.01 SOL 或以上。
38 | - 此费用之外,还会应用 Solana 网络的最低费用。
39 |
40 | #### 买入配置
41 | - `QUOTE_MINT`:设置狙击的池子类型(USDC 或 WSOL)。
42 | - `QUOTE_AMOUNT`:每次买入的金额。
43 | - `AUTO_BUY_DELAY`:在买入代币前的延迟时间(以毫秒为单位)。
44 | - `MAX_BUY_RETRIES`:买入代币的最大重试次数。
45 | - `BUY_SLIPPAGE`:买入时的滑点百分比。
46 |
47 | #### 卖出配置
48 | - `AUTO_SELL`:设为 `true` 以启用自动卖出代币。如果你想手动卖出,请禁用此选项。
49 | - `MAX_SELL_RETRIES`:卖出代币的最大重试次数。
50 | - `AUTO_SELL_DELAY`:自动卖出代币前的延迟时间(以毫秒为单位)。
51 | - `PRICE_CHECK_INTERVAL`:检查止盈和止损条件的时间间隔(以毫秒为单位)。
52 | - 设置为 0 可禁用止盈和止损功能。
53 | - `PRICE_CHECK_DURATION`:等待止盈/止损条件的时间(以毫秒为单位)。如果未达到预期的利润或亏损,机器人将在此时间后自动卖出。
54 | - 设置为 0 以禁用该功能。
55 | - `TAKE_PROFIT`:达到该百分比利润时进行止盈。
56 | - 利润基于报价资产(如 USDC 或 WSOL)计算。
57 | - `STOP_LOSS`:达到该百分比亏损时止损。
58 | - 亏损基于报价资产计算。
59 | - `SELL_SLIPPAGE`:卖出时的滑点百分比。
60 |
61 | #### 狙击列表
62 | - `USE_SNIPE_LIST`:设为 `true` 以启用只购买 `snipe-list.txt` 中列出的代币。
63 | - 该池子在机器人启动前不得存在。
64 | - 如果在机器人启动前可以交易该代币,则不会执行购买。
65 | - `SNIPE_LIST_REFRESH_INTERVAL`:刷新狙击列表的时间间隔(以毫秒为单位)。你可以在机器人运行期间更新列表,它将在每次刷新时应用更改。
66 |
67 | #### 过滤器
68 | - `FILTER_CHECK_INTERVAL` 和 `FILTER_CHECK_DURATION`:设置检查池子是否符合过滤条件的时间间隔和持续时间。
69 | - `CONSECUTIVE_FILTER_MATCHES`:连续多少次满足过滤条件时才购买。
70 | - `CHECK_IF_MUTABLE`:设置为 `true` 仅购买不可修改的代币。
71 | - `CHECK_IF_MINT_IS_RENOUNCED`:设置为 `true` 仅购买铸币已放弃的代币。
72 | - `CHECK_IF_FREEZABLE` 和 `CHECK_IF_BURNED`:设置为 `true` 仅购买不可冻结或未被销毁的流动性池。
73 | - `MIN_POOL_SIZE` 和 `MAX_POOL_SIZE`:设置池子大小范围以确定是否进行购买。
74 |
75 | ## 常见问题
76 | 如果遇到未列出的问题,请在此仓库中创建新的问题。为获取更多调试信息,可以将 `LOG_LEVEL` 设置为 `debug`。
77 |
78 | ### 没有代币账户
79 | - 如果日志中显示如下错误:
80 | `Error: No SOL token account found in wallet:`
81 | 这意味着你提供的钱包中没有 USDC/WSOL 代币账户。
82 | - **解决方法**:前往去中心化交易所,将一些 SOL 转换为 USDC/WSOL。例如,转换后的 WSOL 应在钱包中显示。
83 |
84 | ## 免责声明
85 | AxisBot Solana Sniper 是一款简化许多常规交易任务的代码工具,整合了多种实用工具。
86 | 加密货币交易存在巨大风险,包括可能的本金损失。该机器人不保证盈利或特定结果。用户需自行承担使用此工具的风险。
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/cache/index.ts:
--------------------------------------------------------------------------------
1 | export * from './market.cache';
2 | export * from './pool.cache';
3 | export * from './snipe-list.cache';
4 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/cache/market.cache.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { Connection, PublicKey } from '@solana/web3.js'; // Solana 相关库
3 | import { getMinimalMarketV3, logger, MINIMAL_MARKET_STATE_LAYOUT_V3, MinimalMarketLayoutV3 } from '../helpers'; // 辅助函数和类型
4 | import { MAINNET_PROGRAM_ID, MARKET_STATE_LAYOUT_V3, Token } from '@raydium-io/raydium-sdk'; // Raydium SDK
5 |
6 | // 创建市场缓存类
7 | export class MarketCache {
8 | private readonly keys: Map = new Map(); // 存储市场的 Map
9 | constructor(private readonly connection: Connection) {} // 构造函数,接受 Solana 连接
10 |
11 | // 初始化缓存的方法
12 | async init(config: { quoteToken: Token }) {
13 | logger.debug({}, `正在获取所有现有的 ${config.quoteToken.symbol} 市场...`); // 记录调试信息
14 |
15 | // 获取程序账户
16 | const accounts = await this.connection.getProgramAccounts(MAINNET_PROGRAM_ID.OPENBOOK_MARKET, {
17 | commitment: this.connection.commitment, // 提交级别
18 | dataSlice: {
19 | offset: MARKET_STATE_LAYOUT_V3.offsetOf('eventQueue'), // 数据偏移
20 | length: MINIMAL_MARKET_STATE_LAYOUT_V3.span, // 数据长度
21 | },
22 | filters: [
23 | { dataSize: MARKET_STATE_LAYOUT_V3.span }, // 数据大小过滤
24 | {
25 | memcmp: { // 根据报价代币的 mint 过滤
26 | offset: MARKET_STATE_LAYOUT_V3.offsetOf('quoteMint'),
27 | bytes: config.quoteToken.mint.toBase58(),
28 | },
29 | },
30 | ],
31 | });
32 |
33 | // 遍历账户并缓存市场信息
34 | for (const account of accounts) {
35 | const market = MINIMAL_MARKET_STATE_LAYOUT_V3.decode(account.account.data); // 解码市场信息
36 | this.keys.set(account.pubkey.toString(), market); // 将市场信息存入缓存
37 | }
38 |
39 | logger.debug({}, `缓存了 ${this.keys.size} 个市场`); // 记录缓存市场的数量
40 | }
41 |
42 | // 保存市场信息的方法
43 | public save(marketId: string, keys: MinimalMarketLayoutV3) {
44 | if (!this.keys.has(marketId)) { // 如果市场 ID 不在缓存中
45 | logger.trace({}, `缓存新市场: ${marketId}`); // 记录缓存新市场的信息
46 | this.keys.set(marketId, keys); // 将市场信息存入缓存
47 | }
48 | }
49 |
50 | // 获取市场信息的方法
51 | public async get(marketId: string): Promise {
52 | if (this.keys.has(marketId)) { // 如果市场 ID 在缓存中
53 | return this.keys.get(marketId)!; // 返回缓存的市场信息
54 | }
55 |
56 | logger.trace({}, `获取市场 ${marketId} 的新密钥`); // 记录获取新市场信息的日志
57 | const market = await this.fetch(marketId); // 从区块链获取市场信息
58 | this.keys.set(marketId, market); // 将获取的市场信息存入缓存
59 | return market; // 返回市场信息
60 | }
61 |
62 | // 私有方法:从区块链获取市场信息
63 | private fetch(marketId: string): Promise {
64 | return getMinimalMarketV3(this.connection, new PublicKey(marketId), this.connection.commitment); // 获取市场信息
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/cache/pool.cache.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { LiquidityStateV4 } from '@raydium-io/raydium-sdk'; // Raydium SDK
3 | import { logger } from '../helpers'; // 自定义日志记录器
4 |
5 | // 创建 PoolCache 类
6 | export class PoolCache {
7 | private readonly keys: Map = new Map< // 存储池的 Map
8 | string,
9 | { id: string; state: LiquidityStateV4 } // 键为代币 mint,值为池 ID 和状态
10 | >();
11 |
12 | // 保存池信息的方法
13 | public save(id: string, state: LiquidityStateV4) {
14 | // 如果状态的基础代币 mint 不在缓存中
15 | if (!this.keys.has(state.baseMint.toString())) {
16 | logger.trace(`缓存新池,代币 mint: ${state.baseMint.toString()}`); // 记录缓存新池的信息
17 | this.keys.set(state.baseMint.toString(), { id, state }); // 将池信息存入缓存
18 | }
19 | }
20 |
21 | // 获取池信息的方法
22 | public async get(mint: string): Promise<{ id: string; state: LiquidityStateV4 }> {
23 | return this.keys.get(mint)!; // 返回缓存的池信息
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/cache/snipe-list.cache.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import fs from 'fs'; // 文件系统模块
3 | import path from 'path'; // 路径处理模块
4 | import { logger, SNIPE_LIST_REFRESH_INTERVAL } from '../helpers'; // 自定义日志记录器和常量
5 |
6 | // 创建 SnipeListCache 类
7 | export class SnipeListCache {
8 | private snipeList: string[] = []; // 存储抢购列表
9 | private fileLocation = path.join(__dirname, '../snipe-list.txt'); // 抢购列表文件的路径
10 |
11 | constructor() {
12 | // 设置定时器,定时刷新抢购列表
13 | setInterval(() => this.loadSnipeList(), SNIPE_LIST_REFRESH_INTERVAL);
14 | }
15 |
16 | // 初始化方法,加载抢购列表
17 | public init() {
18 | this.loadSnipeList(); // 加载抢购列表
19 | }
20 |
21 | // 检查某个 mint 是否在抢购列表中
22 | public isInList(mint: string) {
23 | return this.snipeList.includes(mint); // 返回结果
24 | }
25 |
26 | // 私有方法:加载抢购列表
27 | private loadSnipeList() {
28 | logger.trace(`正在刷新抢购列表...`); // 记录刷新日志
29 |
30 | const count = this.snipeList.length; // 记录当前列表的长度
31 | const data = fs.readFileSync(this.fileLocation, 'utf-8'); // 读取抢购列表文件
32 | this.snipeList = data
33 | .split('\n') // 按行分割
34 | .map((a) => a.trim()) // 去掉每行的空白
35 | .filter((a) => a); // 过滤掉空行
36 |
37 | // 如果列表长度发生变化,记录加载信息
38 | if (this.snipeList.length != count) {
39 | logger.info(`加载抢购列表: ${this.snipeList.length}`); // 记录加载的抢购列表数量
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/filters/burn.filter.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { Filter, FilterResult } from './pool-filters'; // 过滤器接口和结果类型
3 | import { Connection } from '@solana/web3.js'; // Solana 相关库
4 | import { LiquidityPoolKeysV4 } from '@raydium-io/raydium-sdk'; // Raydium SDK 的流动性池密钥类型
5 | import { logger } from '../helpers'; // 自定义日志记录器
6 |
7 | // 创建 BurnFilter 类实现 Filter 接口
8 | export class BurnFilter implements Filter {
9 | constructor(private readonly connection: Connection) {} // 构造函数,接受 Solana 连接
10 |
11 | // 执行过滤器的方法
12 | async execute(poolKeys: LiquidityPoolKeysV4): Promise {
13 | try {
14 | // 获取流动性池的代币供应量
15 | const amount = await this.connection.getTokenSupply(poolKeys.lpMint, this.connection.commitment);
16 | const burned = amount.value.uiAmount === 0; // 判断 LP 是否已被销毁
17 | return { ok: burned, message: burned ? undefined : "已销毁 -> 创建者未销毁 LP" }; // 返回结果
18 | } catch (e: any) {
19 | // 捕获错误,检查错误代码
20 | if (e.code == -32602) {
21 | return { ok: true }; // 如果是特定错误代码,返回 ok 为 true
22 | }
23 |
24 | // 记录错误日志
25 | logger.error({ mint: poolKeys.baseMint }, `检查 LP 是否已销毁失败`);
26 | }
27 |
28 | return { ok: false, message: '检查 LP 是否已销毁失败' }; // 返回未通过的结果
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/filters/index.ts:
--------------------------------------------------------------------------------
1 | export * from './burn.filter';
2 | export * from './mutable.filter';
3 | export * from './pool-filters';
4 | export * from './pool-size.filter';
5 | export * from './renounced.filter';
6 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/filters/mutable.filter.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { Filter, FilterResult } from './pool-filters'; // 过滤器接口和结果类型
3 | import { Connection, PublicKey } from '@solana/web3.js'; // Solana 相关库
4 | import { LiquidityPoolKeysV4 } from '@raydium-io/raydium-sdk'; // Raydium SDK 的流动性池密钥类型
5 | import { getPdaMetadataKey } from '@raydium-io/raydium-sdk'; // 获取 PDA 元数据键的函数
6 | import { getMetadataAccountDataSerializer, MetadataAccountData, MetadataAccountDataArgs } from '@metaplex-foundation/mpl-token-metadata'; // Metaplex 相关库
7 | import { Serializer } from '@metaplex-foundation/umi/serializers'; // Serializer 类型
8 | import { logger } from '../helpers'; // 自定义日志记录器
9 |
10 | // 创建 MutableFilter 类实现 Filter 接口
11 | export class MutableFilter implements Filter {
12 | constructor(
13 | private readonly connection: Connection, // Solana 连接
14 | private readonly metadataSerializer: Serializer // 元数据序列化器
15 | ) {}
16 |
17 | // 执行过滤器的方法
18 | async execute(poolKeys: LiquidityPoolKeysV4): Promise {
19 | try {
20 | // 获取与基础代币相关的元数据 PDA
21 | const metadataPDA = getPdaMetadataKey(poolKeys.baseMint);
22 | // 获取元数据账户信息
23 | const metadataAccount = await this.connection.getAccountInfo(metadataPDA.publicKey);
24 |
25 | // 检查账户数据是否存在
26 | if (!metadataAccount?.data) {
27 | return { ok: false, message: '可变性 -> 获取账户数据失败' }; // 返回错误信息
28 | }
29 |
30 | // 反序列化账户数据
31 | const deserialize = this.metadataSerializer.deserialize(metadataAccount.data);
32 | const mutable = deserialize[0].isMutable; // 检查元数据是否可变
33 |
34 | // 返回结果
35 | return { ok: !mutable, message: !mutable ? undefined : "可变性 -> 创建者可以更改元数据" };
36 | } catch (e: any) {
37 | // 记录错误日志
38 | logger.error({ mint: poolKeys.baseMint }, `可变性 -> 检查元数据是否可变失败`);
39 | }
40 |
41 | return { ok: false, message: '可变性 -> 检查元数据是否可变失败' }; // 返回未通过的结果
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/filters/pool-filters.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { Connection } from '@solana/web3.js'; // Solana 相关库
3 | import { LiquidityPoolKeysV4, Token, TokenAmount } from '@raydium-io/raydium-sdk'; // Raydium SDK
4 | import { getMetadataAccountDataSerializer } from '@metaplex-foundation/mpl-token-metadata'; // Metaplex 相关库
5 | import { BurnFilter } from './burn.filter'; // 引入销毁过滤器
6 | import { MutableFilter } from './mutable.filter'; // 引入可变性过滤器
7 | import { RenouncedFreezeFilter } from './renounced.filter'; // 引入放弃冻结过滤器
8 | import { PoolSizeFilter } from './pool-size.filter'; // 引入池大小过滤器
9 | import { CHECK_IF_BURNED, CHECK_IF_FREEZABLE, CHECK_IF_MINT_IS_RENOUNCED, CHECK_IF_MUTABLE, logger } from '../helpers'; // 引入辅助函数和常量
10 |
11 | // 过滤器接口
12 | export interface Filter {
13 | execute(poolKeysV4: LiquidityPoolKeysV4): Promise; // 执行过滤器的方法
14 | }
15 |
16 | // 过滤器结果接口
17 | export interface FilterResult {
18 | ok: boolean; // 过滤器是否通过
19 | message?: string; // 可选的消息
20 | }
21 |
22 | // 池过滤器参数接口
23 | export interface PoolFilterArgs {
24 | minPoolSize: TokenAmount; // 最小池大小
25 | maxPoolSize: TokenAmount; // 最大池大小
26 | quoteToken: Token; // 报价代币
27 | }
28 |
29 | // 池过滤器类
30 | export class PoolFilters {
31 | private readonly filters: Filter[] = []; // 存储过滤器数组
32 |
33 | constructor(
34 | readonly connection: Connection, // Solana 连接
35 | readonly args: PoolFilterArgs, // 过滤器参数
36 | ) {
37 | // 根据配置条件添加相应的过滤器
38 | if (CHECK_IF_BURNED) {
39 | this.filters.push(new BurnFilter(connection)); // 添加销毁过滤器
40 | }
41 |
42 | if (CHECK_IF_MINT_IS_RENOUNCED || CHECK_IF_FREEZABLE) {
43 | this.filters.push(new RenouncedFreezeFilter(connection, CHECK_IF_MINT_IS_RENOUNCED, CHECK_IF_FREEZABLE)); // 添加放弃冻结过滤器
44 | }
45 |
46 | if (CHECK_IF_MUTABLE) {
47 | this.filters.push(new MutableFilter(connection, getMetadataAccountDataSerializer())); // 添加可变性过滤器
48 | }
49 |
50 | // 如果最小或最大池大小不为零,添加池大小过滤器
51 | if (!args.minPoolSize.isZero() || !args.maxPoolSize.isZero()) {
52 | this.filters.push(new PoolSizeFilter(connection, args.quoteToken, args.minPoolSize, args.maxPoolSize));
53 | }
54 | }
55 |
56 | // 执行所有过滤器的方法
57 | public async execute(poolKeys: LiquidityPoolKeysV4): Promise {
58 | // 如果没有过滤器,则通过
59 | if (this.filters.length === 0) {
60 | return true;
61 | }
62 |
63 | // 并行执行所有过滤器
64 | const result = await Promise.all(this.filters.map((f) => f.execute(poolKeys)));
65 | const pass = result.every((r) => r.ok); // 检查是否所有过滤器都通过
66 |
67 | if (pass) {
68 | return true; // 如果所有过滤器都通过,返回 true
69 | }
70 |
71 | // 记录未通过过滤器的消息
72 | for (const filterResult of result.filter((r) => !r.ok)) {
73 | logger.trace(filterResult.message);
74 | }
75 |
76 | return false; // 返回 false,表示未通过
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/filters/pool-size.filter.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { Filter, FilterResult } from './pool-filters'; // 过滤器接口和结果类型
3 | import { LiquidityPoolKeysV4, Token, TokenAmount } from '@raydium-io/raydium-sdk'; // Raydium SDK
4 | import { Connection } from '@solana/web3.js'; // Solana 相关库
5 | import { logger } from '../helpers'; // 自定义日志记录器
6 |
7 | // 创建 PoolSizeFilter 类实现 Filter 接口
8 | export class PoolSizeFilter implements Filter {
9 | constructor(
10 | private readonly connection: Connection, // Solana 连接
11 | private readonly quoteToken: Token, // 报价代币
12 | private readonly minPoolSize: TokenAmount, // 最小池大小
13 | private readonly maxPoolSize: TokenAmount, // 最大池大小
14 | ) {}
15 |
16 | // 执行过滤器的方法
17 | async execute(poolKeys: LiquidityPoolKeysV4): Promise {
18 | try {
19 | // 获取报价库的账户余额
20 | const response = await this.connection.getTokenAccountBalance(poolKeys.quoteVault, this.connection.commitment);
21 | const poolSize = new TokenAmount(this.quoteToken, response.value.amount, true); // 创建池大小的 TokenAmount 实例
22 | let inRange = true; // 默认池大小在范围内
23 |
24 | // 检查最大池大小
25 | if (!this.maxPoolSize?.isZero()) {
26 | inRange = poolSize.raw.lte(this.maxPoolSize.raw); // 检查当前池大小是否小于等于最大池大小
27 |
28 | if (!inRange) {
29 | return { ok: false, message: `池大小 -> 池大小 ${poolSize.toFixed()} > ${this.maxPoolSize.toFixed()}` }; // 返回未通过的结果
30 | }
31 | }
32 |
33 | // 检查最小池大小
34 | if (!this.minPoolSize?.isZero()) {
35 | inRange = poolSize.raw.gte(this.minPoolSize.raw); // 检查当前池大小是否大于等于最小池大小
36 |
37 | if (!inRange) {
38 | return { ok: false, message: `池大小 -> 池大小 ${poolSize.toFixed()} < ${this.minPoolSize.toFixed()}` }; // 返回未通过的结果
39 | }
40 | }
41 |
42 | return { ok: inRange }; // 返回检查结果
43 | } catch (error) {
44 | // 记录错误日志
45 | logger.error({ mint: poolKeys.baseMint }, `检查池大小失败`);
46 | }
47 |
48 | return { ok: false, message: '池大小 -> 检查池大小失败' }; // 返回未通过的结果
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/filters/renounced.filter.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { Filter, FilterResult } from './pool-filters'; // 过滤器接口和结果类型
3 | import { MintLayout } from '@solana/spl-token'; // 代币布局
4 | import { Connection } from '@solana/web3.js'; // Solana 相关库
5 | import { LiquidityPoolKeysV4 } from '@raydium-io/raydium-sdk'; // Raydium SDK 的流动性池密钥类型
6 | import { logger } from '../helpers'; // 自定义日志记录器
7 |
8 | // 创建 RenouncedFreezeFilter 类实现 Filter 接口
9 | export class RenouncedFreezeFilter implements Filter {
10 | constructor(
11 | private readonly connection: Connection, // Solana 连接
12 | private readonly checkRenounced: boolean, // 是否检查是否放弃
13 | private readonly checkFreezable: boolean // 是否检查是否可冻结
14 | ) {}
15 |
16 | // 执行过滤器的方法
17 | async execute(poolKeys: LiquidityPoolKeysV4): Promise {
18 | // 构建错误消息
19 | const errorMessage = [this.checkRenounced ? 'mint' : undefined, this.checkFreezable ? 'freeze' : undefined].filter((e) => e !== undefined);
20 |
21 | try {
22 | // 获取基础代币的账户信息
23 | const accountInfo = await this.connection.getAccountInfo(poolKeys.baseMint, this.connection.commitment);
24 | if (!accountInfo?.data) {
25 | return { ok: false, message: '放弃冻结 -> 获取账户数据失败' }; // 返回错误信息
26 | }
27 |
28 | // 解码代币账户信息
29 | const deserialize = MintLayout.decode(accountInfo.data);
30 | const renounced = !this.checkRenounced || deserialize.mintAuthorityOption === 0; // 检查是否放弃
31 | const freezable = !this.checkFreezable || deserialize.freezeAuthorityOption !== 0; // 检查是否可冻结
32 |
33 | // 构建返回消息
34 | const message = [renounced ? undefined : 'mint', !freezable ? undefined : 'freeze'].filter((e) => e !== undefined);
35 | const ok = renounced && !freezable; // 检查是否满足条件
36 |
37 | return { ok: ok, message: ok ? undefined : `放弃冻结 -> 创建者可以 ${message.join(' 和 ')} 代币` }; // 返回结果
38 | } catch (e) {
39 | // 记录错误日志
40 | logger.error({ mint: poolKeys.baseMint }, `放弃冻结 -> 检查创建者是否可以 ${errorMessage.join(' 和 ')} 代币失败`);
41 | }
42 |
43 | return { ok: false, message: `放弃冻结 -> 检查创建者是否可以 ${errorMessage.join(' 和 ')} 代币失败` }; // 返回未通过的结果
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/helpers/constants.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { Logger } from 'pino'; // 日志记录库
3 | import dotenv from 'dotenv'; // 环境变量加载库
4 | import { Commitment } from '@solana/web3.js'; // Solana 相关库
5 | import { logger } from './logger'; // 自定义日志记录器
6 |
7 | // 加载环境变量
8 | dotenv.config();
9 |
10 | // 检索环境变量的函数
11 | const retrieveEnvVariable = (variableName: string, logger: Logger) => {
12 | const variable = process.env[variableName] || ''; // 从环境变量中获取值
13 | if (!variable) {
14 | logger.error(`${variableName} 未设置`); // 记录错误日志
15 | process.exit(1); // 退出程序
16 | }
17 | return variable; // 返回环境变量的值
18 | };
19 |
20 | // 钱包
21 | export const PRIVATE_KEY = retrieveEnvVariable('PRIVATE_KEY', logger); // 私钥
22 |
23 | // 连接配置
24 | export const NETWORK = 'mainnet-beta'; // 网络
25 | export const COMMITMENT_LEVEL: Commitment = retrieveEnvVariable('COMMITMENT_LEVEL', logger) as Commitment; // 提交级别
26 | export const RPC_ENDPOINT = retrieveEnvVariable('RPC_ENDPOINT', logger); // RPC 端点
27 | export const RPC_WEBSOCKET_ENDPOINT = retrieveEnvVariable('RPC_WEBSOCKET_ENDPOINT', logger); // RPC WebSocket 端点
28 |
29 | // 机器人配置
30 | export const LOG_LEVEL = retrieveEnvVariable('LOG_LEVEL', logger); // 日志级别
31 | export const ONE_TOKEN_AT_A_TIME = retrieveEnvVariable('ONE_TOKEN_AT_A_TIME', logger) === 'true'; // 一次处理一个代币
32 | export const COMPUTE_UNIT_LIMIT = Number(retrieveEnvVariable('COMPUTE_UNIT_LIMIT', logger)); // 计算单元限制
33 | export const COMPUTE_UNIT_PRICE = Number(retrieveEnvVariable('COMPUTE_UNIT_PRICE', logger)); // 计算单元价格
34 | export const PRE_LOAD_EXISTING_MARKETS = retrieveEnvVariable('PRE_LOAD_EXISTING_MARKETS', logger) === 'true'; // 预加载现有市场
35 | export const CACHE_NEW_MARKETS = retrieveEnvVariable('CACHE_NEW_MARKETS', logger) === 'true'; // 缓存新市场
36 | export const TRANSACTION_EXECUTOR = retrieveEnvVariable('TRANSACTION_EXECUTOR', logger); // 交易执行器类型
37 | export const CUSTOM_FEE = retrieveEnvVariable('CUSTOM_FEE', logger); // 自定义费用
38 |
39 | // 购买配置
40 | export const AUTO_BUY_DELAY = Number(retrieveEnvVariable('AUTO_BUY_DELAY', logger)); // 自动购买延迟
41 | export const QUOTE_MINT = retrieveEnvVariable('QUOTE_MINT', logger); // 报价代币的 mint
42 | export const QUOTE_AMOUNT = retrieveEnvVariable('QUOTE_AMOUNT', logger); // 报价金额
43 | export const MAX_BUY_RETRIES = Number(retrieveEnvVariable('MAX_BUY_RETRIES', logger)); // 最大购买重试次数
44 | export const BUY_SLIPPAGE = Number(retrieveEnvVariable('BUY_SLIPPAGE', logger)); // 购买滑点
45 |
46 | // 出售配置
47 | export const AUTO_SELL = retrieveEnvVariable('AUTO_SELL', logger) === 'true'; // 是否自动出售
48 | export const AUTO_SELL_DELAY = Number(retrieveEnvVariable('AUTO_SELL_DELAY', logger)); // 自动出售延迟
49 | export const MAX_SELL_RETRIES = Number(retrieveEnvVariable('MAX_SELL_RETRIES', logger)); // 最大出售重试次数
50 | export const TAKE_PROFIT = Number(retrieveEnvVariable('TAKE_PROFIT', logger)); // 止盈设置
51 | export const STOP_LOSS = Number(retrieveEnvVariable('STOP_LOSS', logger)); // 止损设置
52 | export const PRICE_CHECK_INTERVAL = Number(retrieveEnvVariable('PRICE_CHECK_INTERVAL', logger)); // 价格检查间隔
53 | export const PRICE_CHECK_DURATION = Number(retrieveEnvVariable('PRICE_CHECK_DURATION', logger)); // 价格检查持续时间
54 | export const SELL_SLIPPAGE = Number(retrieveEnvVariable('SELL_SLIPPAGE', logger)); // 出售滑点
55 |
56 | // 过滤器配置
57 | export const FILTER_CHECK_INTERVAL = Number(retrieveEnvVariable('FILTER_CHECK_INTERVAL', logger)); // 过滤器检查间隔
58 | export const FILTER_CHECK_DURATION = Number(retrieveEnvVariable('FILTER_CHECK_DURATION', logger)); // 过滤器检查持续时间
59 | export const CONSECUTIVE_FILTER_MATCHES = Number(retrieveEnvVariable('CONSECUTIVE_FILTER_MATCHES', logger)); // 连续过滤器匹配次数
60 | export const CHECK_IF_MUTABLE = retrieveEnvVariable('CHECK_IF_MUTABLE', logger) === 'true'; // 检查是否可变
61 | export const CHECK_IF_MINT_IS_RENOUNCED = retrieveEnvVariable('CHECK_IF_MINT_IS_RENOUNCED', logger) === 'true'; // 检查是否被放弃
62 | export const CHECK_IF_FREEZABLE = retrieveEnvVariable('CHECK_IF_FREEZABLE', logger) === 'true'; // 检查是否可冻结
63 | export const CHECK_IF_BURNED = retrieveEnvVariable('CHECK_IF_BURNED', logger) === 'true'; // 检查是否已销毁
64 | export const MIN_POOL_SIZE = retrieveEnvVariable('MIN_POOL_SIZE', logger); // 最小池大小
65 | export const MAX_POOL_SIZE = retrieveEnvVariable('MAX_POOL_SIZE', logger); // 最大池大小
66 | export const USE_SNIPE_LIST = retrieveEnvVariable('USE_SNIPE_LIST', logger) === 'true'; // 使用抢购列表
67 | export const SNIPE_LIST_REFRESH_INTERVAL = Number(retrieveEnvVariable('SNIPE_LIST_REFRESH_INTERVAL', logger)); // 抢购列表刷新间隔
68 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/helpers/index.ts:
--------------------------------------------------------------------------------
1 | export * from './market';
2 | export * from './liquidity';
3 | export * from './logger';
4 | export * from './constants';
5 | export * from './token';
6 | export * from './wallet';
7 | export * from './promises'
8 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/helpers/liquidity.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { PublicKey } from '@solana/web3.js'; // Solana 相关库
3 | import { Liquidity, LiquidityPoolKeys, LiquidityStateV4, MAINNET_PROGRAM_ID, Market } from '@raydium-io/raydium-sdk'; // Raydium SDK
4 | import { MinimalMarketLayoutV3 } from './market'; // 最小市场布局
5 |
6 | // 创建流动池密钥的函数
7 | export function createPoolKeys(
8 | id: PublicKey, // 流动池 ID
9 | accountData: LiquidityStateV4, // 流动池状态
10 | minimalMarketLayoutV3: MinimalMarketLayoutV3, // 最小市场布局
11 | ): LiquidityPoolKeys { // 返回流动池密钥
12 | return {
13 | id, // 流动池 ID
14 | baseMint: accountData.baseMint, // 基础代币的 mint 地址
15 | quoteMint: accountData.quoteMint, // 报价代币的 mint 地址
16 | lpMint: accountData.lpMint, // 流动性代币的 mint 地址
17 | baseDecimals: accountData.baseDecimal.toNumber(), // 基础代币的小数位数
18 | quoteDecimals: accountData.quoteDecimal.toNumber(), // 报价代币的小数位数
19 | lpDecimals: 5, // 流动性代币的小数位数
20 | version: 4, // 版本号
21 | programId: MAINNET_PROGRAM_ID.AmmV4, // 程序 ID
22 | authority: Liquidity.getAssociatedAuthority({ // 获取关联的授权公钥
23 | programId: MAINNET_PROGRAM_ID.AmmV4,
24 | }).publicKey,
25 | openOrders: accountData.openOrders, // 当前开放订单
26 | targetOrders: accountData.targetOrders, // 目标订单
27 | baseVault: accountData.baseVault, // 基础代币的库房地址
28 | quoteVault: accountData.quoteVault, // 报价代币的库房地址
29 | marketVersion: 3, // 市场版本号
30 | marketProgramId: accountData.marketProgramId, // 市场程序 ID
31 | marketId: accountData.marketId, // 市场 ID
32 | marketAuthority: Market.getAssociatedAuthority({ // 获取市场的关联授权公钥
33 | programId: accountData.marketProgramId,
34 | marketId: accountData.marketId,
35 | }).publicKey,
36 | marketBaseVault: accountData.baseVault, // 市场基础代币的库房地址
37 | marketQuoteVault: accountData.quoteVault, // 市场报价代币的库房地址
38 | marketBids: minimalMarketLayoutV3.bids, // 市场买入订单
39 | marketAsks: minimalMarketLayoutV3.asks, // 市场卖出订单
40 | marketEventQueue: minimalMarketLayoutV3.eventQueue, // 市场事件队列
41 | withdrawQueue: accountData.withdrawQueue, // 提款队列
42 | lpVault: accountData.lpVault, // 流动性代币库房地址
43 | lookupTableAccount: PublicKey.default, // 查找表账户
44 | };
45 | }
46 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/helpers/logger.ts:
--------------------------------------------------------------------------------
1 | // 导入 pino 日志库
2 | import pino from 'pino';
3 |
4 | // 配置日志传输格式
5 | const transport = pino.transport({
6 | target: 'pino-pretty', // 使用 pino-pretty 格式化日志输出
7 | });
8 |
9 | // 创建日志记录器
10 | export const logger = pino(
11 | {
12 | level: 'info', // 设置日志级别为 info
13 | redact: ['poolKeys'], // 遮蔽 poolKeys 字段以保护敏感信息
14 | serializers: {
15 | error: pino.stdSerializers.err, // 使用标准错误序列化器
16 | },
17 | base: undefined, // 不输出基础字段
18 | },
19 | transport, // 使用配置的传输格式
20 | );
21 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/helpers/market.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { Commitment, Connection, PublicKey } from '@solana/web3.js'; // Solana 相关库
3 | import { GetStructureSchema, MARKET_STATE_LAYOUT_V3, publicKey, struct } from '@raydium-io/raydium-sdk'; // Raydium SDK
4 |
5 | // 定义最小市场状态布局 V3
6 | export const MINIMAL_MARKET_STATE_LAYOUT_V3 = struct([
7 | publicKey('eventQueue'), // 事件队列的公钥
8 | publicKey('bids'), // 买入订单的公钥
9 | publicKey('asks'), // 卖出订单的公钥
10 | ]);
11 |
12 | // 定义类型
13 | export type MinimalMarketStateLayoutV3 = typeof MINIMAL_MARKET_STATE_LAYOUT_V3; // 最小市场状态布局类型
14 | export type MinimalMarketLayoutV3 = GetStructureSchema; // 获取最小市场布局的结构类型
15 |
16 | // 获取最小市场 V3 的异步函数
17 | export async function getMinimalMarketV3(
18 | connection: Connection, // Solana 连接
19 | marketId: PublicKey, // 市场 ID
20 | commitment?: Commitment, // 提交级别(可选)
21 | ): Promise { // 返回最小市场布局 V3
22 | // 从区块链获取市场信息
23 | const marketInfo = await connection.getAccountInfo(marketId, {
24 | commitment, // 提交级别
25 | dataSlice: { // 数据切片
26 | offset: MARKET_STATE_LAYOUT_V3.offsetOf('eventQueue'), // 从事件队列开始的偏移
27 | length: 32 * 3, // 读取的长度
28 | },
29 | });
30 |
31 | // 解码并返回市场信息
32 | return MINIMAL_MARKET_STATE_LAYOUT_V3.decode(marketInfo!.data);
33 | }
34 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/helpers/promises.ts:
--------------------------------------------------------------------------------
1 | // 创建一个睡眠函数,返回一个 Promise
2 | export const sleep = (ms = 0) => new Promise((resolve) => setTimeout(resolve, ms));
3 | // 默认参数 ms 为 0,调用 setTimeout 在指定的毫秒数后解析 Promise
4 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/helpers/token.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { Token } from '@raydium-io/raydium-sdk'; // Raydium SDK 的 Token 类
3 | import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; // Solana 代币程序 ID
4 | import { PublicKey } from '@solana/web3.js'; // Solana 相关库
5 |
6 | // 获取代币的函数
7 | export function getToken(token: string) {
8 | // 根据代币类型返回相应的 Token 对象
9 | switch (token) {
10 | case 'WSOL': { // 如果代币是 WSOL
11 | return Token.WSOL; // 返回 WSOL 代币对象
12 | }
13 | case 'USDC': { // 如果代币是 USDC
14 | return new Token(
15 | TOKEN_PROGRAM_ID, // 代币程序 ID
16 | new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'), // USDC 的公钥
17 | 6, // USDC 的小数位数
18 | 'USDC', // 代币符号
19 | 'USDC', // 代币名称
20 | );
21 | }
22 | default: { // 处理不支持的代币类型
23 | throw new Error(`不支持的报价代币 "${token}"。支持的值为 USDC 和 WSOL`); // 抛出错误
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/helpers/wallet.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { Keypair } from '@solana/web3.js'; // Solana 相关库
3 | import bs58 from 'bs58'; // Base58 编码库
4 | import { mnemonicToSeedSync } from 'bip39'; // 处理助记词的库
5 | import { derivePath } from 'ed25519-hd-key'; // HD 钱包路径推导库
6 |
7 | // 获取钱包的函数
8 | export function getWallet(wallet: string): Keypair {
9 | // 如果钱包字符串以 "[" 开头,表示可能是二进制格式的私钥
10 | if (wallet.startsWith('[')) {
11 | return Keypair.fromSecretKey(JSON.parse(wallet)); // 解析并返回密钥对
12 | }
13 |
14 | // 如果钱包字符串包含空格,表示可能是助记词
15 | if (wallet.split(' ').length > 1) {
16 | const seed = mnemonicToSeedSync(wallet, ''); // 将助记词转换为种子
17 | const path = `m/44'/501'/0'/0'`; // 假设使用第一个路径
18 | return Keypair.fromSeed(derivePath(path, seed.toString('hex')).key); // 从种子生成密钥对
19 | }
20 |
21 | // 如果钱包字符串是 Base58 编码的私钥
22 | return Keypair.fromSecretKey(bs58.decode(wallet)); // 解码并返回密钥对
23 | }
24 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/index.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { MarketCache, PoolCache } from './cache'; // 缓存相关
3 | import { Listeners } from './listeners'; // 监听器
4 | import { Connection, KeyedAccountInfo, Keypair } from '@solana/web3.js'; // Solana 连接和账户信息
5 | import { LIQUIDITY_STATE_LAYOUT_V4, MARKET_STATE_LAYOUT_V3, Token, TokenAmount } from '@raydium-io/raydium-sdk'; // Raydium SDK
6 | import { AccountLayout, getAssociatedTokenAddressSync } from '@solana/spl-token'; // 账户布局和代币地址
7 | import { Bot, BotConfig } from './bot'; // 机器人相关
8 | import { DefaultTransactionExecutor, TransactionExecutor } from './transactions'; // 交易执行器
9 | import {
10 | getToken,
11 | getWallet,
12 | logger,
13 | COMMITMENT_LEVEL,
14 | RPC_ENDPOINT,
15 | RPC_WEBSOCKET_ENDPOINT,
16 | PRE_LOAD_EXISTING_MARKETS,
17 | LOG_LEVEL,
18 | CHECK_IF_MUTABLE,
19 | CHECK_IF_MINT_IS_RENOUNCED,
20 | CHECK_IF_FREEZABLE,
21 | CHECK_IF_BURNED,
22 | QUOTE_MINT,
23 | MAX_POOL_SIZE,
24 | MIN_POOL_SIZE,
25 | QUOTE_AMOUNT,
26 | PRIVATE_KEY,
27 | USE_SNIPE_LIST,
28 | ONE_TOKEN_AT_A_TIME,
29 | AUTO_SELL_DELAY,
30 | MAX_SELL_RETRIES,
31 | AUTO_SELL,
32 | MAX_BUY_RETRIES,
33 | AUTO_BUY_DELAY,
34 | COMPUTE_UNIT_LIMIT,
35 | COMPUTE_UNIT_PRICE,
36 | CACHE_NEW_MARKETS,
37 | TAKE_PROFIT,
38 | STOP_LOSS,
39 | BUY_SLIPPAGE,
40 | SELL_SLIPPAGE,
41 | PRICE_CHECK_DURATION,
42 | PRICE_CHECK_INTERVAL,
43 | SNIPE_LIST_REFRESH_INTERVAL,
44 | TRANSACTION_EXECUTOR,
45 | CUSTOM_FEE,
46 | FILTER_CHECK_INTERVAL,
47 | FILTER_CHECK_DURATION,
48 | CONSECUTIVE_FILTER_MATCHES,
49 | } from './helpers'; // 辅助函数和常量
50 | import { version } from './package.json'; // 获取版本信息
51 | import { WarpTransactionExecutor } from './transactions/warp-transaction-executor'; // Warp 交易执行器
52 | import { JitoTransactionExecutor } from './transactions/jito-rpc-transaction-executor'; // Jito 交易执行器
53 |
54 | // 创建与Solana区块链的连接
55 | const connection = new Connection(RPC_ENDPOINT, {
56 | wsEndpoint: RPC_WEBSOCKET_ENDPOINT,
57 | commitment: COMMITMENT_LEVEL,
58 | });
59 |
60 | // 打印钱包和机器人配置信息的函数
61 | function printDetails(wallet: Keypair, quoteToken: Token, bot: Bot) {
62 | logger.info(`
63 |
64 | █████╗ ██╗ ██╗██╗███████╗██████╗ ██████╗ ████████╗
65 | ██╔══██╗╚██╗██╔╝██║██╔════╝██╔══██╗██╔═══██╗╚══██╔══╝
66 | ███████║ ╚███╔╝ ██║███████╗██████╔╝██║ ██║ ██║
67 | ██╔══██║ ██╔██╗ ██║╚════██║██╔══██╗██║ ██║ ██║
68 | ██║ ██║██╔╝ ██╗██║███████║██████╔╝╚██████╔╝ ██║
69 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚══════╝╚═════╝ ╚═════╝ ╚═╝
70 |
71 | AxisBot Solana Sniper v1.0
72 | 制作团队:AxisBot Team
73 | 版本:${version}
74 | `);
75 |
76 | const botConfig = bot.config; // 获取机器人配置
77 |
78 | logger.info('------- 配置开始 -------');
79 | logger.info(`钱包地址: ${wallet.publicKey.toString()}`);
80 |
81 | logger.info('- 机器人 -');
82 |
83 | logger.info(
84 | `使用的执行器: ${bot.isWarp || bot.isJito || (TRANSACTION_EXECUTOR === 'default' ? true : false)}`,
85 | );
86 | if (bot.isWarp || bot.isJito) {
87 | logger.info(`${TRANSACTION_EXECUTOR} 费用: ${CUSTOM_FEE}`); // 打印执行器费用
88 | } else {
89 | logger.info(`计算单元限制: ${botConfig.unitLimit}`); // 打印计算单元限制
90 | logger.info(`计算单元价格(微 lamports): ${botConfig.unitPrice}`); // 打印计算单元价格
91 | }
92 |
93 | logger.info(`每次处理一个代币: ${botConfig.oneTokenAtATime}`); // 打印每次处理一个代币的设置
94 | logger.info(`预加载现有市场: ${PRE_LOAD_EXISTING_MARKETS}`); // 打印是否预加载现有市场
95 | logger.info(`缓存新市场: ${CACHE_NEW_MARKETS}`); // 打印缓存新市场的设置
96 | logger.info(`日志级别: ${LOG_LEVEL}`); // 打印日志级别
97 |
98 | logger.info('- 购买 -');
99 | logger.info(`购买金额: ${botConfig.quoteAmount.toFixed()} ${botConfig.quoteToken.name}`); // 打印购买金额
100 | logger.info(`自动购买延迟: ${botConfig.autoBuyDelay} 毫秒`); // 打印自动购买延迟
101 | logger.info(`最大购买重试次数: ${botConfig.maxBuyRetries}`); // 打印最大购买重试次数
102 | logger.info(`购买金额(${quoteToken.symbol}): ${botConfig.quoteAmount.toFixed()}`); // 打印购买金额
103 | logger.info(`购买滑点: ${botConfig.buySlippage}%`); // 打印购买滑点
104 |
105 | logger.info('- 出售 -');
106 | logger.info(`自动出售: ${AUTO_SELL}`); // 打印自动出售设置
107 | logger.info(`自动出售延迟: ${botConfig.autoSellDelay} 毫秒`); // 打印自动出售延迟
108 | logger.info(`最大出售重试次数: ${botConfig.maxSellRetries}`); // 打印最大出售重试次数
109 | logger.info(`出售滑点: ${botConfig.sellSlippage}%`); // 打印出售滑点
110 | logger.info(`价格检查间隔: ${botConfig.priceCheckInterval} 毫秒`); // 打印价格检查间隔
111 | logger.info(`价格检查持续时间: ${botConfig.priceCheckDuration} 毫秒`); // 打印价格检查持续时间
112 | logger.info(`止盈: ${botConfig.takeProfit}%`); // 打印止盈设置
113 | logger.info(`止损: ${botConfig.stopLoss}%`); // 打印止损设置
114 |
115 | logger.info('- 抢购列表 -');
116 | logger.info(`使用抢购列表: ${botConfig.useSnipeList}`); // 打印抢购列表设置
117 | logger.info(`抢购列表刷新间隔: ${SNIPE_LIST_REFRESH_INTERVAL} 毫秒`); // 打印抢购列表刷新间隔
118 |
119 | if (botConfig.useSnipeList) {
120 | logger.info('- 过滤器 -');
121 | logger.info(`启用抢购列表时过滤器被禁用`); // 打印过滤器禁用信息
122 | } else {
123 | logger.info('- 过滤器 -');
124 | logger.info(`过滤器检查间隔: ${botConfig.filterCheckInterval} 毫秒`); // 打印过滤器检查间隔
125 | logger.info(`过滤器检查持续时间: ${botConfig.filterCheckDuration} 毫秒`); // 打印过滤器检查持续时间
126 | logger.info(`连续过滤器匹配次数: ${botConfig.consecutiveMatchCount}`); // 打印连续过滤器匹配次数
127 | logger.info(`检查是否被放弃: ${botConfig.checkRenounced}`); // 打印检查是否被放弃设置
128 | logger.info(`检查是否可冻结: ${botConfig.checkFreezable}`); // 打印检查是否可冻结设置
129 | logger.info(`检查是否已销毁: ${botConfig.checkBurned}`); // 打印检查是否已销毁设置
130 | logger.info(`最小池大小: ${botConfig.minPoolSize.toFixed()}`); // 打印最小池大小
131 | logger.info(`最大池大小: ${botConfig.maxPoolSize.toFixed()}`); // 打印最大池大小
132 | }
133 |
134 | logger.info('------- 配置结束 -------');
135 |
136 | logger.info('机器人正在运行!按 CTRL + C 停止它。');
137 | }
138 |
139 | // 启动监听器的函数
140 | const runListener = async () => {
141 | logger.level = LOG_LEVEL; // 设置日志级别
142 | logger.info('机器人正在启动...'); // 打印启动信息
143 |
144 | const marketCache = new MarketCache(connection); // 创建市场缓存
145 | const poolCache = new PoolCache(); // 创建池缓存
146 | let txExecutor: TransactionExecutor; // 定义交易执行器变量
147 |
148 | // 根据配置选择交易执行器
149 | switch (TRANSACTION_EXECUTOR) {
150 | case 'warp': {
151 | txExecutor = new WarpTransactionExecutor(CUSTOM_FEE); // 创建Warp交易执行器
152 | break;
153 | }
154 | case 'jito': {
155 | txExecutor = new JitoTransactionExecutor(CUSTOM_FEE, connection); // 创建Jito交易执行器
156 | break;
157 | }
158 | default: {
159 | txExecutor = new DefaultTransactionExecutor(connection); // 默认交易执行器
160 | break;
161 | }
162 | }
163 |
164 | const wallet = getWallet(PRIVATE_KEY.trim()); // 获取钱包
165 | const quoteToken = getToken(QUOTE_MINT); // 获取报价代币
166 | const botConfig = {
167 | wallet,
168 | quoteAta: getAssociatedTokenAddressSync(quoteToken.mint, wallet.publicKey), // 获取关联代币地址
169 | checkRenounced: CHECK_IF_MINT_IS_RENOUNCED,
170 | checkFreezable: CHECK_IF_FREEZABLE,
171 | checkBurned: CHECK_IF_BURNED,
172 | minPoolSize: new TokenAmount(quoteToken, MIN_POOL_SIZE, false), // 最小池大小
173 | maxPoolSize: new TokenAmount(quoteToken, MAX_POOL_SIZE, false), // 最大池大小
174 | quoteToken,
175 | quoteAmount: new TokenAmount(quoteToken, QUOTE_AMOUNT, false), // 报价金额
176 | oneTokenAtATime: ONE_TOKEN_AT_A_TIME,
177 | useSnipeList: USE_SNIPE_LIST,
178 | autoSell: AUTO_SELL,
179 | autoSellDelay: AUTO_SELL_DELAY,
180 | maxSellRetries: MAX_SELL_RETRIES,
181 | autoBuyDelay: AUTO_BUY_DELAY,
182 | maxBuyRetries: MAX_BUY_RETRIES,
183 | unitLimit: COMPUTE_UNIT_LIMIT, // 计算单元限制
184 | unitPrice: COMPUTE_UNIT_PRICE, // 计算单元价格
185 | takeProfit: TAKE_PROFIT, // 止盈设置
186 | stopLoss: STOP_LOSS, // 止损设置
187 | buySlippage: BUY_SLIPPAGE, // 购买滑点
188 | sellSlippage: SELL_SLIPPAGE, // 出售滑点
189 | priceCheckInterval: PRICE_CHECK_INTERVAL, // 价格检查间隔
190 | priceCheckDuration: PRICE_CHECK_DURATION, // 价格检查持续时间
191 | filterCheckInterval: FILTER_CHECK_INTERVAL, // 过滤器检查间隔
192 | filterCheckDuration: FILTER_CHECK_DURATION, // 过滤器检查持续时间
193 | consecutiveMatchCount: CONSECUTIVE_FILTER_MATCHES, // 连续匹配次数
194 | };
195 |
196 | const bot = new Bot(connection, marketCache, poolCache, txExecutor, botConfig); // 创建机器人实例
197 | const valid = await bot.validate(); // 验证机器人配置
198 |
199 | if (!valid) {
200 | logger.info('机器人正在退出...'); // 验证失败时退出
201 | process.exit(1); // 退出程序
202 | }
203 |
204 | if (PRE_LOAD_EXISTING_MARKETS) {
205 | await marketCache.init({ quoteToken }); // 初始化市场缓存
206 | }
207 |
208 | const runTimestamp = Math.floor(new Date().getTime() / 1000); // 获取当前时间戳
209 | const listeners = new Listeners(connection); // 创建监听器实例
210 | await listeners.start({
211 | walletPublicKey: wallet.publicKey,
212 | quoteToken,
213 | autoSell: AUTO_SELL,
214 | cacheNewMarkets: CACHE_NEW_MARKETS,
215 | });
216 |
217 | // 监听市场信息更新
218 | listeners.on('market', (updatedAccountInfo: KeyedAccountInfo) => {
219 | const marketState = MARKET_STATE_LAYOUT_V3.decode(updatedAccountInfo.accountInfo.data); // 解码市场状态
220 | marketCache.save(updatedAccountInfo.accountId.toString(), marketState); // 保存市场状态
221 | });
222 |
223 | // 监听池信息更新
224 | listeners.on('pool', async (updatedAccountInfo: KeyedAccountInfo) => {
225 | const poolState = LIQUIDITY_STATE_LAYOUT_V4.decode(updatedAccountInfo.accountInfo.data); // 解码池状态
226 | const poolOpenTime = parseInt(poolState.poolOpenTime.toString()); // 获取池开放时间
227 | const exists = await poolCache.get(poolState.baseMint.toString()); // 检查池是否存在
228 |
229 | // 如果池不存在且开放时间在当前时间之后,则进行购买
230 | if (!exists && poolOpenTime > runTimestamp) {
231 | poolCache.save(updatedAccountInfo.accountId.toString(), poolState); // 保存池状态
232 | await bot.buy(updatedAccountInfo.accountId, poolState); // 执行购买
233 | }
234 | });
235 |
236 | // 监听钱包信息更新
237 | listeners.on('wallet', async (updatedAccountInfo: KeyedAccountInfo) => {
238 | const accountData = AccountLayout.decode(updatedAccountInfo.accountInfo.data); // 解码账户数据
239 |
240 | // 如果账户数据的mint与报价代币相同,则返回
241 | if (accountData.mint.equals(quoteToken.mint)) {
242 | return;
243 | }
244 |
245 | await bot.sell(updatedAccountInfo.accountId, accountData); // 执行出售
246 | });
247 |
248 | printDetails(wallet, quoteToken, bot); // 打印详细信息
249 | };
250 |
251 | // 运行监听器
252 | runListener();
253 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/listeners/index.ts:
--------------------------------------------------------------------------------
1 | export * from './listeners';
2 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/listeners/listeners.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { LIQUIDITY_STATE_LAYOUT_V4, MAINNET_PROGRAM_ID, MARKET_STATE_LAYOUT_V3, Token } from '@raydium-io/raydium-sdk'; // Raydium SDK
3 | import bs58 from 'bs58'; // Base58 编码库
4 | import { Connection, PublicKey } from '@solana/web3.js'; // Solana 相关库
5 | import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; // 代币程序 ID
6 | import { EventEmitter } from 'events'; // 事件发射器
7 |
8 | // 监听器类,扩展自 EventEmitter
9 | export class Listeners extends EventEmitter {
10 | private subscriptions: number[] = []; // 存储订阅 ID
11 |
12 | constructor(private readonly connection: Connection) {
13 | super(); // 调用父类构造函数
14 | }
15 |
16 | // 启动监听器,接受配置参数
17 | public async start(config: {
18 | walletPublicKey: PublicKey; // 钱包公钥
19 | quoteToken: Token; // 报价代币
20 | autoSell: boolean; // 是否自动出售
21 | cacheNewMarkets: boolean; // 是否缓存新市场
22 | }) {
23 | // 如果配置了缓存新市场,则订阅开放市场变化
24 | if (config.cacheNewMarkets) {
25 | const openBookSubscription = await this.subscribeToOpenBookMarkets(config);
26 | this.subscriptions.push(openBookSubscription); // 存储订阅 ID
27 | }
28 |
29 | // 订阅 Raydium 池变化
30 | const raydiumSubscription = await this.subscribeToRaydiumPools(config);
31 | this.subscriptions.push(raydiumSubscription); // 存储订阅 ID
32 |
33 | // 如果配置了自动出售,则订阅钱包变化
34 | if (config.autoSell) {
35 | const walletSubscription = await this.subscribeToWalletChanges(config);
36 | this.subscriptions.push(walletSubscription); // 存储订阅 ID
37 | }
38 | }
39 |
40 | // 订阅开放书市场的变化
41 | private async subscribeToOpenBookMarkets(config: { quoteToken: Token }) {
42 | return this.connection.onProgramAccountChange(
43 | MAINNET_PROGRAM_ID.OPENBOOK_MARKET, // 订阅的程序 ID
44 | async (updatedAccountInfo) => {
45 | this.emit('market', updatedAccountInfo); // 触发市场更新事件
46 | },
47 | this.connection.commitment, // 提交级别
48 | [
49 | { dataSize: MARKET_STATE_LAYOUT_V3.span }, // 数据大小过滤
50 | {
51 | memcmp: { // 根据报价代币的 mint 过滤
52 | offset: MARKET_STATE_LAYOUT_V3.offsetOf('quoteMint'),
53 | bytes: config.quoteToken.mint.toBase58(),
54 | },
55 | },
56 | ],
57 | );
58 | }
59 |
60 | // 订阅 Raydium 池的变化
61 | private async subscribeToRaydiumPools(config: { quoteToken: Token }) {
62 | return this.connection.onProgramAccountChange(
63 | MAINNET_PROGRAM_ID.AmmV4, // 订阅的程序 ID
64 | async (updatedAccountInfo) => {
65 | this.emit('pool', updatedAccountInfo); // 触发池更新事件
66 | },
67 | this.connection.commitment, // 提交级别
68 | [
69 | { dataSize: LIQUIDITY_STATE_LAYOUT_V4.span }, // 数据大小过滤
70 | {
71 | memcmp: { // 根据报价代币的 mint 过滤
72 | offset: LIQUIDITY_STATE_LAYOUT_V4.offsetOf('quoteMint'),
73 | bytes: config.quoteToken.mint.toBase58(),
74 | },
75 | },
76 | {
77 | memcmp: { // 根据市场程序 ID 过滤
78 | offset: LIQUIDITY_STATE_LAYOUT_V4.offsetOf('marketProgramId'),
79 | bytes: MAINNET_PROGRAM_ID.OPENBOOK_MARKET.toBase58(),
80 | },
81 | },
82 | {
83 | memcmp: { // 根据状态过滤
84 | offset: LIQUIDITY_STATE_LAYOUT_V4.offsetOf('status'),
85 | bytes: bs58.encode([6, 0, 0, 0, 0, 0, 0, 0]),
86 | },
87 | },
88 | ],
89 | );
90 | }
91 |
92 | // 订阅钱包变化
93 | private async subscribeToWalletChanges(config: { walletPublicKey: PublicKey }) {
94 | return this.connection.onProgramAccountChange(
95 | TOKEN_PROGRAM_ID, // 订阅的程序 ID
96 | async (updatedAccountInfo) => {
97 | this.emit('wallet', updatedAccountInfo); // 触发钱包更新事件
98 | },
99 | this.connection.commitment, // 提交级别
100 | [
101 | {
102 | dataSize: 165, // 数据大小过滤
103 | },
104 | {
105 | memcmp: { // 根据钱包公钥过滤
106 | offset: 32, // 偏移量
107 | bytes: config.walletPublicKey.toBase58(),
108 | },
109 | },
110 | ],
111 | );
112 | }
113 |
114 | // 停止所有订阅
115 | public async stop() {
116 | for (let i = this.subscriptions.length; i >= 0; --i) {
117 | const subscription = this.subscriptions[i];
118 | await this.connection.removeAccountChangeListener(subscription); // 移除账户变化监听
119 | this.subscriptions.splice(i, 1); // 从订阅列表中删除
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "axisbot-solana-sniper",
3 | "author": "AxisBot",
4 | "homepage": "https://axisbot.xyz",
5 | "version": "1.0.1",
6 | "scripts": {
7 | "start": "ts-node index.ts",
8 | "tsc": "tsc --noEmit"
9 | },
10 | "dependencies": {
11 | "@metaplex-foundation/mpl-token-metadata": "^3.2.1",
12 | "@raydium-io/raydium-sdk": "^1.3.1-beta.47",
13 | "@solana/spl-token": "^0.4.0",
14 | "@solana/web3.js": "^1.89.1",
15 | "async-mutex": "^0.5.0",
16 | "axios": "^1.6.8",
17 | "bigint-buffer": "^1.1.5",
18 | "bip39": "^3.1.0",
19 | "bn.js": "^5.2.1",
20 | "bs58": "^5.0.0",
21 | "dotenv": "^16.4.1",
22 | "ed25519-hd-key": "^1.3.0",
23 | "i": "^0.3.7",
24 | "npm": "^10.5.2",
25 | "pino": "^8.18.0",
26 | "pino-pretty": "^10.3.1",
27 | "pino-std-serializers": "^6.2.2"
28 | },
29 | "devDependencies": {
30 | "@types/bn.js": "^5.1.5",
31 | "prettier": "^3.2.4",
32 | "ts-node": "^10.9.2",
33 | "typescript": "^5.3.3"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/snipe-list.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kent7j/cc7/5513027b90ac474b4b05670e891c19d11580de2e/Bot汉化/bot Solana Sniper Main/snipe-list.txt
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/transactions/default-transaction-executor.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import {
3 | BlockhashWithExpiryBlockHeight,
4 | Connection,
5 | Keypair,
6 | Transaction,
7 | VersionedTransaction,
8 | } from '@solana/web3.js'; // Solana 相关库
9 | import { TransactionExecutor } from './transaction-executor.interface'; // 交易执行器接口
10 | import { logger } from '../helpers'; // 日志记录器
11 |
12 | // 默认交易执行器类
13 | export class DefaultTransactionExecutor implements TransactionExecutor {
14 | constructor(private readonly connection: Connection) {} // 初始化连接
15 |
16 | // 执行并确认交易的公共方法
17 | public async executeAndConfirm(
18 | transaction: VersionedTransaction, // 版本化交易
19 | payer: Keypair, // 付款方的密钥对
20 | latestBlockhash: BlockhashWithExpiryBlockHeight, // 最新区块哈希和过期区块高度
21 | ): Promise<{ confirmed: boolean; signature?: string }> {
22 | logger.debug('正在执行交易...'); // 记录交易执行日志
23 | const signature = await this.execute(transaction); // 执行交易并获取签名
24 |
25 | logger.debug({ signature }, '正在确认交易...'); // 记录确认交易日志
26 | return this.confirm(signature, latestBlockhash); // 确认交易并返回结果
27 | }
28 |
29 | // 私有方法:执行交易
30 | private async execute(transaction: Transaction | VersionedTransaction) {
31 | return this.connection.sendRawTransaction(transaction.serialize(), { // 发送序列化的交易
32 | preflightCommitment: this.connection.commitment, // 提交前的确认级别
33 | });
34 | }
35 |
36 | // 私有方法:确认交易
37 | private async confirm(signature: string, latestBlockhash: BlockhashWithExpiryBlockHeight) {
38 | const confirmation = await this.connection.confirmTransaction(
39 | {
40 | signature, // 交易签名
41 | lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, // 最后有效区块高度
42 | blockhash: latestBlockhash.blockhash, // 区块哈希
43 | },
44 | this.connection.commitment, // 提交的确认级别
45 | );
46 |
47 | return { confirmed: !confirmation.value.err, signature }; // 返回确认结果
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/transactions/index.ts:
--------------------------------------------------------------------------------
1 | export * from './default-transaction-executor';
2 | export * from './transaction-executor.interface';
3 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/transactions/jito-rpc-transaction-executor.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import {
3 | BlockhashWithExpiryBlockHeight,
4 | Keypair,
5 | PublicKey,
6 | SystemProgram,
7 | Connection,
8 | TransactionMessage,
9 | VersionedTransaction,
10 | } from '@solana/web3.js'; // Solana 相关库
11 | import { TransactionExecutor } from './transaction-executor.interface'; // 交易执行器接口
12 | import { logger } from '../helpers'; // 日志记录器
13 | import axios, { AxiosError } from 'axios'; // Axios 库用于 HTTP 请求
14 | import bs58 from 'bs58'; // Base58 编码库
15 | import { Currency, CurrencyAmount } from '@raydium-io/raydium-sdk'; // Raydium SDK
16 |
17 | // Jito 交易执行器类
18 | export class JitoTransactionExecutor implements TransactionExecutor {
19 | // Jito 提示账户列表
20 | private jitpTipAccounts = [
21 | 'Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY',
22 | 'DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL',
23 | '96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5',
24 | '3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT',
25 | 'HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe',
26 | 'ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49',
27 | 'ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt',
28 | 'DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh',
29 | ];
30 |
31 | private JitoFeeWallet: PublicKey; // Jito 费用钱包
32 |
33 | constructor(
34 | private readonly jitoFee: string, // Jito 费用
35 | private readonly connection: Connection, // Solana 连接
36 | ) {
37 | this.JitoFeeWallet = this.getRandomValidatorKey(); // 获取随机验证者密钥
38 | }
39 |
40 | // 获取随机验证者密钥
41 | private getRandomValidatorKey(): PublicKey {
42 | const randomValidator = this.jitpTipAccounts[Math.floor(Math.random() * this.jitpTipAccounts.length)];
43 | return new PublicKey(randomValidator); // 返回随机选择的验证者密钥
44 | }
45 |
46 | // 执行并确认交易的公共方法
47 | public async executeAndConfirm(
48 | transaction: VersionedTransaction, // 版本化交易
49 | payer: Keypair, // 付款方的密钥对
50 | latestBlockhash: BlockhashWithExpiryBlockHeight, // 最新区块哈希和过期区块高度
51 | ): Promise<{ confirmed: boolean; signature?: string }> {
52 | logger.debug('开始 Jito 交易执行...'); // 记录交易执行开始日志
53 | this.JitoFeeWallet = this.getRandomValidatorKey(); // 每次执行时更新钱包密钥
54 | logger.trace(`选择的 Jito 费用钱包: ${this.JitoFeeWallet.toBase58()}`); // 记录选中的费用钱包
55 |
56 | try {
57 | const fee = new CurrencyAmount(Currency.SOL, this.jitoFee, false).raw.toNumber(); // 计算费用
58 | logger.trace(`计算的费用: ${fee} lamports`); // 记录计算的费用
59 |
60 | // 创建 Jito 提示交易消息
61 | const jitTipTxFeeMessage = new TransactionMessage({
62 | payerKey: payer.publicKey, // 付款方公钥
63 | recentBlockhash: latestBlockhash.blockhash, // 最新区块哈希
64 | instructions: [
65 | SystemProgram.transfer({ // 转账指令
66 | fromPubkey: payer.publicKey, // 付款方公钥
67 | toPubkey: this.JitoFeeWallet, // 收款方公钥
68 | lamports: fee, // 转账的 lamports 数量
69 | }),
70 | ],
71 | }).compileToV0Message(); // 编译为 V0 消息
72 |
73 | const jitoFeeTx = new VersionedTransaction(jitTipTxFeeMessage); // 创建版本化交易
74 | jitoFeeTx.sign([payer]); // 签名交易
75 |
76 | const jitoTxsignature = bs58.encode(jitoFeeTx.signatures[0]); // 获取签名并进行 Base58 编码
77 |
78 | // 一次性序列化交易
79 | const serializedjitoFeeTx = bs58.encode(jitoFeeTx.serialize()); // 序列化 Jito 费用交易
80 | const serializedTransaction = bs58.encode(transaction.serialize()); // 序列化主交易
81 | const serializedTransactions = [serializedjitoFeeTx, serializedTransaction]; // 组合交易
82 |
83 | // Jito API 端点列表
84 | const endpoints = [
85 | 'https://mainnet.block-engine.jito.wtf/api/v1/bundles',
86 | 'https://amsterdam.mainnet.block-engine.jito.wtf/api/v1/bundles',
87 | 'https://frankfurt.mainnet.block-engine.jito.wtf/api/v1/bundles',
88 | 'https://ny.mainnet.block-engine.jito.wtf/api/v1/bundles',
89 | 'https://tokyo.mainnet.block-engine.jito.wtf/api/v1/bundles',
90 | ];
91 |
92 | // 发送请求到所有端点
93 | const requests = endpoints.map((url) =>
94 | axios.post(url, {
95 | jsonrpc: '2.0',
96 | id: 1,
97 | method: 'sendBundle',
98 | params: [serializedTransactions], // 发送序列化的交易
99 | }),
100 | );
101 |
102 | logger.trace('正在向端点发送交易...'); // 记录发送交易日志
103 | const results = await Promise.all(requests.map((p) => p.catch((e) => e))); // 等待所有请求结果
104 |
105 | const successfulResults = results.filter((result) => !(result instanceof Error)); // 筛选成功的结果
106 |
107 | if (successfulResults.length > 0) { // 如果至少有一个成功的响应
108 | logger.trace(`至少有一个成功的响应`); // 记录成功响应日志
109 | logger.debug(`确认 Jito 交易...`); // 记录确认交易日志
110 | return await this.confirm(jitoTxsignature, latestBlockhash); // 确认交易
111 | } else {
112 | logger.debug(`没有收到 Jito 的成功响应`); // 记录无成功响应日志
113 | }
114 |
115 | return { confirmed: false }; // 返回未确认
116 | } catch (error) {
117 | if (error instanceof AxiosError) {
118 | logger.trace({ error: error.response?.data }, '执行 Jito 交易失败'); // 记录错误信息
119 | }
120 | logger.error('交易执行期间出错', error); // 记录错误日志
121 | return { confirmed: false }; // 返回未确认
122 | }
123 | }
124 |
125 | // 私有方法:确认交易
126 | private async confirm(signature: string, latestBlockhash: BlockhashWithExpiryBlockHeight) {
127 | const confirmation = await this.connection.confirmTransaction(
128 | {
129 | signature, // 交易签名
130 | lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, // 最后有效区块高度
131 | blockhash: latestBlockhash.blockhash, // 区块哈希
132 | },
133 | this.connection.commitment, // 提交的确认级别
134 | );
135 |
136 | return { confirmed: !confirmation.value.err, signature }; // 返回确认结果
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/transactions/transaction-executor.interface.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import { BlockhashWithExpiryBlockHeight, Keypair, VersionedTransaction } from '@solana/web3.js'; // Solana 相关库
3 |
4 | // 交易执行器接口
5 | export interface TransactionExecutor {
6 | // 执行并确认交易的方法
7 | executeAndConfirm(
8 | transaction: VersionedTransaction, // 版本化交易
9 | payer: Keypair, // 付款方的密钥对
10 | latestBlockHash: BlockhashWithExpiryBlockHeight, // 最新区块哈希和过期区块高度
11 | ): Promise<{ confirmed: boolean; signature?: string; error?: string }>; // 返回确认结果、交易签名和可能的错误信息
12 | }
13 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/transactions/warp-transaction-executor.ts:
--------------------------------------------------------------------------------
1 | // 导入所需的模块和库
2 | import {
3 | BlockhashWithExpiryBlockHeight,
4 | Keypair,
5 | PublicKey,
6 | SystemProgram,
7 | TransactionMessage,
8 | VersionedTransaction,
9 | } from '@solana/web3.js'; // Solana 相关库
10 | import { TransactionExecutor } from './transaction-executor.interface'; // 交易执行器接口
11 | import { logger } from '../helpers'; // 日志记录器
12 | import axios, { AxiosError } from 'axios'; // Axios 库用于 HTTP 请求
13 | import bs58 from 'bs58'; // Base58 编码库
14 | import { Currency, CurrencyAmount } from '@raydium-io/raydium-sdk'; // Raydium SDK
15 |
16 | // Warp 交易执行器类
17 | export class WarpTransactionExecutor implements TransactionExecutor {
18 | private readonly warpFeeWallet = new PublicKey('AXSBTx227eh6ZtEu5kHrKCWviW6R1JJV7oDJ63tX9GiH'); // Warp 费用钱包地址
19 |
20 | constructor(private readonly warpFee: string) {} // 初始化 Warp 费用
21 |
22 | // 执行并确认交易的公共方法
23 | public async executeAndConfirm(
24 | transaction: VersionedTransaction, // 版本化交易
25 | payer: Keypair, // 付款方的密钥对
26 | latestBlockhash: BlockhashWithExpiryBlockHeight, // 最新区块哈希和过期区块高度
27 | ): Promise<{ confirmed: boolean; signature?: string }> {
28 | logger.debug('正在执行交易...'); // 记录执行交易日志
29 |
30 | try {
31 | // 计算费用
32 | const fee = new CurrencyAmount(Currency.SOL, this.warpFee, false).raw.toNumber();
33 | // 创建 Warp 费用交易消息
34 | const warpFeeMessage = new TransactionMessage({
35 | payerKey: payer.publicKey, // 付款方公钥
36 | recentBlockhash: latestBlockhash.blockhash, // 最新区块哈希
37 | instructions: [
38 | SystemProgram.transfer({ // 转账指令
39 | fromPubkey: payer.publicKey, // 付款方公钥
40 | toPubkey: this.warpFeeWallet, // 收款方公钥
41 | lamports: fee, // 转账的 lamports 数量
42 | }),
43 | ],
44 | }).compileToV0Message(); // 编译为 V0 消息
45 |
46 | const warpFeeTx = new VersionedTransaction(warpFeeMessage); // 创建版本化交易
47 | warpFeeTx.sign([payer]); // 签名交易
48 |
49 | // 发送请求到 Warp 交易执行 API
50 | const response = await axios.post<{ confirmed: boolean; signature: string, error?: string }>(
51 | 'https://tx.warp.id/transaction/execute', // API 地址
52 | {
53 | transactions: [bs58.encode(warpFeeTx.serialize()), bs58.encode(transaction.serialize())], // 发送序列化的交易
54 | latestBlockhash, // 最新区块哈希
55 | },
56 | {
57 | timeout: 100000, // 请求超时时间
58 | },
59 | );
60 |
61 | return response.data; // 返回响应数据
62 | } catch (error) {
63 | if (error instanceof AxiosError) {
64 | logger.trace({ error: error.response?.data }, '执行 Warp 交易失败'); // 记录错误信息
65 | }
66 | }
67 |
68 | return { confirmed: false }; // 返回未确认
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Bot汉化/bot Solana Sniper Main/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig to read more about this file */
4 |
5 | /* Projects */
6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12 |
13 | /* Language and Environment */
14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16 | // "jsx": "preserve", /* Specify what JSX code is generated. */
17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
26 |
27 | /* Modules */
28 | "module": "commonjs", /* Specify what module code is generated. */
29 | // "rootDir": "./", /* Specify the root folder within your source files. */
30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */
36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
42 | "resolveJsonModule": true, /* Enable importing .json files. */
43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
45 |
46 | /* JavaScript Support */
47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
50 |
51 | /* Emit */
52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */
54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
57 | // "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. */
58 | // "outDir": "./", /* Specify an output folder for all emitted files. */
59 | // "removeComments": true, /* Disable emitting comments. */
60 | // "noEmit": true, /* Disable emitting files from a compilation. */
61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
68 | // "newLine": "crlf", /* Set the newline character for emitting files. */
69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
75 |
76 | /* Interop Constraints */
77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
78 | // "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. */
79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
83 |
84 | /* Type Checking */
85 | "strict": true, /* Enable all strict type-checking options. */
86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
104 |
105 | /* Completeness */
106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/.gitignore:
--------------------------------------------------------------------------------
1 | **/node_modules
2 | .DS_Store
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/README.md:
--------------------------------------------------------------------------------
1 | # AxisBot Solana Spam Sniper
2 |
3 | ## 概述:
4 | 此项目是一个 Solana SPL 代币的狙击程序,旨在通过扫描 Solana 区块链上的交易,尽早在 Raydium 新流动性对的第一根价格蜡烛内完成代币交换(购买)。
5 |
6 | ## 程序工作原理:
7 | - 扫描 Solana 区块链,寻找“初始化市场”交易,并解码以获取所有必要的流动性池密钥和相关信息。
8 | - 在流动性池上线之前,不断发送和重试“交换”交易,最小化交易与流动性池创建之间的时间差。
9 | - 当发送有效交易后,开始跟踪用户的位置,扫描并解码链上流动性池信息以获取当前最准确的价格/百分比增益。
10 |
11 | ## 环境要求:
12 | 需要 npm 版本 18.17.0 或更低。
13 |
14 | ## 设置步骤:
15 | 按以下说明安装并运行程序(假设已安装 Node.js):
16 | 1. 创建一个 Solana 钱包,并获取公钥和私钥(推荐使用 Phantom 钱包)。
17 | 2. 获取 Solana RPC/WebSocket 连接,例如 `https://solana-mainnet.rpc.extrnode.com/5b667693-6518-4921-8ea1-4f65ff09c463` 和 `wss://solana-mainnet.rpc.extrnode.com/5b667693-6518-4921-8ea1-4f65ff09c463` 以进行测试。
18 | 3. 运行 `npm install` 来安装依赖项。
19 | 4. 在 `utils/config.js` 文件中,输入公钥、私钥及上述两个 RPC 连接。同时,设置每次交换使用的 SOL 数量。
20 |
21 | ## 运行脚本:
22 | 该项目包含两种不同的策略用于狙击新流动性对:
23 |
24 | ### **策略 #1:**
25 | - 第一种策略从创建流动性池的交易中获取所需的流动性池密钥。运行脚本使用 `node strategy1/start1.js`。由于 Solana 的某些 RPC 节点可能会丢弃交易,因此交易可能会失败多次后才成功。
26 | - **注意:** 此脚本较慢,必须等待“添加流动性”交易达到“已确认”状态才能获取池数据,这导致从池创建到交换交易之间约有 30 秒的延迟。
27 |
28 | ### **策略 #2:**
29 | - 第二种策略从“初始化市场”交易中获取流动性池密钥,该交易通常发生在流动性池上线前大约 2 分钟。这使得所有池密钥可以提前计算。该脚本每秒多次重试交换交易,允许在“添加流动性”交易的“处理中”状态发送交换交易,而非等待“已确认”,大大减少了流动性池创建与交换交易之间的时间差。运行此脚本使用 `node strategy2/start2.js`。
30 | - **注意:** 两个脚本都使用相同的交换/仓位管理系统,存放于 `./swap/swap1.js` 和 `/swap/swap2.js` 中。
31 |
32 | ### **附加说明:**
33 | - 程序启动后,只有在找到新的市场 ID/池时才会显示输出。
34 | - 关于“amm 账户所有者不匹配该程序 + 错误 0x1b”:此错误发生在程序向尚未有流动性的池发送交换交易时。交易的频繁发送是狙击策略的一部分,直到池子有流动性并成功进行交换,错误会持续出现。
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@openbook-dex/openbook": "^0.0.9",
4 | "@raydium-io/raydium-sdk": "^1.3.1-beta.46",
5 | "@solana/spl-token": "^0.3.11",
6 | "@solana/web3.js": "^1.87.6",
7 | "borsh": "^2.0.0",
8 | "bs64": "^0.1.0",
9 | "node": "^21.2.0"
10 | },
11 | "name": "solana",
12 | "version": "1.0.0",
13 | "main": "tx.js",
14 | "scripts": {
15 | "test": "echo \"Error: no test specified\" && exit 1"
16 | },
17 | "author": "",
18 | "license": "ISC",
19 | "description": ""
20 | }
21 |
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/strategy1/formatAmmKeysById.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | Object.defineProperty(exports, "__esModule", { value: true });
12 | exports.formatAmmKeysById = void 0;
13 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
14 | const web3_js_1 = require("@solana/web3.js");
15 | const config_1 = require("../utils/config.js");
16 | function formatAmmKeysById(id) {
17 | return __awaiter(this, void 0, void 0, function* () {
18 | const account = yield config_1.connection.getAccountInfo(new web3_js_1.PublicKey(id));
19 | if (account === null)
20 | throw Error(' get id info error ');
21 | const info = raydium_sdk_1.LIQUIDITY_STATE_LAYOUT_V4.decode(account.data);
22 | const marketId = info.marketId;
23 | const marketAccount = yield config_1.connection.getAccountInfo(marketId);
24 | if (marketAccount === null)
25 | throw Error(' get market info error');
26 | const marketInfo = raydium_sdk_1.MARKET_STATE_LAYOUT_V3.decode(marketAccount.data);
27 | const lpMint = info.lpMint;
28 | const lpMintAccount = yield config_1.connection.getAccountInfo(lpMint);
29 | if (lpMintAccount === null)
30 | throw Error(' get lp mint info error');
31 | const lpMintInfo = raydium_sdk_1.SPL_MINT_LAYOUT.decode(lpMintAccount.data);
32 | return {
33 | id,
34 | baseMint: info.baseMint.toString(),
35 | quoteMint: info.quoteMint.toString(),
36 | lpMint: info.lpMint.toString(),
37 | baseDecimals: info.baseDecimal.toNumber(),
38 | quoteDecimals: info.quoteDecimal.toNumber(),
39 | // lpDecimals: lpMintInfo.decimals,
40 | lpDecimals: info.baseDecimal.toNumber(),
41 | version: 4,
42 | programId: account.owner.toString(),
43 | authority: raydium_sdk_1.Liquidity.getAssociatedAuthority({ programId: account.owner }).publicKey.toString(),
44 | openOrders: info.openOrders.toString(),
45 | targetOrders: info.targetOrders.toString(),
46 | baseVault: info.baseVault.toString(),
47 | quoteVault: info.quoteVault.toString(),
48 | withdrawQueue: info.withdrawQueue.toString(),
49 | lpVault: info.lpVault.toString(),
50 | marketVersion: 3,
51 | marketProgramId: info.marketProgramId.toString(),
52 | marketId: info.marketId.toString(),
53 | marketAuthority: raydium_sdk_1.Market.getAssociatedAuthority({ programId: info.marketProgramId, marketId: info.marketId }).publicKey.toString(),
54 | marketBaseVault: marketInfo.baseVault.toString(),
55 | marketQuoteVault: marketInfo.quoteVault.toString(),
56 | marketBids: marketInfo.bids.toString(),
57 | marketAsks: marketInfo.asks.toString(),
58 | marketEventQueue: marketInfo.eventQueue.toString(),
59 | lookupTableAccount: web3_js_1.PublicKey.default.toString()
60 | };
61 | });
62 | }
63 | exports.formatAmmKeysById = formatAmmKeysById;
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/strategy1/start1.js:
--------------------------------------------------------------------------------
1 | const web3 = require('@solana/web3.js')
2 | const WebSocket = require('ws')
3 | const swap = require('./swap1.js')
4 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
5 | const config = require('../utils/config.js');
6 |
7 | const connection = config.connection;
8 | const ws = new WebSocket(config.websocketConnection)
9 | ws.onopen = () => {
10 | ws.send(
11 | JSON.stringify({
12 | jsonrpc: '2.0',
13 | id: 1,
14 | method: 'blockSubscribe',
15 | params: [{"mentionsAccountOrProgram": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"}, {"commitment": "confirmed", "maxSupportedTransactionVersion": 0, "encoding": "jsonParsed"}]
16 | })
17 | )
18 | }
19 |
20 | ws.on('message', (evt) => {
21 | try {
22 | const buffer = evt.toString('utf8');
23 | parseBlock(JSON.parse(buffer));
24 | return;
25 | } catch (e) {
26 | console.log(e)
27 | }
28 | })
29 |
30 | function isStatusError(status){
31 | if(status.hasOwnProperty('Err')){
32 | return true;
33 | }
34 | else if(status.hasOwnProperty('Ok')){
35 | return false;
36 | }
37 | }
38 |
39 | async function getTx(tx){
40 | return await connection.getTransaction(tx, {
41 | "commitment": "confirmed",
42 | "maxSupportedTransactionVersion": 0,
43 | "encoded": "jsonParsed"
44 | })
45 | }
46 |
47 | let swapped = false;
48 | function parseBlock(transaction){
49 | try{
50 | const tx = transaction.params.result.value.block.transactions;
51 | for(let i = 0; i < tx.length; i++){
52 | if(tx[i].meta.innerInstructions !== undefined && tx[i].meta.innerInstructions.length !== 0){
53 | if(tx[i].meta.innerInstructions[0].instructions.length === 32 && !isStatusError(tx[i].meta.status)){
54 | const signature = tx[i].transaction.signatures[0];
55 | console.log(tx[i].transaction.signatures);
56 | if(swapped === false){
57 | swapped = true;
58 | let now = new Date();
59 | let utcString = now.toUTCString();
60 | console.log(utcString);
61 | ws.close();
62 | }
63 | }
64 | }
65 | }
66 | } catch(error){
67 | console.log("searching...")
68 | }
69 | }
70 |
71 | async function getJsonPoolInfo(tx){
72 | // market account
73 | const marketAccount = await connection.getAccountInfo(new web3.PublicKey(tx.transaction.message.accountKeys[19].pubkey));
74 | const marketInfo = raydium_sdk_1.MARKET_STATE_LAYOUT_V3.decode(marketAccount.data);
75 | // get decimals
76 | const getTokenAccount = await connection.getParsedAccountInfo(new web3.PublicKey(tx.transaction.message.accountKeys[17].pubkey));
77 | const decimals = getTokenAccount.value.data.parsed.info.decimals;
78 | // create poolKeys object
79 | const keys = {
80 | id: tx.transaction.message.accountKeys[2].pubkey,
81 | baseMint: tx.transaction.message.accountKeys[17].pubkey,
82 | quoteMint: 'So11111111111111111111111111111111111111112',
83 | lpMint: tx.transaction.message.accountKeys[4].pubkey,
84 | baseDecimals: decimals,
85 | quoteDecimals: 9,
86 | lpDecimals: decimals,
87 | version: 4,
88 | programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',
89 | authority: '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1',
90 | openOrders: tx.transaction.message.accountKeys[3].pubkey,
91 | targetOrders: tx.transaction.message.accountKeys[7].pubkey,
92 | baseVault: tx.transaction.message.accountKeys[5].pubkey,
93 | quoteVault: tx.transaction.message.accountKeys[6].pubkey,
94 | withdrawQueue: '11111111111111111111111111111111',
95 | lpVault: '11111111111111111111111111111111',
96 | marketVersion: 3,
97 | marketProgramId: tx.transaction.message.accountKeys[22].pubkey,
98 | marketId: tx.transaction.message.accountKeys[19].pubkey,
99 | marketAuthority: raydium_sdk_1.Market.getAssociatedAuthority({ programId: new web3.PublicKey(tx.transaction.message.accountKeys[22].pubkey), marketId: new web3.PublicKey(tx.transaction.message.accountKeys[19].pubkey) }).publicKey.toString(),
100 | marketBaseVault: marketInfo.baseVault.toString(),
101 | marketQuoteVault: marketInfo.quoteVault.toString(),
102 | marketBids: marketInfo.bids.toString(),
103 | marketAsks: marketInfo.asks.toString(),
104 | marketEventQueue: marketInfo.eventQueue.toString(),
105 | lookupTableAccount: '11111111111111111111111111111111'
106 | }
107 | // convert poolKeys object to JSON
108 | const jsonPoolKeys = raydium_sdk_1.jsonInfo2PoolKeys(keys);
109 | swap.swap(jsonPoolKeys, tx.transaction.message.accountKeys[17].pubkey);
110 | }
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/strategy1/swap1.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | var __importDefault = (this && this.__importDefault) || function (mod) {
12 | return (mod && mod.__esModule) ? mod : { "default": mod };
13 | };
14 | Object.defineProperty(exports, "__esModule", { value: true });
15 | const assert_1 = __importDefault(require("assert"));
16 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
17 | const config_1 = require("../utils/config.js");
18 | const formatAmmKeysById_1 = require("./formatAmmKeysById.js");
19 | const util_1 = require("../utils/util.js");
20 | const { LAMPORTS_PER_SOL } = require("@solana/web3.js");
21 | const web3 = require("@solana/web3.js");
22 | const connection = config_1.connection;
23 | function swapOnlyAmm(input) {
24 | return __awaiter(this, void 0, void 0, function* () {
25 | const outputToken = new raydium_sdk_1.Token(raydium_sdk_1.TOKEN_PROGRAM_ID, new web3.PublicKey(input.tokenAddress), input.poolKeys.lpDecimals);
26 | const { innerTransactions } = yield raydium_sdk_1.Liquidity.makeSwapInstructionSimple({
27 | connection: config_1.connection,
28 | poolKeys: input.poolKeys,
29 | userKeys: {
30 | tokenAccounts: input.walletTokenAccounts,
31 | owner: input.wallet.publicKey,
32 | },
33 | amountIn: input.inputTokenAmount,
34 | amountOut: new raydium_sdk_1.TokenAmount(outputToken, 1),
35 | fixedSide: 'in',
36 | makeTxVersion: config_1.makeTxVersion,
37 | });
38 | return { txids: yield (0, util_1.buildAndSendTx)(innerTransactions) };
39 | });
40 | }
41 |
42 | const buyAmtSol = config_1.amtBuySol;
43 | function swap(poolKeys, tokenAddress) {
44 | return __awaiter(this, void 0, void 0, function* () {
45 | const ownerAddress = config_1.ownerAddress;
46 | const inputToken = new raydium_sdk_1.Token(raydium_sdk_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey('So11111111111111111111111111111111111111112'), 9, 'WSOL', 'WSOL'); // WSOL
47 | const inputTokenAmount = new raydium_sdk_1.TokenAmount(inputToken, LAMPORTS_PER_SOL * buyAmtSol);
48 | const slippage = new raydium_sdk_1.Percent(1, 100);
49 | const walletTokenAccounts = yield (0, util_1.getWalletTokenAccount)(config_1.connection, config_1.wallet.publicKey);
50 | swapOnlyAmm({
51 | poolKeys,
52 | tokenAddress,
53 | inputTokenAmount,
54 | slippage,
55 | walletTokenAccounts,
56 | wallet: config_1.wallet,
57 | }).then(({ txids }) => {
58 | /** continue with txids */
59 | console.log('txids', txids);
60 | if(txids.length === 1){
61 | monitorTokenSell(txids[0], tokenAddress, ownerAddress, poolKeys.baseVault.toString(), poolKeys.quoteVault.toString());
62 | }
63 | }).catch(error => {
64 | console.log(error);
65 | swap(poolKeys, tokenAddress);
66 | })
67 | });
68 | }
69 | exports.swap = swap
70 |
71 | async function getTx(tx){
72 | return await connection.getTransaction(tx, {
73 | maxSupportedTransactionVersion: 0,
74 | commitment: "confirmed"
75 | })
76 | }
77 |
78 | async function getBalances(tx, tokenAddress, ownerAddress){
79 | let validTx = await getTx(tx);
80 | while(validTx === null){
81 | validTx = await getTx(tx);
82 | if(validTx !== null){
83 | for(const account of validTx.meta.postTokenBalances){
84 | if(account.mint === tokenAddress && account.owner === ownerAddress){
85 | return account.uiTokenAmount.uiAmount;
86 | }
87 | }
88 | }
89 | }
90 | }
91 |
92 | async function getTokenPriceInSol(baseVault, quoteVault){
93 | const baseVaultAccount = await connection.getTokenAccountBalance(new web3.PublicKey(baseVault));
94 | const quoteVaultAccount = await connection.getTokenAccountBalance(new web3.PublicKey(quoteVault));
95 | const baseVaultAccountAmount = baseVaultAccount.value.uiAmount;
96 | const quoteVaultAccountAmount = quoteVaultAccount.value.uiAmount;
97 | return (quoteVaultAccountAmount / baseVaultAccountAmount);
98 | }
99 |
100 | async function monitorTokenSell(tx, tokenAddress, ownerAddress, baseVault, quoteVault){
101 | const tokenBalance = await getBalances(tx, tokenAddress, ownerAddress);
102 | const buyPrice = (buyAmtSol / tokenBalance);
103 | monitorToken(buyPrice, baseVault, quoteVault);
104 | }
105 |
106 | async function monitorToken(buyPrice, baseVault, quoteVault){
107 | let interval = setInterval(async () => {
108 | const currentPrice = await getTokenPriceInSol(baseVault, quoteVault);
109 | console.log("buy price: " + buyPrice + " current price: " + currentPrice);
110 | const percentIncrease = ((buyPrice - currentPrice) / buyPrice) * 100;
111 | console.log("percent increase: " + percentIncrease);
112 | }, 500)
113 | }
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/strategy2/derivePoolKeys.js:
--------------------------------------------------------------------------------
1 | const web3 = require('@solana/web3.js');
2 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
3 | const spl = require('@solana/spl-token');
4 | const {Market} = require('@openbook-dex/openbook');
5 | const config = require('../utils/config.js');
6 |
7 | const connection = config.connection;
8 |
9 | const wsolAddress = 'So11111111111111111111111111111111111111112';
10 | const openbookProgramId = new web3.PublicKey('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX');
11 |
12 | const rayProgram = new web3.PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8');
13 | const myAccount = new web3.PublicKey(config.ownerAddress);
14 |
15 | async function derivePoolKeys(id){
16 | console.log(id);
17 | const marketId = new web3.PublicKey(id);
18 |
19 | const marketInfo = await getMarketInfo(marketId);
20 | const marketDeco = await getDecodedData(marketInfo);
21 |
22 | const baseMint = marketDeco.baseMint;
23 | const baseMintData = await getMintData(baseMint);
24 | const baseDecimals = await getDecimals(baseMintData);
25 | const ownerBaseAta = await getOwnerAta(baseMint, myAccount);
26 |
27 | const quoteMint = marketDeco.quoteMint;
28 | const quoteMintData = await getMintData(quoteMint);
29 | const quoteDecimals = await getDecimals(quoteMintData);
30 | const ownerQuoteAta = await getOwnerAta(quoteMint, myAccount);
31 |
32 | const authority = (raydium_sdk_1.findProgramAddress([Buffer.from([97, 109, 109, 32, 97, 117, 116, 104, 111, 114, 105, 116, 121])], rayProgram))['publicKey'];
33 | // const marketAuthority = getVaultSigner(marketId, marketDeco);
34 |
35 | const poolKeys = {
36 | id: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('amm_associated_seed', 'utf-8')], rayProgram)['publicKey'],
37 | baseMint: baseMint,
38 | quoteMint, quoteMint,
39 | lpMint: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('lp_mint_associated_seed', 'utf-8')], rayProgram)['publicKey'],
40 | baseDecimals: baseDecimals,
41 | quoteDecimals: quoteDecimals,
42 | lpDecimals: baseDecimals,
43 | version: 4,
44 | programId: rayProgram,
45 | authority: authority,
46 | openOrders: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('open_order_associated_seed', 'utf-8')], rayProgram)['publicKey'],
47 | targetOrders: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('target_associated_seed', 'utf-8')], rayProgram)['publicKey'],
48 | baseVault: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('coin_vault_associated_seed', 'utf-8')], rayProgram)['publicKey'],
49 | quoteVault: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('pc_vault_associated_seed', 'utf-8')], rayProgram)['publicKey'],
50 | // withdrawQueue: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('withdraw_associated_seed', 'utf-8')], rayProgram)['publicKey'],
51 | // lpVault: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('temp_lp_token_associated_seed', 'utf-8')], rayProgram)['publicKey'],
52 | withdrawQueue: new web3.PublicKey('11111111111111111111111111111111'),
53 | lpVault: new web3.PublicKey('11111111111111111111111111111111'),
54 | marketVersion: 3,
55 | marketProgramId: openbookProgramId,
56 | // marketProgramId: new web3.PublicKey('9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin'),
57 | marketId: marketId,
58 | marketAuthority: raydium_sdk_1.Market.getAssociatedAuthority({ programId: new web3.PublicKey('9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin'), marketId: marketId }).publicKey,
59 | marketBaseVault: marketDeco.baseVault,
60 | marketQuoteVault: marketDeco.quoteVault,
61 | marketBids: marketDeco.bids,
62 | marketAsks: marketDeco.asks,
63 | marketEventQueue: marketDeco.eventQueue,
64 | // ownerBaseAta: ownerBaseAta,
65 | // ownerQuoteAta: ownerQuoteAta,
66 | // marketAuthority: marketAuthority,
67 | // coinVault: raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), marketId.toBuffer(), Buffer.from('pc_vault_associated_seed', 'utf-8')], rayProgram)['publicKey'],
68 | lookupTableAccount: web3.PublicKey.default
69 | };
70 | return poolKeys;
71 | }
72 | exports.derivePoolKeys = derivePoolKeys;
73 |
74 | async function getMarketInfo(marketId){
75 | const marketInfo = await connection.getAccountInfo(marketId);
76 | return marketInfo;
77 | }
78 |
79 | async function getDecodedData(marketInfo){
80 | return await Market.getLayout(openbookProgramId).decode(marketInfo.data);
81 | }
82 |
83 | async function getMintData(mint){
84 | return await connection.getAccountInfo(mint);
85 | }
86 |
87 | async function getDecimals(mintData){
88 | return raydium_sdk_1.SPL_MINT_LAYOUT.decode(mintData.data).decimals;
89 | }
90 |
91 | async function getOwnerAta(mint, publicKey){
92 | const foundAta = web3.PublicKey.findProgramAddressSync([publicKey.toBuffer(), spl.TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()], spl.ASSOCIATED_TOKEN_PROGRAM_ID)[0];
93 | return foundAta;
94 | }
95 |
96 | function getVaultSigner(marketId, marketDeco){
97 | const seeds = [marketId.toBuffer()];
98 | const seedsWithNonce = seeds.concat(Buffer.from([Number(marketDeco.vaultSignerNonce.toString())]), Buffer.alloc(7));
99 | return web3.PublicKey.createProgramAddressSync(seedsWithNonce, openbookProgramId);
100 | }
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/strategy2/start2.js:
--------------------------------------------------------------------------------
1 | const web3 = require('@solana/web3.js');
2 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
3 | const WebSocket = require('ws');
4 | const derivePoolKeys = require('./derivePoolKeys.js');
5 | const swap = require('./swap2.js');
6 | const config = require('../utils/config.js');
7 |
8 | const connection = config.connection;
9 |
10 | const ws = new WebSocket(config.websocketConnection)
11 | ws.onopen = () => {
12 | ws.send(
13 | JSON.stringify({
14 | jsonrpc: '2.0',
15 | id: 1,
16 | method: 'blockSubscribe',
17 | params: [{"mentionsAccountOrProgram": "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX"}, {"commitment": "confirmed", "maxSupportedTransactionVersion": 0, "encoding": "jsonParsed"}]
18 | })
19 | )
20 | }
21 |
22 | ws.on('message', (evt) => {
23 | try {
24 | const buffer = evt.toString('utf8');
25 | parseTxs(JSON.parse(buffer));
26 | return;
27 | } catch (e) {
28 | console.log(e)
29 | }
30 | })
31 |
32 | function parseTxs(txsFromBlock){
33 | if(txsFromBlock.params === undefined){
34 | return;
35 | }
36 | const allTx = txsFromBlock.params.result.value.block.transactions;
37 | for(const tx of allTx){
38 | if(parseLogs(tx.meta.logMessages) && tx.transaction.message.accountKeys.length === 13 && tx.transaction.message.instructions.length === 6){
39 | ws.close();
40 | console.log(tx.transaction.signatures)
41 | parseAccountKeys(tx.transaction.message.accountKeys, tx.transaction.signatures);
42 | }
43 | }
44 | }
45 |
46 | function parseLogs(logs){
47 | let invoke = 0;
48 | let consumed = 0;
49 | let success = 0;
50 | for(const log of logs){
51 | if(log.includes("Program srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX invoke")){
52 | invoke += 1;
53 | }
54 | if(log.includes("Program srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX consumed")){
55 | consumed += 1;
56 | }
57 | if(log.includes("Program srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX success")){
58 | success += 1;
59 | }
60 | }
61 | if(invoke === 1 && consumed === 1 && success === 1){
62 | return true;
63 | } else{
64 | return false;
65 | }
66 | }
67 |
68 | async function parseAccountKeys(keys, signature){
69 | let marketId = null;
70 | for(const key of keys){
71 | console.log(key);
72 | const keyData = await connection.getAccountInfo(new web3.PublicKey(key.pubkey));
73 | if(keyData !== null && keyData.data.length === 388){
74 | marketId = key.pubkey;
75 | }
76 | }
77 | if(marketId === null){
78 | parseAccountKeys(keys);
79 | } else{
80 | const poolKeys = await derivePoolKeys.derivePoolKeys(marketId);
81 | swap.swap(poolKeys, signature);
82 | }
83 | }
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/strategy2/swap2.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | var __importDefault = (this && this.__importDefault) || function (mod) {
12 | return (mod && mod.__esModule) ? mod : { "default": mod };
13 | };
14 | Object.defineProperty(exports, "__esModule", { value: true });
15 | const assert_1 = __importDefault(require("assert"));
16 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
17 | const config_1 = require("../utils/config.js");
18 | const util_1 = require("../utils/util.js");
19 | const { LAMPORTS_PER_SOL } = require("@solana/web3.js");
20 | const web3 = require("@solana/web3.js");
21 | const connection = config_1.connection;
22 | function swapOnlyAmm(input) {
23 | return __awaiter(this, void 0, void 0, function* () {
24 | const outputToken = new raydium_sdk_1.Token(raydium_sdk_1.TOKEN_PROGRAM_ID, new web3.PublicKey(input.tokenAddress), input.poolKeys.lpDecimals);
25 | const { innerTransactions } = yield raydium_sdk_1.Liquidity.makeSwapInstructionSimple({
26 | connection: config_1.connection,
27 | poolKeys: input.poolKeys,
28 | userKeys: {
29 | tokenAccounts: input.walletTokenAccounts,
30 | owner: input.wallet.publicKey,
31 | },
32 | amountIn: input.inputTokenAmount,
33 | amountOut: new raydium_sdk_1.TokenAmount(outputToken, 1),
34 | fixedSide: 'in',
35 | makeTxVersion: config_1.makeTxVersion,
36 | });
37 | return { txids: yield (0, util_1.buildAndSendTx)(innerTransactions) };
38 | });
39 | }
40 |
41 | const buyAmtSol = config_1.amtBuySol;
42 | function swap(poolKeys, signature) {
43 | return __awaiter(this, void 0, void 0, function* () {
44 | const ownerAddress = config_1.ownerAddress;
45 | const inputToken = new raydium_sdk_1.Token(raydium_sdk_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey('So11111111111111111111111111111111111111112'), 9, 'WSOL', 'WSOL'); // WSOL
46 | const inputTokenAmount = new raydium_sdk_1.TokenAmount(inputToken, LAMPORTS_PER_SOL * buyAmtSol);
47 | const slippage = new raydium_sdk_1.Percent(1, 100);
48 | const walletTokenAccounts = yield (0, util_1.getWalletTokenAccount)(config_1.connection, config_1.wallet.publicKey);
49 | swapOnlyAmm({
50 | poolKeys,
51 | tokenAddress: poolKeys.baseMint.toString(),
52 | inputTokenAmount,
53 | slippage,
54 | walletTokenAccounts,
55 | wallet: config_1.wallet,
56 | }).then(({ txids }) => {
57 | /** continue with txids */
58 | console.log('txids', txids);
59 | if(txids.length === 1){
60 | monitorTokenSell(txids[0], poolKeys.baseMint.toString(), ownerAddress, poolKeys.baseVault.toString(), poolKeys.quoteVault.toString());
61 | }
62 | }).catch(error => {
63 | console.log(signature);
64 | console.log(error);
65 | swap(poolKeys, poolKeys.baseMint.toString());
66 | })
67 | });
68 | }
69 | exports.swap = swap
70 |
71 | async function getTx(tx){
72 | return await connection.getTransaction(tx, {
73 | maxSupportedTransactionVersion: 0,
74 | commitment: "confirmed"
75 | })
76 | }
77 |
78 | async function getBalances(tx, tokenAddress, ownerAddress){
79 | let validTx = await getTx(tx);
80 | while(validTx === null){
81 | validTx = await getTx(tx);
82 | if(validTx !== null){
83 | for(const account of validTx.meta.postTokenBalances){
84 | if(account.mint === tokenAddress && account.owner === ownerAddress){
85 | return account.uiTokenAmount.uiAmount;
86 | }
87 | }
88 | }
89 | }
90 | }
91 |
92 | async function getTokenPriceInSol(baseVault, quoteVault){
93 | const baseVaultAccount = await connection.getTokenAccountBalance(new web3.PublicKey(baseVault));
94 | const quoteVaultAccount = await connection.getTokenAccountBalance(new web3.PublicKey(quoteVault));
95 | const baseVaultAccountAmount = baseVaultAccount.value.uiAmount;
96 | const quoteVaultAccountAmount = quoteVaultAccount.value.uiAmount;
97 | return (quoteVaultAccountAmount / baseVaultAccountAmount);
98 | }
99 |
100 | async function monitorTokenSell(tx, tokenAddress, ownerAddress, baseVault, quoteVault){
101 | const tokenBalance = await getBalances(tx, tokenAddress, ownerAddress);
102 | const buyPrice = (buyAmtSol / tokenBalance);
103 | monitorToken(buyPrice, baseVault, quoteVault);
104 | }
105 |
106 | async function monitorToken(buyPrice, baseVault, quoteVault){
107 | let interval = setInterval(async () => {
108 | const currentPrice = await getTokenPriceInSol(baseVault, quoteVault);
109 | console.log("buy price: " + buyPrice + " current price: " + currentPrice);
110 | const percentIncrease = ((buyPrice - currentPrice) / buyPrice) * 100;
111 | console.log("percent increase: " + percentIncrease);
112 | }, 500)
113 | }
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/utils/config.js:
--------------------------------------------------------------------------------
1 | const bs58 = require('bs58');
2 | "use strict";
3 | Object.defineProperty(exports, "__esModule", { value: true });
4 | exports.DEFAULT_TOKEN = exports.addLookupTableInfo = exports.makeTxVersion = exports.RAYDIUM_MAINNET_API = exports.ENDPOINT = exports.PROGRAMIDS = exports.connection = exports.wallet = exports.rpcToken = exports.rpcUrl = void 0;
5 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
6 | const web3_js_1 = require("@solana/web3.js");
7 | exports.ownerAddress = '';
8 | exports.wallet = web3_js_1.Keypair.fromSecretKey(bs58.decode(''));
9 | exports.connection = new web3_js_1.Connection('');
10 | exports.websocketConnection = '';
11 | exports.amtBuySol = '';
12 | exports.PROGRAMIDS = raydium_sdk_1.MAINNET_PROGRAM_ID;
13 | exports.ENDPOINT = raydium_sdk_1.ENDPOINT;
14 | exports.RAYDIUM_MAINNET_API = raydium_sdk_1.RAYDIUM_MAINNET;
15 | exports.makeTxVersion = raydium_sdk_1.TxVersion.V0; // LEGACY
16 | exports.addLookupTableInfo = raydium_sdk_1.LOOKUP_TABLE_CACHE;
17 |
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/utils/decoderaylog.js:
--------------------------------------------------------------------------------
1 | const web3 = require('@solana/web3.js');
2 | const WebSocket = require('ws');
3 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
4 | const bs64 = require('bs64');
5 | const config = require('./config');
6 |
7 | const connection = config.connection;
8 |
9 | const feeAddress = '7YttLkHDoNj9wyDur5pM1ejNaAvT9X4eqaYcHQqtj2G5'
10 | const rayProgram = new web3.PublicKey('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8');
11 |
12 | const ws = new WebSocket(config.websocketConnection)
13 | ws.onopen = () => {
14 | ws.send(
15 | JSON.stringify({
16 | jsonrpc: '2.0',
17 | id: 1,
18 | method: 'logsSubscribe',
19 | params: [{"mentions": [feeAddress]}, {"commitment": "processed"}]
20 | })
21 | )
22 | }
23 |
24 | ws.on('message', (evt) => {
25 | try {
26 | const buffer = evt.toString('utf8');
27 | parseLogs(JSON.parse(buffer));
28 | return;
29 | } catch (e) {
30 | console.log(e)
31 | }
32 | })
33 |
34 | function parseLogs(buffer){
35 | if(buffer.params === undefined){
36 | return;
37 | }
38 | let now = new Date();
39 | let utcString = now.toUTCString();
40 | console.log(utcString);
41 | const allLogs = buffer.params.result.value.logs;
42 | for(const log of allLogs){
43 | if(log.includes("ray_log")){
44 | const rayLogSplit = log.split(" ");
45 | const rayLog = rayLogSplit[3];
46 | const logData = Buffer.from(rayLog, "base64");
47 | const market = new web3.PublicKey(logData.subarray(75 - 32), 75);
48 | console.log(market)
49 | const pool = raydium_sdk_1.findProgramAddress([rayProgram.toBuffer(), market.toBuffer(), Buffer.from('amm_associated_seed', 'utf-8')], rayProgram)['publicKey'];
50 | console.log(pool);
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/Bot汉化/bot Spam Sniper/utils/util.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | Object.defineProperty(exports, "__esModule", { value: true });
12 | exports.sleepTime = exports.getATAAddress = exports.buildAndSendTx = exports.getWalletTokenAccount = exports.sendTx = void 0;
13 | const raydium_sdk_1 = require("@raydium-io/raydium-sdk");
14 | const web3_js_1 = require("@solana/web3.js");
15 | const config_1 = require("./config");
16 | function sendTx(connection, payer, txs, options) {
17 | return __awaiter(this, void 0, void 0, function* () {
18 | const txids = [];
19 | for (const iTx of txs) {
20 | if (iTx instanceof web3_js_1.VersionedTransaction) {
21 | iTx.sign([payer]);
22 | txids.push(yield connection.sendTransaction(iTx, options));
23 | }
24 | else {
25 | txids.push(yield connection.sendTransaction(iTx, [payer], options));
26 | }
27 | }
28 | return txids;
29 | });
30 | }
31 | exports.sendTx = sendTx;
32 | function getWalletTokenAccount(connection, wallet) {
33 | return __awaiter(this, void 0, void 0, function* () {
34 | const walletTokenAccount = yield connection.getTokenAccountsByOwner(wallet, {
35 | programId: raydium_sdk_1.TOKEN_PROGRAM_ID,
36 | });
37 | return walletTokenAccount.value.map((i) => ({
38 | pubkey: i.pubkey,
39 | programId: i.account.owner,
40 | accountInfo: raydium_sdk_1.SPL_ACCOUNT_LAYOUT.decode(i.account.data),
41 | }));
42 | });
43 | }
44 | exports.getWalletTokenAccount = getWalletTokenAccount;
45 | function buildAndSendTx(innerSimpleV0Transaction, options) {
46 | return __awaiter(this, void 0, void 0, function* () {
47 | const willSendTx = yield (0, raydium_sdk_1.buildSimpleTransaction)({
48 | connection: config_1.connection,
49 | makeTxVersion: config_1.makeTxVersion,
50 | payer: config_1.wallet.publicKey,
51 | innerTransactions: innerSimpleV0Transaction,
52 | addLookupTableInfo: config_1.addLookupTableInfo,
53 | });
54 | return yield sendTx(config_1.connection, config_1.wallet, willSendTx, options);
55 | });
56 | }
57 | exports.buildAndSendTx = buildAndSendTx;
58 | function getATAAddress(programId, owner, mint) {
59 | const { publicKey, nonce } = (0, raydium_sdk_1.findProgramAddress)([owner.toBuffer(), programId.toBuffer(), mint.toBuffer()], new web3_js_1.PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"));
60 | return { publicKey, nonce };
61 | }
62 | exports.getATAAddress = getATAAddress;
63 | function sleepTime(ms) {
64 | return __awaiter(this, void 0, void 0, function* () {
65 | console.log((new Date()).toLocaleString(), 'sleepTime', ms);
66 | return new Promise(resolve => setTimeout(resolve, ms));
67 | });
68 | }
69 | exports.sleepTime = sleepTime;
70 | //# sourceMappingURL=util.js.map
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 123
2 |
--------------------------------------------------------------------------------