@clonegod/ttd-sol-common 2.0.69 → 2.0.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,5 +2,4 @@ export * from './tx_result_check';
2
2
  export * from './tx_result_parse';
3
3
  export * from './tx_builder';
4
4
  export * from './send';
5
- export * from './jito_tip_wallets';
6
5
  export * from './sol_gas_cache';
@@ -18,5 +18,4 @@ __exportStar(require("./tx_result_check"), exports);
18
18
  __exportStar(require("./tx_result_parse"), exports);
19
19
  __exportStar(require("./tx_builder"), exports);
20
20
  __exportStar(require("./send"), exports);
21
- __exportStar(require("./jito_tip_wallets"), exports);
22
21
  __exportStar(require("./sol_gas_cache"), exports);
@@ -3,5 +3,4 @@ import { TradeContext } from '@clonegod/ttd-core/dist';
3
3
  export declare class TransactionSender {
4
4
  constructor();
5
5
  sendTransaction(context: TradeContext, mainTx: Transaction | VersionedTransaction, swqos_only?: boolean): Promise<string>;
6
- sendBundle(context: TradeContext, mainTx: Transaction | VersionedTransaction, tipTx: Transaction | VersionedTransaction, use_multi_ips?: boolean): Promise<string>;
7
6
  }
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TransactionSender = void 0;
4
4
  const web3_js_1 = require("@solana/web3.js");
5
5
  const helius_1 = require("./helius");
6
- const jito_1 = require("./jito");
7
6
  const common_1 = require("../../common");
8
7
  const sol_gas_cache_1 = require("../sol_gas_cache");
9
8
  class TransactionSender {
@@ -15,18 +14,6 @@ class TransactionSender {
15
14
  const singedTxBase64 = serializeTransactionBase64(mainTx);
16
15
  return await (0, helius_1.sendTxWithHelius)(singedTxBase64, swqos_only);
17
16
  }
18
- async sendBundle(context, mainTx, tipTx, use_multi_ips = false) {
19
- const mainTxHash = (0, common_1.getSignature)(mainTx);
20
- set_transaciton_gas_cost(mainTxHash, context);
21
- const mainTxBase64 = serializeTransactionBase64(mainTx);
22
- const tipTxBase64 = serializeTransactionBase64(tipTx);
23
- if (use_multi_ips) {
24
- return await (0, jito_1.sendBundleWithJitoMultiIps)(mainTxHash, mainTxBase64, tipTxBase64);
25
- }
26
- else {
27
- return await (0, jito_1.sendBundleWithJito)(mainTxBase64, tipTxBase64);
28
- }
29
- }
30
17
  }
31
18
  exports.TransactionSender = TransactionSender;
