@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.
- package/dist/trade/index.d.ts +0 -1
- package/dist/trade/index.js +0 -1
- package/dist/trade/send/send_tx.d.ts +0 -1
- package/dist/trade/send/send_tx.js +0 -13
- package/dist/trade/tx_builder.d.ts +0 -3
- package/dist/trade/tx_builder.js +11 -43
- package/package.json +2 -2
- package/src/trade/index.ts +0 -1
- package/src/trade/send/send_tx.ts +0 -25
- package/src/trade/tx_builder.ts +18 -68
- package/src/trade/jito_tip_wallets.ts +0 -143
- package/src/trade/send/jito.ts +0 -132
package/dist/trade/index.d.ts
CHANGED
package/dist/trade/index.js
CHANGED
|
@@ -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
|
}
|
package/dist/trade/tx_builder.js
CHANGED
|
@@ -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 {
|
|
103
|
-
|
|
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 >
|
|
134
|
-
tip_lamports =
|
|
104
|
+
if (tip_lamports > 1000000) {
|
|
105
|
+
tip_lamports = 1000000;
|
|
135
106
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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.
|
|
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.
|
|
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",
|
package/src/trade/index.ts
CHANGED
|
@@ -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
|
|
package/src/trade/tx_builder.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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 >
|
|
228
|
-
tip_lamports =
|
|
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
|
-
|
|
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
|
-
|
package/src/trade/send/jito.ts
DELETED
|
@@ -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
|
-
|