@clonegod/ttd-sol-common 1.0.114 → 1.0.115

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,7 +587,7 @@ 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;
590
+ const timeout = 10000;
591
591
  const interval = 5000;
592
592
  const startTime = Date.now();
593
593
  while (Date.now() - startTime < timeout ||
@@ -767,5 +767,53 @@ class RpcClient {
767
767
  return bundleId;
768
768
  });
769
769
  }
770
+ get_last_blockhash_slot(connections) {
771
+ return __awaiter(this, void 0, void 0, function* () {
772
+ let last_blockhash_slot;
773
+ try {
774
+ let appConfig = global.appConfig;
775
+ let { key, value } = yield appConfig.arb_cache.loading_cache.get(dist_1.CHAIN_ID.SOLANA, 'b', 'slot', true);
776
+ let { context_slot, blockhash, blockHeight } = JSON.parse(value);
777
+ last_blockhash_slot = {
778
+ context: {
779
+ slot: context_slot
780
+ },
781
+ value: {
782
+ blockhash,
783
+ lastValidBlockHeight: blockHeight
784
+ }
785
+ };
786
+ }
787
+ catch (err) {
788
+ (0, dist_1.log_error)('get_last_blockhash_slot, from redis', err);
789
+ }
790
+ if (!last_blockhash_slot) {
791
+ try {
792
+ last_blockhash_slot = yield Promise.race(connections.map(c => c.getLatestBlockhashAndContext()));
793
+ }
794
+ catch (err) {
795
+ (0, dist_1.log_error)('get_last_blockhash_slot, fetch by connection', err);
796
+ }
797
+ }
798
+ return last_blockhash_slot;
799
+ });
800
+ }
801
+ check_bundle_result(bundle_id_1) {
802
+ return __awaiter(this, arguments, void 0, function* (bundle_id, timeoutMs = 3000) {
803
+ this.jitoClient.confirmInflightBundle(bundle_id, timeoutMs);
804
+ let start = Date.now();
805
+ while (Date.now() - start < timeoutMs) {
806
+ try {
807
+ let rs = yield fetch(`https://bundles.jito.wtf/api/v1/bundles/get_bundle_error/${bundle_id}`);
808
+ let jsonObj = yield rs.json();
809
+ console.log('get_bundle_error, res=', jsonObj);
810
+ }
811
+ catch (err) {
812
+ console.error('get_bundle_error, error!', err);
813
+ }
814
+ yield new Promise(resolve => setTimeout(resolve, 500));
815
+ }
816
+ });
817
+ }
770
818
  }
771
819
  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;
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.115",
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
+