32
19
  function serializeTransactionBase64(tx) {
@@ -1,14 +1,12 @@
1
1
  import { TradeContext } from "@clonegod/ttd-core/dist";
2
2
  import { Connection, Keypair, Transaction, TransactionInstruction } from "@solana/web3.js";
3
3
  import { SolanaTradeAppConfig } from "../appconfig/SolanaTradeAppConfig";
4
- import { JitoTipWalletManager } from "./jito_tip_wallets";
5
4
  export declare class SolTransactionBuilder {
6
5
  appConfig: SolanaTradeAppConfig;
7
6
  connection: Connection;
8
7
  keypair: Keypair;
9
8
  recentBlockhash: string;
10
9
  recentBlockheight: number;
11
- jitoTipWalletManager: JitoTipWalletManager;
12
10
  constructor(appConfig: SolanaTradeAppConfig);
13
11
  init(): Promise<void>;
14
12
  private handleBlockUpdateEvent;
@@ -16,5 +14,4 @@ export declare class SolTransactionBuilder {
16
14
  private createComputeUnitLimitWithJitoDontFront;
17
15
  private getPostInstructions;
18
16
  buildTransactionForSwap(context: TradeContext, swapInstructions: TransactionInstruction[]): Transaction;
19
- buildTransactionForTipJito(context: TradeContext): Transaction;
20
17
  }
@@ -5,8 +5,6 @@ const dist_1 = require("@clonegod/ttd-core/dist");
5
5
  const web3_js_1 = require("@solana/web3.js");
6
6
  const common_1 = require("../common");
7
7
  const helius_1 = require("./send/helius");
8
- const jito_1 = require("./send/jito");
9
- const jito_tip_wallets_1 = require("./jito_tip_wallets");
10
8
  const jitodontfrontAccounts = [
11
9
  'jitodontfront111111111111111111111111111111',
12
10
  'jitodontfront111111111111111111111111111123',
@@ -52,7 +50,6 @@ class SolTransactionBuilder {
52
50
  this.appConfig = appConfig;
53
51
  this.connection = appConfig.connection;
54
52
  this.keypair = appConfig.keypair;
55
- this.jitoTipWalletManager = new jito_tip_wallets_1.JitoTipWalletManager();
56
53
  this.init();
57
54
  }
58
55
  async init() {
@@ -99,51 +96,22 @@ class SolTransactionBuilder {
99
96
  swapTx.recentBlockhash = this.recentBlockhash;
100
97
  swapTx.lastValidBlockHeight = this.recentBlockheight + max_block_offset;
101
98
  swapTx.feePayer = this.keypair.publicKey;
102
- const { sol_bundle_only, sol_tip_fee } = context.trade_runtime.settings.strategy;
103
- if (!sol_bundle_only) {
104
- let tip_lamports = sol_tip_fee;
105
- if (tip_lamports < 5000) {
106
- tip_lamports = 5000;
107
- }
108
- if (tip_lamports > 300000) {
109
- tip_lamports = 300000;
110
- }
111
- let tip_instruction = web3_js_1.SystemProgram.transfer({
112
- fromPubkey: this.keypair.publicKey,
113
- toPubkey: new web3_js_1.PublicKey(helius_1.HELIUS_TIP_ACCOUNTS[Math.floor(Math.random() * helius_1.HELIUS_TIP_ACCOUNTS.length)]),
114
- lamports: tip_lamports,
115
- });
116
- swapTx.instructions.push(tip_instruction);
117
- }
118
- swapTx.sign(this.keypair);
119
- return swapTx;
120
- }
121
- buildTransactionForTipJito(context) {
122
- const groupId = context.trade_runtime.group.id;
123
- const max_block_offset = context.trade_runtime.settings.strategy.max_block_offset;
124
- let tipPayer = this.jitoTipWalletManager.getNextWallet(groupId);
125
- if (!tipPayer) {
126
- tipPayer = this.keypair;
127
- }
128
- let tipAccount = (0, jito_1.getJitoTipAccount)();
129
- let tip_lamports = context.trade_runtime.settings.strategy.sol_tip_fee;
99
+ const { sol_tip_fee } = context.trade_runtime.settings.strategy;
100
+ let tip_lamports = sol_tip_fee;
130
101
  if (tip_lamports < 5000) {
131
102
  tip_lamports = 5000;
132
103
  }
133
- if (tip_lamports > 300000) {
134
- tip_lamports = 300000;
104
+ if (tip_lamports > 1000000) {
105
+ tip_lamports = 1000000;
135
106
  }
136
- const jitoTipTx = new web3_js_1.Transaction();
137
- jitoTipTx.add(web3_js_1.SystemProgram.transfer({
138
- fromPubkey: tipPayer.publicKey,
139
- toPubkey: new web3_js_1.PublicKey(tipAccount),
107
+ let tip_instruction = web3_js_1.SystemProgram.transfer({
108
+ fromPubkey: this.keypair.publicKey,
109
+ toPubkey: new web3_js_1.PublicKey(helius_1.HELIUS_TIP_ACCOUNTS[Math.floor(Math.random() * helius_1.HELIUS_TIP_ACCOUNTS.length)]),
140
110
  lamports: tip_lamports,
141
- }));
142
- jitoTipTx.recentBlockhash = this.recentBlockhash;
143
- jitoTipTx.lastValidBlockHeight = this.recentBlockheight + max_block_offset;
144
- jitoTipTx.feePayer = tipPayer.publicKey;
145
- jitoTipTx.sign(tipPayer);
146
- return jitoTipTx;
111
+ });
112
+ swapTx.instructions.push(tip_instruction);
113
+ swapTx.sign(this.keypair);
114
+ return swapTx;
147
115
  }
148
116
  }
149
117
  exports.SolTransactionBuilder = SolTransactionBuilder;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-sol-common",
3
- "version": "2.0.69",
3
+ "version": "2.0.71",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,7 +13,7 @@
13
13
  "push": "npm run build && npm publish"
14
14
  },
15
15
  "dependencies": {
16
- "@clonegod/ttd-core": "3.1.84",
16
+ "@clonegod/ttd-core": "3.1.86",
17
17
  "@solana/web3.js": "1.91.6",
18
18
  "rpc-websockets": "7.10.0",
19
19
  "axios": "^1.2.3",
@@ -2,6 +2,5 @@ export * from './tx_result_check'
2
2
  export * from './tx_result_parse'
3
3
  export * from './tx_builder'
4
4
  export * from './send'
5
- export * from './jito_tip_wallets'
6
5
  export * from './sol_gas_cache'
7
6
 
@@ -1,6 +1,5 @@
1
1
  import { Transaction, VersionedTransaction } from '@solana/web3.js';
2
2
  import { sendTxWithHelius } from './helius';
3
- import { sendBundleWithJito, sendBundleWithJitoMultiIps } from './jito';
4
3
  import { getSignature } from '../../common';
5
4
  import { TradeContext } from '@clonegod/ttd-core/dist';
6
5
  import { set_sol_gas_fee } from '../sol_gas_cache';
@@ -31,30 +30,6 @@ export class TransactionSender {
31
30
  return await sendTxWithHelius(singedTxBase64, swqos_only)
32
31
  }
33
32
 
34
- /**
35
- * 使用Jito Bundle 发送交易
36
- * - use_multi_ips=true, 使用多台服务器向jito提交交易(缓解jito的限流)
37
- * - use_multi_ips=false, 本地直接向jito提交交易
38
- *
39
- * @param mainTx 主交易
40
- * @param tipTx 小费交易
41
- * @param use_multi_ips true:多节点;false: 单节点
42
- * @returns bundleId
43
- */
44
- async sendBundle(context:TradeContext, mainTx: Transaction | VersionedTransaction, tipTx: Transaction | VersionedTransaction, use_multi_ips: boolean=false): Promise<string> {
45
- const mainTxHash = getSignature(mainTx)
46
- set_transaciton_gas_cost(mainTxHash, context)
47
-
48
- const mainTxBase64 = serializeTransactionBase64(mainTx)
49
- const tipTxBase64 = serializeTransactionBase64(tipTx)
50
-
51
- if(use_multi_ips) {
52
- return await sendBundleWithJitoMultiIps(mainTxHash, mainTxBase64, tipTxBase64)
53
- } else {
54
- return await sendBundleWithJito(mainTxBase64, tipTxBase64)
55
- }
56
- }
57
-
58
33
  }
59
34
 
60
35
 
@@ -4,8 +4,6 @@ import { LAMPORTS_PER_MICRO_LAMPORTS } from "../common";
4
4
  import { SolanaBlockMetaUpdateEvent } from "../types";
5
5
  import { SolanaTradeAppConfig } from "../appconfig/SolanaTradeAppConfig";
6
6
  import { HELIUS_TIP_ACCOUNTS } from "./send/helius";
7
- import { getJitoTipAccount } from "./send/jito";
8
- import { JitoTipWalletManager } from "./jito_tip_wallets";
9
7
 
10
8
  /**
11
9
  * Jito Sandwich Mitigation: jitodontfront 账户
@@ -71,13 +69,10 @@ export class SolTransactionBuilder {
71
69
  recentBlockhash: string
72
70
  recentBlockheight: number
73
71
 
74
- jitoTipWalletManager: JitoTipWalletManager
75
-
76
72
  constructor(appConfig: SolanaTradeAppConfig) {
77
73
  this.appConfig = appConfig
78
74
  this.connection = appConfig.connection
79
75
  this.keypair = appConfig.keypair
80
- this.jitoTipWalletManager = new JitoTipWalletManager()
81
76
  this.init()
82
77
  }
83
78
 
@@ -175,74 +170,29 @@ export class SolTransactionBuilder {
175
170
  swapTx.lastValidBlockHeight = this.recentBlockheight + max_block_offset
176
171
  swapTx.feePayer = this.keypair.publicKey
177
172
 
178
- const { sol_bundle_only, sol_tip_fee } = context.trade_runtime.settings.strategy
179
-
180
- // sol_bundle_only = false, 使用 Helius Sender
181
- // sol_bundle_only = true, 使用 Jito Bundle - 不需要给Helius小费
182
- if (!sol_bundle_only) {
183
- // 使用 Helius Sender:
184
- // 1、swqos_only: 至少 5000 lamports 小费
185
- // -> transaction must send a tip of at least 5000 lamports to one of the following Helius wallets: [xxx, ...]
186
- // 2、swqos + jito: 至少 0.0002 SOL 小费 -> lamports = 0.0002 * LAMPORTS_PER_SOL
187
- // -> Requires minimum 0.0002 SOL tip.
188
- let tip_lamports = sol_tip_fee
189
- if (tip_lamports < 5000) {
190
- tip_lamports = 5000
191
- }
192
- if (tip_lamports > 300000) {
193
- tip_lamports = 300000
194
- }
195
- let tip_instruction = SystemProgram.transfer({
196
- fromPubkey: this.keypair.publicKey,
197
- toPubkey: new PublicKey(HELIUS_TIP_ACCOUNTS[Math.floor(Math.random() * HELIUS_TIP_ACCOUNTS.length)]),
198
- lamports: tip_lamports,
199
- })
200
- swapTx.instructions.push(tip_instruction)
201
- }
202
-
203
- swapTx.sign(this.keypair)
204
-
205
- return swapTx
206
- }
207
-
173
+ const { sol_tip_fee } = context.trade_runtime.settings.strategy
208
174
 
209
-
210
- /**
211
- * build transaction for tip jito
212
- */
213
- buildTransactionForTipJito(context: TradeContext): Transaction {
214
- const groupId = context.trade_runtime.group.id
215
- const max_block_offset = context.trade_runtime.settings.strategy.max_block_offset
216
-
217
- let tipPayer = this.jitoTipWalletManager.getNextWallet(groupId)
218
- if (!tipPayer) {
219
- tipPayer = this.keypair
220
- }
221
-
222
- let tipAccount = getJitoTipAccount()
223
- let tip_lamports = context.trade_runtime.settings.strategy.sol_tip_fee
175
+ // 发送只走 Helius Sender,必须附带最低小费:
176
+ // 1、swqos_only: 至少 5000 lamports 小费
177
+ // -> transaction must send a tip of at least 5000 lamports to one of the Helius tip wallets
178
+ // 2、swqos + jito: 至少 0.0002 SOL 小费 -> lamports = 0.0002 * LAMPORTS_PER_SOL
179
+ let tip_lamports = sol_tip_fee
224
180
  if (tip_lamports < 5000) {
225
- tip_lamports = 5000
181
+ tip_lamports = 5000 // 下限:Helius swqos 协议硬要求
226
182
  }
227
- if (tip_lamports > 300000) {
228
- tip_lamports = 300000
183
+ if (tip_lamports > 1000000) {
184
+ tip_lamports = 1000000 // 上限:0.001 SOL
229
185
  }
186
+ let tip_instruction = SystemProgram.transfer({
187
+ fromPubkey: this.keypair.publicKey,
188
+ toPubkey: new PublicKey(HELIUS_TIP_ACCOUNTS[Math.floor(Math.random() * HELIUS_TIP_ACCOUNTS.length)]),
189
+ lamports: tip_lamports,
190
+ })
191
+ swapTx.instructions.push(tip_instruction)
192
+
193
+ swapTx.sign(this.keypair)
230
194
 
231
- const jitoTipTx = new Transaction();
232
- jitoTipTx.add(
233
- SystemProgram.transfer({
234
- fromPubkey: tipPayer.publicKey,
235
- toPubkey: new PublicKey(tipAccount),
236
- lamports: tip_lamports,
237
- }),
238
- );
239
- jitoTipTx.recentBlockhash = this.recentBlockhash
240
- jitoTipTx.lastValidBlockHeight = this.recentBlockheight + max_block_offset
241
- jitoTipTx.feePayer = tipPayer.publicKey;
242
-
243
- jitoTipTx.sign(tipPayer)
244
-
245
- return jitoTipTx
195
+ return swapTx
246
196
  }
247
197
 
248
198
  }
@@ -1,143 +0,0 @@
1
- import { Keypair } from '@solana/web3.js';
2
- import { log_info, log_warn, log_error } from '@clonegod/ttd-core/dist';
3
- import bs58 from 'bs58';
4
- import * as fs from 'fs';
5
- import os from 'os';
6
- import path from 'path';
7
-
8
- /**
9
- * 钱包配置接口
10
- */
11
- export interface WalletConfig {
12
- public_key: string;
13
- private_key: string;
14
- type: string; // main | sub
15
- keypair: Keypair; // 添加 Keypair 字段
16
- }
17
-
18
- /**
19
- * 分组配置接口
20
- */
21
- export interface GroupConfig {
22
- group_id: string;
23
- tip_wallets: WalletConfig[];
24
- }
25
-
26
- /**
27
- * Jito Tip 钱包管理器
28
- *
29
- * 功能:
30
- * 1. 从文件加载 tip wallets
31
- * 2. 返回下一个钱包(轮询)
32
- */
33
- export class JitoTipWalletManager {
34
- private readonly jito_tip_wallet_filename: string = 'jito_tip_wallet.json';
35
- private walletConfigs: GroupConfig[] = [];
36
- private walletIndexMap: Map<string, number> = new Map();
37
-
38
- constructor() {
39
- this.loadWalletConfigs();
40
- }
41
-
42
- /**
43
- * 从私钥创建 Keypair
44
- */
45
- private createKeypair(privateKeyBase58: string): Keypair {
46
- const privateKeyBytes = bs58.decode(privateKeyBase58);
47
- return Keypair.fromSecretKey(privateKeyBytes);
48
- }
49
-
50
- /**
51
- * 从文件加载钱包配置
52
- */
53
- private loadWalletConfigs(): void {
54
- try {
55
- // 从环境变量获取配置文件路径
56
- let jito_tip_wallet_path = process.env.JITO_TIP_WALLET_PATH || '';
57
- if (!jito_tip_wallet_path.startsWith('/')) {
58
- jito_tip_wallet_path = path.join(os.homedir(), 'data', 'keypairs', this.jito_tip_wallet_filename);
59
- }
60
-
61
- if (!fs.existsSync(jito_tip_wallet_path)) {
62
- log_warn(`[JitoTipWalletManager] 配置文件${this.jito_tip_wallet_filename}不存在!路径: ${jito_tip_wallet_path}`);
63
- this.walletConfigs = [];
64
- return;
65
- }
66
-
67
- const configData = fs.readFileSync(jito_tip_wallet_path, 'utf-8');
68
- this.walletConfigs = JSON.parse(configData);
69
-
70
- // 为每个钱包生成 KeyPair
71
- this.walletConfigs.forEach(group => {
72
- group.tip_wallets.forEach(wallet => {
73
- try {
74
- wallet.keypair = this.createKeypair(wallet.private_key);
75
- } catch (error) {
76
- log_error(`[JitoTipWalletManager] 生成钱包 KeyPair 失败 - public_key: ${wallet.public_key}`, error);
77
- }
78
- });
79
- });
80
-
81
- log_info(`[JitoTipWalletManager] 成功加载配置文件: ${jito_tip_wallet_path}`);
82
-
83
- // 加载完成后打印钱包信息
84
- this.printWalletInfo();
85
- } catch (error) {
86
- log_error('[JitoTipWalletManager] 加载钱包配置时出错:', error);
87
- this.walletConfigs = [];
88
- }
89
- }
90
-
91
- /**
92
- * 打印钱包信息(用于调试)
93
- */
94
- private printWalletInfo(): void {
95
- log_info('\n=== Tip钱包配置信息 ===');
96
- if (this.walletConfigs.length === 0) {
97
- log_info('没有找到任何钱包配置');
98
- return;
99
- }
100
-
101
- this.walletConfigs.forEach(group => {
102
- log_info(`\n分组: ${group.group_id}`);
103
- log_info(`钱包数量: ${group.tip_wallets.length}`);
104
- group.tip_wallets.forEach((wallet, index) => {
105
- const keypairStatus = wallet.keypair ? '✓' : '✗';
106
- log_info(` ${index + 1}. ${wallet.public_key}${wallet.type ? ` (${wallet.type})` : ''} [KeyPair: ${keypairStatus}]`);
107
- });
108
- });
109
- log_info('\n===================\n');
110
- }
111
-
112
- /**
113
- * 获取下一个钱包(轮询)
114
- * @param groupId 分组ID
115
- * @returns 钱包配置,如果未找到则返回 null
116
- */
117
- public getNextWallet(groupId: string): Keypair | null {
118
- const group = this.walletConfigs.find(g => g.group_id === groupId);
119
- if (!group) {
120
- log_warn(`[JitoTipWalletManager] 未找到group_id对应的钱包组: ${groupId}`);
121
- return null;
122
- }
123
-
124
- if (group.tip_wallets.length === 0) {
125
- log_warn(`[JitoTipWalletManager] group_id: ${groupId} 没有配置钱包`);
126
- return null;
127
- }
128
-
129
- // 获取当前索引,如果不存在则初始化为0
130
- let currentIndex = this.walletIndexMap.get(groupId) || 0;
131
-
132
- // 获取下一个钱包
133
- const wallet = group.tip_wallets[currentIndex];
134
-
135
- // 更新索引,如果达到列表末尾则重置为0
136
- currentIndex = (currentIndex + 1) % group.tip_wallets.length;
137
- this.walletIndexMap.set(groupId, currentIndex);
138
-
139
- return wallet.keypair;
140
- }
141
- }
142
-
143
-
@@ -1,132 +0,0 @@
1
- import { log_warn } from "@clonegod/ttd-core/dist";
2
- import axios, { AxiosError } from "axios";
3
- import { getHttpClient } from "./http_client";
4
-
5
- export const JITO_TIP_ACCOUNTS = [
6
- "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh",
7
- "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL",
8
- "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT",
9
- "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5",
10
- "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt",
11
- "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY",
12
- "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49",
13
- "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe"
14
- ]
15
-
16
- export class JitoUtils {
17
- static jitoTipAccounts: string[] = []
18
- static jitoTipAccountUrl = 'https://mainnet.block-engine.jito.wtf/api/v1/getTipAccounts'
19
-
20
- static async init(): Promise<void> {
21
- return JitoUtils.fetchJitoTipAccounts().then((accounts) => {
22
- JitoUtils.jitoTipAccounts = accounts;
23
- console.log(`fetchJitoTipAccounts success: ${accounts.length} accounts`, accounts)
24
- }).catch((error) => {
25
- log_warn(`fetchJitoTipAccounts failed!`, {
26
- url: JitoUtils.jitoTipAccountUrl,
27
- error: error.message
28
- });
29
- });
30
- }
31
-
32
- static async fetchJitoTipAccounts(): Promise<string[]> {
33
- const response = await axios.post<{ result: string[] }>(JitoUtils.jitoTipAccountUrl, {
34
- jsonrpc: '2.0',
35
- id: 1,
36
- method: 'getTipAccounts',
37
- params: []
38
- })
39
- return response.data.result;
40
- }
41
- }
42
-
43
-
44
- export const getJitoTipAccount = (): string => {
45
- let jito_tip_accounts = JitoUtils.jitoTipAccounts
46
- if (jito_tip_accounts.length === 0) {
47
- jito_tip_accounts = JITO_TIP_ACCOUNTS
48
- }
49
- return jito_tip_accounts[Math.floor(Math.random() * jito_tip_accounts.length)];
50
- }
51
-
52
- JitoUtils.init()
53
-
54
- // -----------------------------------------------------------
55
-
56
- export const sendBundleWithJito = async (mainTxBase64: string, tipTxBase64: string): Promise<string> => {
57
- let url = process.env.JITO_SEND_BUNDLE_URL || 'https://tokyo.mainnet.block-engine.jito.wtf/api/v1/bundles'
58
-
59
- // 使用共享的 axios 实例,复用连接池
60
- const client = getHttpClient(url)
61
-
62
- // Bundle 顺序: [mainTx, tipTx]
63
- // 根据 Jito Sandwich Mitigation 规则 (https://docs.jito.wtf/lowlatencytxnsend/#sandwich-mitigation):
64
- // - 如果主交易包含 jitodontfront 账户,它必须在 bundle 的第一个位置(索引 0)
65
- // - 允许的模式: [tx_with_dont_front, tip]
66
- // - 不允许的模式: [tip, tx_with_dont_front]
67
- const requestData = {
68
- jsonrpc: '2.0',
69
- id: 1,
70
- method: 'sendBundle',
71
- params: [
72
- [mainTxBase64, tipTxBase64],
73
- {
74
- "encoding": "base64"
75
- }
76
- ]
77
- };
78
-
79
- try {
80
- const response = await client.post<{ result: string }>(url, requestData)
81
- // {
82
- // jsonrpc: '2.0',
83
- // result: 'e62062b4af6963bb0f67fea429f97e4f4fee59851a4ef65154b9f49b5995b5be', // bundle id
84
- // id: 1
85
- // }
86
- // console.dir(response.data, { depth: null })
87
- const bundleId = response.data.result;
88
- console.log(`[sendBundleWithJito] bundleId: ${bundleId}`);
89
-
90
- return bundleId;
91
- } catch (error) {
92
- if(error instanceof AxiosError) {
93
- // 提取关键错误信息
94
- const status = error.response?.status;
95
- const statusText = error.response?.statusText;
96
-
97
- log_warn(`[sendBundleWithJito] Request failed: ${status} - ${statusText}`);
98
- } else {
99
- log_warn(`[sendBundleWithJito] Unexpected error: ${url} - ${error.message}`);
100
- }
101
- }
102
- }
103
-
104
-
105
- export const sendBundleWithJitoMultiIps = async (mainTxHash: string, mainTxBase64: string, tipTxBase64: string): Promise<string> => {
106
- let ips = (process.env.JITO_SEND_BUNDLE_SERVER_IPS || '127.0.0.1').split(',')
107
- let urls = ips.map(ip => `http://${ip}:10429/solana/send_tx`)
108
-
109
- // Bundle 顺序: [mainTx, tipTx]
110
- // 与 sendBundleWithJito 保持一致,符合 Jito Sandwich Mitigation 规则
111
- const body = {
112
- trace_id: '',
113
- txid: mainTxHash,
114
- encoding: 'base64', // base64
115
- encoded_tx: [mainTxBase64, tipTxBase64].join(','), // bundle: mainTx, tipTx
116
- max_retry: 3
117
- }
118
-
119
- Promise.all(urls.map(async (url) => {
120
- try {
121
- const client = getHttpClient(url)
122
- const response = await client.post<{ result: string }>(url, body)
123
- return response.data.result;
124
- } catch (error) {
125
- console.error(`sendBundleWithJitoByMultiIps error: ${url}`, error)
126
- }
127
- }))
128
-
129
- return 'success';
130
- }
131
-
132
-