@clonegod/ttd-sol-common 1.0.114 → 1.0.116

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,6 +2,7 @@ import { BlockhashWithExpiryBlockHeight, VersionedTransaction, AddressLookupTabl
2
2
  import { DAS } from './types/das-types';
3
3
  import { GetPriorityFeeEstimateRequest, GetPriorityFeeEstimateResponse, JitoRegion, PollTransactionOptions, SmartTransactionContext, HeliusSendOptions } from './types';
4
4
  import { SolanaTradeRuntimeType } from '../../types';
5
+ import { JitoJsonRpcClient } from '../jito';
5
6
  export type SendAndConfirmTransactionResponse = {
6
7
  signature: TransactionSignature;
7
8
  confirmResponse: RpcResponseAndContext<SignatureResult>;
@@ -11,6 +12,7 @@ export type SendAndConfirmTransactionResponse = {
11
12
  export declare class RpcClient {
12
13
  protected readonly connection: Connection;
13
14
  protected readonly id?: string;
15
+ jitoClient: JitoJsonRpcClient;
14
16
  constructor(connection: Connection, id?: string);
15
17
  airdrop(publicKey: PublicKey, lamports: number, commitment?: Commitment): Promise<SendAndConfirmTransactionResponse>;
16
18
  getLatestBlockhash(commitmentOrConfig?: Commitment | GetLatestBlockhashConfig): Promise<BlockhashWithExpiryBlockHeight>;
@@ -48,4 +50,6 @@ export declare class RpcClient {
48
50
  sendTransaction(transaction: Transaction | VersionedTransaction, options?: HeliusSendOptions): Promise<TransactionSignature>;
49
51
  sendSmartTransactionWithTipMixed(solana_trade_runtime: SolanaTradeRuntimeType, instructions: TransactionInstruction[], signers: Signer[], lookupTables?: AddressLookupTableAccount[], tipAmount?: number, region?: JitoRegion, feePayer?: Signer, lastValidBlockHeightOffset?: number): Promise<string>;
50
52
  sendJitoTransaction(serializedTransaction: string, jitoApiUrl: string): Promise<string>;
53
+ get_last_blockhash_slot(connections: Connection[]): Promise<RpcResponseAndContext<BlockhashWithExpiryBlockHeight>>;
54
+ check_bundle_result(bundle_id: string, timeoutMs?: number): Promise<void>;
51
55
  }
@@ -19,10 +19,12 @@ const axios_1 = __importDefault(require("axios"));
19
19
  const types_1 = require("./types");
20
20
  const get_signature_1 = require("../send_tx/get_signature");
21
21
  const dist_1 = require("@clonegod/ttd-common/dist");
22
+ const jito_1 = require("../jito");
22
23
  class RpcClient {
23
24
  constructor(connection, id) {
24
25
  this.connection = connection;
25
26
  this.id = id;
27
+ this.jitoClient = new jito_1.JitoJsonRpcClient('https://mainnet.block-engine.jito.wtf/api/v1', undefined);
26
28
  }
27
29
  airdrop(publicKey, lamports, commitment) {
28
30
  return __awaiter(this, void 0, void 0, function* () {
@@ -365,10 +367,7 @@ class RpcClient {
365
367
  }
366
368
  (0, dist_1.log_info)(`>>> getLatestBlockhashAndContext, start`);
367
369
  const payerKey = feePayer ? feePayer.publicKey : signers[0].publicKey;
368
- const { context: { slot: minContextSlot }, value: blockhash, } = yield Promise.race([
369
- this.connection.getLatestBlockhashAndContext(),
370
- solana_trade_runtime.connection.getLatestBlockhashAndContext()
371
- ]);
370
+ let { context: { slot: minContextSlot }, value: blockhash, } = yield this.get_last_blockhash_slot([this.connection, solana_trade_runtime.connection]);
372
371
  (0, dist_1.log_info)(`>>> getLatestBlockhashAndContext, end`);
373
372
  const recentBlockhash = blockhash.blockhash;
374
373
  const isVersioned = lookupTables.length > 0;
@@ -396,7 +395,7 @@ class RpcClient {
396
395
  }
397
396
  }
398
397
  setTimeout(() => __awaiter(this, void 0, void 0, function* () {
399
- if (Math.random() > 0.15)
398
+ if (Math.random() > -1)
400
399
  return;
401
400
  const serializedTransaction = bs58_1.default.encode(isVersioned
402
401
  ? versionedTransaction.serialize()
@@ -423,7 +422,7 @@ class RpcClient {
423
422
  });
424
423
  instructions.unshift(computeBudgetIx);
425
424
  setTimeout(() => __awaiter(this, void 0, void 0, function* () {
426
- if (Math.random() > 0)
425
+ if (Math.random() > -1)
427
426
  return;
428
427
  (0, dist_1.log_info)(`>>> getComputeUnits, start`);
429
428
  const units = yield this.getComputeUnits(instructions, payerKey, isVersioned ? lookupTables : [], signers);
@@ -580,6 +579,7 @@ class RpcClient {
580
579
  let jitoApiUrl = `${types_1.JITO_API_URLS[region]}/api/v1/bundles`;
581
580
  this.sendJitoTransaction(serializedTransaction, `${types_1.JITO_API_URLS['Default']}/api/v1/transactions?bundleOnly=true`);
582
581
  const bundleId = yield this.sendJitoBundle([serializedTransaction], jitoApiUrl);
582
+ this.check_bundle_result(bundleId);
583
583
  (0, dist_1.log_info)(`sendJitoBundle finish`, {
584
584
  jitoApiUrl,
585
585
  txid,
@@ -587,11 +587,10 @@ class RpcClient {
587
587
  });
588
588
  const currentBlockHeight = yield solana_trade_runtime.connection.getBlockHeight();
589
589
  const lastValidBlockHeight = Math.min(blockhash.lastValidBlockHeight, currentBlockHeight + lastValidBlockHeightOffset);
590
- const timeout = 60000;
591
- const interval = 5000;
590
+ const timeout = 10000;
591
+ const interval = 2000;
592
592
  const startTime = Date.now();
593
- while (Date.now() - startTime < timeout ||
594
- (yield this.connection.getBlockHeight()) <= lastValidBlockHeight) {
593
+ while (Date.now() - startTime < timeout) {
595
594
  const bundleStatuses = yield this.getBundleStatuses([bundleId], jitoApiUrl);
596
595
  (0, dist_1.log_info)(`getBundleStatuses`, {
597
596
  txid,
@@ -767,5 +766,52 @@ class RpcClient {
767
766
  return bundleId;
768
767
  });
769
768
  }
769
+ get_last_blockhash_slot(connections) {
770
+ return __awaiter(this, void 0, void 0, function* () {
771
+ let last_blockhash_slot;
772
+ try {
773
+ let appConfig = global.appConfig;
774
+ let { key, value } = yield appConfig.arb_cache.loading_cache.get(dist_1.CHAIN_ID.SOLANA, 'b', 'slot', true);
775
+ let { context_slot, blockhash, blockHeight } = JSON.parse(value);
776
+ last_blockhash_slot = {
777
+ context: {
778
+ slot: context_slot
779
+ },
780
+ value: {
781
+ blockhash,
782
+ lastValidBlockHeight: blockHeight
783
+ }
784
+ };
785
+ }
786
+ catch (err) {
787
+ (0, dist_1.log_error)('get_last_blockhash_slot, from redis', err);
788
+ }
789
+ if (!last_blockhash_slot) {
790
+ try {
791
+ last_blockhash_slot = yield Promise.race(connections.map(c => c.getLatestBlockhashAndContext()));
792
+ }
793
+ catch (err) {
794
+ (0, dist_1.log_error)('get_last_blockhash_slot, fetch by connection', err);
795
+ }
796
+ }
797
+ return last_blockhash_slot;
798
+ });
799
+ }
800
+ check_bundle_result(bundle_id_1) {
801
+ return __awaiter(this, arguments, void 0, function* (bundle_id, timeoutMs = 10000) {
802
+ let start = Date.now();
803
+ while (Date.now() - start < timeoutMs) {
804
+ try {
805
+ let rs = yield fetch(`https://bundles.jito.wtf/api/v1/bundles/get_bundle_error/${bundle_id}`);
806
+ let jsonObj = yield rs.json();
807
+ console.log('get_bundle_error, res=', jsonObj);
808
+ }
809
+ catch (err) {
810
+ console.error('get_bundle_error, error!', err);
811
+ }
812
+ yield new Promise(resolve => setTimeout(resolve, 1000));
813
+ }
814
+ });
815
+ }
770
816
  }
771
817
  exports.RpcClient = RpcClient;
@@ -0,0 +1,14 @@
1
+ export declare class JitoJsonRpcClient {
2
+ baseUrl: string;
3
+ uuid: string;
4
+ client: any;
5
+ constructor(baseUrl: string, uuid: string);
6
+ sendRequest(endpoint: any, method: any, params: any): Promise<any>;
7
+ getTipAccounts(): Promise<any>;
8
+ getRandomTipAccount(): Promise<any>;
9
+ sendBundle(params: any): Promise<any>;
10
+ sendTxn(params: any, bundleOnly?: boolean): Promise<any>;
11
+ getInFlightBundleStatuses(params: any): Promise<any>;
12
+ getBundleStatuses(params: any): Promise<any>;
13
+ confirmInflightBundle(bundleId: any, timeoutMs?: number): Promise<any>;
14
+ }
@@ -0,0 +1,142 @@
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.JitoJsonRpcClient = void 0;
13
+ const axios = require('axios');
14
+ class JitoJsonRpcClient {
15
+ constructor(baseUrl, uuid) {
16
+ this.baseUrl = baseUrl;
17
+ this.uuid = uuid;
18
+ this.client = axios.create({
19
+ headers: {
20
+ 'Content-Type': 'application/json',
21
+ },
22
+ });
23
+ }
24
+ sendRequest(endpoint, method, params) {
25
+ return __awaiter(this, void 0, void 0, function* () {
26
+ const url = `${this.baseUrl}${endpoint}`;
27
+ const data = {
28
+ jsonrpc: '2.0',
29
+ id: 1,
30
+ method,
31
+ params: params || [],
32
+ };
33
+ console.log(`Sending request to: ${url}`);
34
+ console.log(`Request body: ${JSON.stringify(data, null, 2)}`);
35
+ try {
36
+ const response = yield this.client.post(url, data);
37
+ console.log(`Response status: ${response.status}`);
38
+ console.log(`Response body: ${JSON.stringify(response.data, null, 2)}`);
39
+ return response.data;
40
+ }
41
+ catch (error) {
42
+ if (axios.isAxiosError(error)) {
43
+ console.error(`HTTP error: ${error.message}`);
44
+ throw error;
45
+ }
46
+ else {
47
+ console.error(`Unexpected error: ${error}`);
48
+ throw new Error('An unexpected error occurred');
49
+ }
50
+ }
51
+ });
52
+ }
53
+ getTipAccounts() {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ const endpoint = this.uuid ? `/bundles?uuid=${this.uuid}` : '/bundles';
56
+ return this.sendRequest(endpoint, 'getTipAccounts', null);
57
+ });
58
+ }
59
+ getRandomTipAccount() {
60
+ return __awaiter(this, void 0, void 0, function* () {
61
+ const tipAccountsResponse = yield this.getTipAccounts();
62
+ if (tipAccountsResponse.result && Array.isArray(tipAccountsResponse.result) && tipAccountsResponse.result.length > 0) {
63
+ const randomIndex = Math.floor(Math.random() * tipAccountsResponse.result.length);
64
+ return tipAccountsResponse.result[randomIndex];
65
+ }
66
+ else {
67
+ throw new Error('No tip accounts available');
68
+ }
69
+ });
70
+ }
71
+ sendBundle(params) {
72
+ return __awaiter(this, void 0, void 0, function* () {
73
+ const endpoint = this.uuid ? `/bundles?uuid=${this.uuid}` : '/bundles';
74
+ return this.sendRequest(endpoint, 'sendBundle', params);
75
+ });
76
+ }
77
+ sendTxn(params_1) {
78
+ return __awaiter(this, arguments, void 0, function* (params, bundleOnly = false) {
79
+ let endpoint = '/transactions';
80
+ const queryParams = [];
81
+ if (bundleOnly) {
82
+ queryParams.push('bundleOnly=true');
83
+ }
84
+ if (this.uuid) {
85
+ queryParams.push(`uuid=${this.uuid}`);
86
+ }
87
+ if (queryParams.length > 0) {
88
+ endpoint += `?${queryParams.join('&')}`;
89
+ }
90
+ return this.sendRequest(endpoint, 'sendTransaction', params);
91
+ });
92
+ }
93
+ getInFlightBundleStatuses(params) {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ const endpoint = this.uuid ? `/bundles?uuid=${this.uuid}` : '/bundles';
96
+ return this.sendRequest(endpoint, 'getInflightBundleStatuses', params);
97
+ });
98
+ }
99
+ getBundleStatuses(params) {
100
+ return __awaiter(this, void 0, void 0, function* () {
101
+ const endpoint = this.uuid ? `/bundles?uuid=${this.uuid}` : '/bundles';
102
+ return this.sendRequest(endpoint, 'getBundleStatuses', params);
103
+ });
104
+ }
105
+ confirmInflightBundle(bundleId_1) {
106
+ return __awaiter(this, arguments, void 0, function* (bundleId, timeoutMs = 60000) {
107
+ const start = Date.now();
108
+ while (Date.now() - start < timeoutMs) {
109
+ try {
110
+ const response = yield this.getInFlightBundleStatuses([[bundleId]]);
111
+ if (response.result && response.result.value && response.result.value.length > 0) {
112
+ const bundleStatus = response.result.value[0];
113
+ console.log(`Bundle status: ${bundleStatus.status}, Landed slot: ${bundleStatus.landed_slot}`);
114
+ if (bundleStatus.status === "Failed") {
115
+ return bundleStatus;
116
+ }
117
+ else if (bundleStatus.status === "Landed") {
118
+ const detailedStatus = yield this.getBundleStatuses([[bundleId]]);
119
+ if (detailedStatus.result && detailedStatus.result.value && detailedStatus.result.value.length > 0) {
120
+ return detailedStatus.result.value[0];
121
+ }
122
+ else {
123
+ console.log('No detailed status returned for landed bundle.');
124
+ return bundleStatus;
125
+ }
126
+ }
127
+ }
128
+ else {
129
+ console.log('No status returned for the bundle. It may be invalid or very old.');
130
+ }
131
+ }
132
+ catch (error) {
133
+ console.error('Error checking bundle status:', error);
134
+ }
135
+ yield new Promise(resolve => setTimeout(resolve, 2000));
136
+ }
137
+ console.log(`Bundle ${bundleId} has not reached a final state within ${timeoutMs}ms`);
138
+ return { status: 'Timeout' };
139
+ });
140
+ }
141
+ }
142
+ exports.JitoJsonRpcClient = JitoJsonRpcClient;
@@ -73,12 +73,14 @@ const handle_order_message = (appConfig, trade, message) => __awaiter(void 0, vo
73
73
  let { price_msg, id_parts } = yield check_parse_order_msg(appConfig, order_msg);
74
74
  let { order_trace_id } = order_msg;
75
75
  let { chain_id, dex_id, pool_id, fee_rate } = id_parts;
76
- let lock_order = yield (0, exports.try_lock_order_msg)(appConfig, order_msg);
77
- if (!lock_order) {
78
- (0, dist_1.log_warn)(`try lock order failed!`, {
79
- chain_id, group_id, order_trace_id
80
- });
81
- return;
76
+ if (process.env.ENABLE_MULTIPLE_PROCESS === 'true') {
77
+ let lock_order = yield (0, exports.try_lock_order_msg)(appConfig, order_msg);
78
+ if (!lock_order) {
79
+ (0, dist_1.log_warn)(`try lock order failed!`, {
80
+ chain_id, group_id, order_trace_id
81
+ });
82
+ return;
83
+ }
82
84
  }
83
85
  let context;
84
86
  let txid = '';
@@ -87,7 +87,7 @@ class TransactionResultChecker {
87
87
  return __awaiter(this, void 0, void 0, function* () {
88
88
  const check_start_time = Date.now();
89
89
  const check_interval = parseInt(process.env.CHECK_TX_RESULT_INTERVAL_MILLS || '1000');
90
- const check_timeout = parseInt(process.env.CHECK_TX_RESULT_TIMEOUT_MILLS || '30000');
90
+ const check_timeout = parseInt(process.env.CHECK_TX_RESULT_TIMEOUT_MILLS || '6000');
91
91
  const intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
92
92
  this.check_count += 1;
93
93
  (0, dist_1.log_info)(`check transaction start: seq=[${this.check_count}], txhash= ${this.txid}, trace_id=${this.trace_id}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-sol-common",
3
- "version": "1.0.114",
3
+ "version": "1.0.116",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "types/index.d.ts",
@@ -30,4 +30,4 @@
30
30
  "publishConfig": {
31
31
  "access": "public"
32
32
  }
33
- }
33
+ }
package/types/index.d.ts CHANGED
@@ -56,3 +56,11 @@ export interface SolanaTradeRuntimeType extends TradeRuntimeType {
56
56
  }
57
57
 
58
58
 
59
+ export interface SolLastBlockAndSlot {
60
+ context_slot: number
61
+ slot: number
62
+ blockhash: string
63
+ blockHeight: number
64
+ blockTime: number
65
+ }
66
+