@tonappchain/sdk 0.7.2-alpha-21 → 0.7.2-alpha-22

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.
@@ -62,9 +62,9 @@ export declare abstract class BaseContractOpener implements ContractOpener {
62
62
  */
63
63
  private findTransactionByHashType;
64
64
  /**
65
- * Retry lookup for root transaction because it may appear in indexers with a delay.
65
+ * Find transaction with retry logic
66
66
  */
67
- private findRootTransactionWithRetry;
67
+ private findTransactionWithRetry;
68
68
  /**
69
69
  * Track transaction tree and validate all transactions
70
70
  */
@@ -293,46 +293,31 @@ class BaseContractOpener {
293
293
  }
294
294
  }
295
295
  /**
296
- * Retry lookup for root transaction because it may appear in indexers with a delay.
296
+ * Find transaction with retry logic
297
297
  */
298
- async findRootTransactionWithRetry(address, hash, hashType, limit, maxScannedTransactions, waitForRootTransaction) {
299
- if (!waitForRootTransaction) {
300
- return this.findTransactionByHashType(address, hash, hashType, {
301
- limit,
302
- archival: true,
303
- maxScannedTransactions,
304
- });
305
- }
306
- const attempts = Math.ceil(Consts_1.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_TIMEOUT_MS / Consts_1.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_RETRY_DELAY_MS);
307
- const broadSearchOpts = { limit, archival: true, maxScannedTransactions };
308
- const baselineInfo = await this.getAddressInformation(address);
309
- let seenLt = baselineInfo.lastTransaction.lt || undefined;
310
- // Capture baseline before first search.
311
- const firstTx = await this.findTransactionByHashType(address, hash, hashType, broadSearchOpts);
312
- if (firstTx) {
313
- this.logger?.debug(`Root transaction found on attempt 1/${attempts}`);
314
- return firstTx;
315
- }
316
- this.logger?.debug(`Root transaction not found yet (attempt 1/${attempts}), retrying in ${Consts_1.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_RETRY_DELAY_MS}ms`);
317
- await (0, Utils_1.sleep)(Consts_1.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_RETRY_DELAY_MS);
318
- for (let attempt = 2; attempt <= attempts; attempt++) {
319
- const info = await this.getAddressInformation(address);
320
- const currentLt = info.lastTransaction.lt || undefined;
321
- if (!currentLt || currentLt === seenLt) {
322
- this.logger?.debug(`Root transaction not found yet (attempt ${attempt}/${attempts}), lastTx unchanged, retrying in ${Consts_1.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_RETRY_DELAY_MS}ms`);
323
- await (0, Utils_1.sleep)(Consts_1.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_RETRY_DELAY_MS);
324
- continue;
298
+ async findTransactionWithRetry(address, hash, hashType, opts, depth) {
299
+ const retryDelayMs = opts.retryDelayMs ?? Consts_1.DEFAULT_RETRY_ON_NOT_FOUND_DELAY_MS;
300
+ const maxRetries = opts.retries ?? Consts_1.DEFAULT_RETRY_ON_NOT_FOUND_RETRIES;
301
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
302
+ let errorMsg;
303
+ try {
304
+ const tx = await this.findTransactionByHashType(address, hash, hashType, opts);
305
+ if (tx) {
306
+ return tx;
307
+ }
308
+ }
309
+ catch (error) {
310
+ errorMsg = error instanceof Error ? error.message : String(error);
325
311
  }
326
- seenLt = currentLt;
327
- const tx = await this.findTransactionByHashType(address, hash, hashType, broadSearchOpts);
328
- if (tx) {
329
- this.logger?.debug(`Root transaction found on attempt ${attempt}/${attempts}`);
330
- return tx;
312
+ const isLastAttempt = attempt >= maxRetries;
313
+ const reason = errorMsg ?? 'not found';
314
+ const retryInfo = isLastAttempt ? '' : `, retrying in ${retryDelayMs}ms`;
315
+ this.logger?.debug(`Transaction not found at depth ${depth} (attempt ${attempt + 1}/${maxRetries + 1}): ${reason}${retryInfo}`);
316
+ if (isLastAttempt) {
317
+ return null;
331
318
  }
332
- this.logger?.debug(`Root transaction not found yet (attempt ${attempt}/${attempts}), retrying in ${Consts_1.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_RETRY_DELAY_MS}ms`);
333
- await (0, Utils_1.sleep)(Consts_1.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_RETRY_DELAY_MS);
319
+ await (0, Utils_1.sleep)(retryDelayMs);
334
320
  }
335
- this.logger?.debug(`Root transaction not found after ${attempts} attempts`);
336
321
  return null;
337
322
  }
338
323
  /**
@@ -343,7 +328,7 @@ class BaseContractOpener {
343
328
  ignoreOpcodeList: Consts_1.IGNORE_OPCODE,
344
329
  limit: Consts_1.DEFAULT_FIND_TX_LIMIT,
345
330
  direction: 'both',
346
- waitForRootTransaction: Consts_1.DEFAULT_WAIT_FOR_ROOT_TRANSACTION,
331
+ retryOnNotFound: Consts_1.DEFAULT_RETRY_ON_NOT_FOUND,
347
332
  }) {
348
333
  const result = await this.trackTransactionTreeWithResult(address, hash, params);
349
334
  if (this.logger && typeof result.checkedCount === 'number') {
@@ -354,7 +339,13 @@ class BaseContractOpener {
354
339
  const context = reason === 'not_found'
355
340
  ? ` address=${errorAddress ?? 'unknown'} hashType=${hashType ?? 'unknown'}`
356
341
  : '';
357
- throw (0, errors_1.txFinalizationError)(`${txHash}: reason=${reason} (exitCode=${exitCode}, resultCode=${resultCode})${context}`);
342
+ const message = `${txHash}: reason=${reason} (exitCode=${exitCode}, resultCode=${resultCode})${context}`;
343
+ if (reason === 'not_found') {
344
+ throw new Error(message);
345
+ }
346
+ else {
347
+ throw (0, errors_1.txFinalizationError)(message);
348
+ }
358
349
  }
359
350
  }
360
351
  /**
@@ -365,15 +356,21 @@ class BaseContractOpener {
365
356
  ignoreOpcodeList: Consts_1.IGNORE_OPCODE,
366
357
  limit: Consts_1.DEFAULT_FIND_TX_LIMIT,
367
358
  direction: 'both',
368
- waitForRootTransaction: Consts_1.DEFAULT_WAIT_FOR_ROOT_TRANSACTION,
359
+ retryOnNotFound: Consts_1.DEFAULT_RETRY_ON_NOT_FOUND,
369
360
  }) {
370
- const { maxDepth = Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, ignoreOpcodeList = Consts_1.IGNORE_OPCODE, limit = Consts_1.DEFAULT_FIND_TX_LIMIT, maxScannedTransactions = Consts_1.DEFAULT_MAX_SCANNED_TRANSACTIONS, direction = 'both', waitForRootTransaction = Consts_1.DEFAULT_WAIT_FOR_ROOT_TRANSACTION, } = params;
361
+ const { maxDepth = Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, ignoreOpcodeList = Consts_1.IGNORE_OPCODE, limit = Consts_1.DEFAULT_FIND_TX_LIMIT, maxScannedTransactions = Consts_1.DEFAULT_MAX_SCANNED_TRANSACTIONS, direction = 'both', retryOnNotFound = Consts_1.DEFAULT_RETRY_ON_NOT_FOUND, retryDelayMs, retries, } = params;
371
362
  const parsedAddress = ton_1.Address.parse(address);
372
363
  const normalizedRootHash = (0, Utils_1.normalizeHashToBase64)(hash);
373
364
  const visitedSearchKeys = new Set();
374
365
  const processedTxHashes = new Set();
375
366
  let checkedCount = 0;
376
- const searchOpts = { limit, archival: true, maxScannedTransactions };
367
+ const searchOpts = {
368
+ limit,
369
+ archival: true,
370
+ maxScannedTransactions,
371
+ retryDelayMs,
372
+ retries,
373
+ };
377
374
  const queue = [
378
375
  { address: parsedAddress, hash: normalizedRootHash, depth: 0, hashType: 'unknown' },
379
376
  ];
@@ -383,8 +380,8 @@ class BaseContractOpener {
383
380
  if (visitedSearchKeys.has(visitedKey))
384
381
  continue;
385
382
  visitedSearchKeys.add(visitedKey);
386
- const tx = currentDepth === 0
387
- ? await this.findRootTransactionWithRetry(currentAddress, currentHash, hashType, limit, maxScannedTransactions, waitForRootTransaction)
383
+ const tx = retryOnNotFound
384
+ ? await this.findTransactionWithRetry(currentAddress, currentHash, hashType, searchOpts, currentDepth)
388
385
  : await this.findTransactionByHashType(currentAddress, currentHash, hashType, searchOpts);
389
386
  if (!tx) {
390
387
  this.logger?.debug(`Transaction not found for hash: ${currentHash} (address=${currentAddress?.toString()}, hashType=${hashType ?? 'unknown'})`);
@@ -144,12 +144,11 @@ class RetryableContractOpener {
144
144
  for (let index = 0; index < this.openerConfigs.length; index++) {
145
145
  const config = this.openerConfigs[index];
146
146
  const openerLabel = `opener ${index + 1}/${this.openerConfigs.length}`;
147
- this.logger?.debug(`[RetryableContractOpener] ${operationName}: trying ${openerLabel}${useRetries ? ` (max retries ${config.retries})` : ' (single attempt)'}`);
147
+ this.logger?.debug(`[RetryableContractOpener] ${operationName}: trying ${openerLabel}`);
148
148
  const result = useRetries
149
149
  ? await this.tryWithRetries(() => operation(config), config, `${operationName} ${openerLabel}`)
150
150
  : await this.trySingleAttempt(() => operation(config));
151
151
  if (result.success) {
152
- this.logger?.debug(`[RetryableContractOpener] ${operationName}: ${openerLabel} succeeded`);
153
152
  return { success: true, data: result.data };
154
153
  }
155
154
  lastError = result.lastError;
@@ -200,7 +199,7 @@ class RetryableContractOpener {
200
199
  return { success: false, lastError };
201
200
  }
202
201
  if (attempt < config.retries) {
203
- this.logger?.debug(`[RetryableContractOpener] ${operationContext}: attempt ${attempt + 1}/${config.retries + 1} failed, retrying in ${config.retryDelay}ms`);
202
+ this.logger?.debug(`[RetryableContractOpener] ${operationContext}: attempt ${attempt + 1}/${config.retries + 1} failed (${lastError.message}), retrying in ${config.retryDelay}ms`);
204
203
  await sleep(config.retryDelay);
205
204
  }
206
205
  }
@@ -37,8 +37,12 @@ function extractEndpoint(message) {
37
37
  }
38
38
  return match[0].replace(/[),.;]+$/, '');
39
39
  }
40
- function extractResponseMessage(data) {
40
+ function extractResponseMessage(data, includeFullTrace) {
41
41
  if (typeof data === 'string' && data.length > 0) {
42
+ const isHtml = data.includes('<!doctype html>') || data.includes('<html');
43
+ if (isHtml && !includeFullTrace) {
44
+ return '[HTML response]';
45
+ }
42
46
  return data;
43
47
  }
44
48
  if (!data || typeof data !== 'object') {
@@ -53,11 +57,11 @@ function extractResponseMessage(data) {
53
57
  }
54
58
  return undefined;
55
59
  }
56
- function buildInnerErrorSummary(inner) {
60
+ function buildInnerErrorSummary(inner, includeFullTrace) {
57
61
  if (inner && typeof inner === 'object') {
58
62
  const err = inner;
59
63
  const parts = [];
60
- const responseMessage = extractResponseMessage(err.response?.data);
64
+ const responseMessage = extractResponseMessage(err.response?.data, includeFullTrace);
61
65
  const httpStatus = [err.httpStatus, err.status, err.response?.status].find((value) => typeof value === 'number');
62
66
  const httpMessage = typeof err.innerMessage === 'string' && err.innerMessage.length > 0 ? err.innerMessage : responseMessage;
63
67
  if (typeof httpStatus === 'number') {
@@ -81,7 +85,7 @@ function buildInnerErrorSummary(inner) {
81
85
  }
82
86
  return 'message=unknown error';
83
87
  }
84
- const allEndpointsFailedError = (inner, includeInnerStack = false) => new errors_1.FetchError(`All endpoints failed, last err: ${buildInnerErrorSummary(inner)}`, 117, inner, {
88
+ const allEndpointsFailedError = (inner, includeInnerStack = false) => new errors_1.FetchError(`All endpoints failed, last err: ${buildInnerErrorSummary(inner, includeInnerStack)}`, 117, inner, {
85
89
  includeInnerStack,
86
90
  });
87
91
  exports.allEndpointsFailedError = allEndpointsFailedError;
@@ -16,16 +16,18 @@ export declare const TAC_DECIMALS = 18;
16
16
  export declare const FIVE_MINUTES: number;
17
17
  export declare const MINUTE: number;
18
18
  export declare const TON_BURN_ADDRESS = "EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c";
19
- export declare const DEFAULT_TIMEOUT_MS = 300000;
20
19
  export declare const DEFAULT_HTTP_CLIENT_TIMEOUT_MS = 30000;
21
20
  export declare const DEFAULT_RETRY_MAX_COUNT = 5;
22
21
  export declare const DEFAULT_RETRY_DELAY_MS = 1000;
22
+ export declare const DEFAULT_WAIT_TIMEOUT_MS = 300000;
23
+ export declare const DEFAULT_WAIT_MAX_ATTEMPTS = 30;
24
+ export declare const DEFAULT_WAIT_DELAY_MS = 10000;
23
25
  export declare const DEFAULT_FIND_TX_LIMIT = 100;
24
26
  export declare const DEFAULT_MAX_SCANNED_TRANSACTIONS = 100;
25
27
  export declare const DEFAULT_FIND_TX_ARCHIVAL = true;
26
28
  export declare const DEFAULT_FIND_TX_MAX_DEPTH = 10;
27
- export declare const DEFAULT_WAIT_FOR_ROOT_TRANSACTION = true;
28
- export declare const DEFAULT_WAIT_FOR_ROOT_TRANSACTION_TIMEOUT_MS: number;
29
- export declare const DEFAULT_WAIT_FOR_ROOT_TRANSACTION_RETRY_DELAY_MS = 1000;
29
+ export declare const DEFAULT_RETRY_ON_NOT_FOUND = true;
30
+ export declare const DEFAULT_RETRY_ON_NOT_FOUND_RETRIES = 10;
31
+ export declare const DEFAULT_RETRY_ON_NOT_FOUND_DELAY_MS = 5000;
30
32
  export declare const IGNORE_MSG_VALUE_1_NANO = 1n;
31
33
  export declare const IGNORE_OPCODE: number[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.IGNORE_OPCODE = exports.IGNORE_MSG_VALUE_1_NANO = exports.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_RETRY_DELAY_MS = exports.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_TIMEOUT_MS = exports.DEFAULT_WAIT_FOR_ROOT_TRANSACTION = exports.DEFAULT_FIND_TX_MAX_DEPTH = exports.DEFAULT_FIND_TX_ARCHIVAL = exports.DEFAULT_MAX_SCANNED_TRANSACTIONS = exports.DEFAULT_FIND_TX_LIMIT = exports.DEFAULT_RETRY_DELAY_MS = exports.DEFAULT_RETRY_MAX_COUNT = exports.DEFAULT_HTTP_CLIENT_TIMEOUT_MS = exports.DEFAULT_TIMEOUT_MS = exports.TON_BURN_ADDRESS = exports.MINUTE = exports.FIVE_MINUTES = exports.TAC_DECIMALS = exports.TON_DECIMALS = exports.ONE_YEAR_SECONDS = exports.FIFTEEN_MINUTES = exports.TAC_SYMBOL = exports.TON_SYMBOL = exports.MAX_MSG_DEPTH = exports.MAX_HIGHLOAD_GROUP_MSG_NUM = exports.MAX_EXT_MSG_SIZE = exports.SOLIDITY_METHOD_NAME_REGEX = exports.SOLIDITY_SIGNATURE_REGEX = exports.DEFAULT_DELAY = exports.MAX_ITERATION_COUNT = exports.NFT_TRANSFER_FORWARD_TON_AMOUNT = exports.JETTON_TRANSFER_FORWARD_TON_AMOUNT = void 0;
3
+ exports.IGNORE_OPCODE = exports.IGNORE_MSG_VALUE_1_NANO = exports.DEFAULT_RETRY_ON_NOT_FOUND_DELAY_MS = exports.DEFAULT_RETRY_ON_NOT_FOUND_RETRIES = exports.DEFAULT_RETRY_ON_NOT_FOUND = exports.DEFAULT_FIND_TX_MAX_DEPTH = exports.DEFAULT_FIND_TX_ARCHIVAL = exports.DEFAULT_MAX_SCANNED_TRANSACTIONS = exports.DEFAULT_FIND_TX_LIMIT = exports.DEFAULT_WAIT_DELAY_MS = exports.DEFAULT_WAIT_MAX_ATTEMPTS = exports.DEFAULT_WAIT_TIMEOUT_MS = exports.DEFAULT_RETRY_DELAY_MS = exports.DEFAULT_RETRY_MAX_COUNT = exports.DEFAULT_HTTP_CLIENT_TIMEOUT_MS = exports.TON_BURN_ADDRESS = exports.MINUTE = exports.FIVE_MINUTES = exports.TAC_DECIMALS = exports.TON_DECIMALS = exports.ONE_YEAR_SECONDS = exports.FIFTEEN_MINUTES = exports.TAC_SYMBOL = exports.TON_SYMBOL = exports.MAX_MSG_DEPTH = exports.MAX_HIGHLOAD_GROUP_MSG_NUM = exports.MAX_EXT_MSG_SIZE = exports.SOLIDITY_METHOD_NAME_REGEX = exports.SOLIDITY_SIGNATURE_REGEX = exports.DEFAULT_DELAY = exports.MAX_ITERATION_COUNT = exports.NFT_TRANSFER_FORWARD_TON_AMOUNT = exports.JETTON_TRANSFER_FORWARD_TON_AMOUNT = void 0;
4
4
  const ton_1 = require("@ton/ton");
5
5
  exports.JETTON_TRANSFER_FORWARD_TON_AMOUNT = (0, ton_1.toNano)(0.2);
6
6
  exports.NFT_TRANSFER_FORWARD_TON_AMOUNT = (0, ton_1.toNano)(0.3);
@@ -20,17 +20,19 @@ exports.TAC_DECIMALS = 18;
20
20
  exports.FIVE_MINUTES = 5 * 60 * 1000;
21
21
  exports.MINUTE = 60 * 1000;
22
22
  exports.TON_BURN_ADDRESS = 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c';
23
- exports.DEFAULT_TIMEOUT_MS = 300000; // 5 minute
24
23
  exports.DEFAULT_HTTP_CLIENT_TIMEOUT_MS = 30000;
25
24
  exports.DEFAULT_RETRY_MAX_COUNT = 5;
26
25
  exports.DEFAULT_RETRY_DELAY_MS = 1000;
26
+ exports.DEFAULT_WAIT_TIMEOUT_MS = 300000; // 5 minutes
27
+ exports.DEFAULT_WAIT_MAX_ATTEMPTS = 30;
28
+ exports.DEFAULT_WAIT_DELAY_MS = 10000; // 10 seconds
27
29
  exports.DEFAULT_FIND_TX_LIMIT = 100;
28
30
  exports.DEFAULT_MAX_SCANNED_TRANSACTIONS = 100;
29
31
  exports.DEFAULT_FIND_TX_ARCHIVAL = true;
30
32
  exports.DEFAULT_FIND_TX_MAX_DEPTH = 10;
31
- exports.DEFAULT_WAIT_FOR_ROOT_TRANSACTION = true;
32
- exports.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_TIMEOUT_MS = exports.MINUTE;
33
- exports.DEFAULT_WAIT_FOR_ROOT_TRANSACTION_RETRY_DELAY_MS = 1000;
33
+ exports.DEFAULT_RETRY_ON_NOT_FOUND = true;
34
+ exports.DEFAULT_RETRY_ON_NOT_FOUND_RETRIES = 10;
35
+ exports.DEFAULT_RETRY_ON_NOT_FOUND_DELAY_MS = 5000;
34
36
  exports.IGNORE_MSG_VALUE_1_NANO = 1n;
35
37
  exports.IGNORE_OPCODE = [
36
38
  0xd53276db, // Excess
@@ -35,96 +35,78 @@ class OperationTracker {
35
35
  this.logger = logger;
36
36
  }
37
37
  async getOperationIdByTransactionHash(transactionHash, waitOptions) {
38
- this.logger.debug(`Getting operation ID for transactionHash: ${(0, Utils_1.formatObjectForLogging)(transactionHash)}`);
39
38
  const requestFn = async () => {
40
39
  let lastError;
41
40
  for (const client of this.clients) {
42
41
  try {
43
42
  const id = await client.getOperationIdByTransactionHash(transactionHash);
44
- this.logger.debug(`Operation ID ${id == '' ? 'does not exist' : 'retrieved successfully'}`);
45
43
  return id;
46
44
  }
47
45
  catch (error) {
48
- this.logger.warn(`Failed to get OperationId by transactionHash using one of the endpoints`);
49
46
  lastError = error;
50
47
  }
51
48
  }
52
- this.logger.error('All endpoints failed to get operation id by transactionHash');
53
49
  throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
54
50
  };
55
51
  return waitOptions === null
56
52
  ? await requestFn()
57
- : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, 'OperationTracker: Getting operation ID by transaction hash');
53
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting operation ID by transaction hash ${(0, Utils_1.formatObjectForLogging)(transactionHash)}`);
58
54
  }
59
55
  async getOperationType(operationId, waitOptions) {
60
- this.logger.debug(`Getting operation type for ${(0, Utils_1.formatObjectForLogging)(operationId)}`);
61
56
  const requestFn = async () => {
62
57
  let lastError;
63
58
  for (const client of this.clients) {
64
59
  try {
65
60
  const type = await client.getOperationType(operationId);
66
- this.logger.debug(`Operation retrieved successfully`);
67
61
  return type;
68
62
  }
69
63
  catch (error) {
70
- this.logger.warn(`Failed to get operationType using one of the endpoints`);
71
64
  lastError = error;
72
65
  }
73
66
  }
74
- this.logger.error('All endpoints failed to get operation type');
75
67
  throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
76
68
  };
77
69
  return waitOptions === null
78
70
  ? await requestFn()
79
- : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, 'OperationTracker: Getting operation type');
71
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting operation type for ${(0, Utils_1.formatObjectForLogging)(operationId)}`);
80
72
  }
81
73
  async getOperationId(transactionLinker, waitOptions) {
82
- this.logger.debug(`Getting operation ID for transaction linker: ${(0, Utils_1.formatObjectForLogging)(transactionLinker)}`);
83
74
  const requestFn = async () => {
84
75
  let lastError;
85
76
  for (const client of this.clients) {
86
77
  try {
87
78
  const id = await client.getOperationId(transactionLinker);
88
- this.logger.debug(`Operation ID ${id == '' ? 'does not exist' : 'retrieved successfully'}`);
89
79
  return id;
90
80
  }
91
81
  catch (error) {
92
- this.logger.warn(`Failed to get OperationId using one of the endpoints`);
93
82
  lastError = error;
94
83
  }
95
84
  }
96
- this.logger.error('All endpoints failed to get operation id');
97
85
  throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
98
86
  };
99
87
  return waitOptions === null
100
88
  ? await requestFn()
101
- : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, 'OperationTracker: Getting operation ID by transaction linker');
89
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting operation ID by transaction linker ${(0, Utils_1.formatObjectForLogging)(transactionLinker)}`);
102
90
  }
103
91
  async getOperationIdsByShardsKeys(shardsKeys, caller, waitOptions, chunkSize = 100) {
104
- this.logger.debug(`Getting operation IDs for shards keys: ${(0, Utils_1.formatObjectForLogging)(shardsKeys)}`);
105
- this.logger.debug(`Caller: ${caller}, Chunk size: ${chunkSize}`);
106
92
  const requestFn = async () => {
107
93
  let lastError;
108
94
  for (const client of this.clients) {
109
95
  try {
110
96
  const result = await client.getOperationIdsByShardsKeys(shardsKeys, caller, chunkSize);
111
- this.logger.debug(`Operation IDs by shards keys retrieved successfully`);
112
97
  return result;
113
98
  }
114
99
  catch (error) {
115
- this.logger.warn(`Failed to get OperationIds using one of the endpoints`);
116
100
  lastError = error;
117
101
  }
118
102
  }
119
- this.logger.error('All endpoints failed to get operation ids by shards keys');
120
103
  throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
121
104
  };
122
105
  return waitOptions === null
123
106
  ? await requestFn()
124
- : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, 'OperationTracker: Getting operation IDs by shards keys');
107
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting operation IDs by shards keys ${(0, Utils_1.formatObjectForLogging)(shardsKeys)} caller=${caller} chunkSize=${chunkSize}`);
125
108
  }
126
109
  async getStageProfiling(operationId, waitOptions) {
127
- this.logger.debug(`Getting stage profiling for operation ${operationId}`);
128
110
  const requestFn = async () => {
129
111
  let lastError;
130
112
  for (const client of this.clients) {
@@ -132,72 +114,57 @@ class OperationTracker {
132
114
  const map = await client.getStageProfilings([operationId]);
133
115
  const result = map[operationId];
134
116
  if (!result) {
135
- this.logger.warn(`No stageProfiling data for operationId=${operationId}`);
136
117
  throw new Error(`No stageProfiling data for operationId=${operationId}`);
137
118
  }
138
- this.logger.debug(`Stage profiling retrieved successfully`);
139
119
  return result;
140
120
  }
141
121
  catch (error) {
142
- this.logger.warn(`Failed to get stage profiling using one of the endpoints`);
143
122
  lastError = error;
144
123
  }
145
124
  }
146
- this.logger.error('All endpoints failed to get stage profiling');
147
125
  throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
148
126
  };
149
127
  return waitOptions === null
150
128
  ? await requestFn()
151
- : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, 'OperationTracker: Getting stage profiling');
129
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting stage profiling for operation ${operationId}`);
152
130
  }
153
131
  async getStageProfilings(operationIds, waitOptions, chunkSize = 100) {
154
- this.logger.debug(`Getting stage profilings for operations: ${operationIds.join(', ')}`);
155
- this.logger.debug(`Chunk size: ${chunkSize}`);
156
132
  const requestFn = async () => {
157
133
  let lastError;
158
134
  for (const client of this.clients) {
159
135
  try {
160
136
  const result = await client.getStageProfilings(operationIds, chunkSize);
161
- this.logger.debug(`Stage profilings retrieved successfully`);
162
137
  return result;
163
138
  }
164
139
  catch (error) {
165
- this.logger.warn(`Failed to get stage profilings using one of the endpoints`);
166
140
  lastError = error;
167
141
  }
168
142
  }
169
- this.logger.error('All endpoints failed to get stage profilings');
170
143
  throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
171
144
  };
172
145
  return waitOptions === null
173
146
  ? await requestFn()
174
- : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, 'OperationTracker: Getting stage profilings');
147
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting stage profilings for operations: ${operationIds.join(', ')} chunkSize=${chunkSize}`);
175
148
  }
176
149
  async getOperationStatuses(operationIds, waitOptions, chunkSize = 100) {
177
- this.logger.debug(`Getting operation statuses for operations: ${(0, Utils_1.formatObjectForLogging)(operationIds)}`);
178
- this.logger.debug(`Chunk size: ${chunkSize}`);
179
150
  const requestFn = async () => {
180
151
  let lastError;
181
152
  for (const client of this.clients) {
182
153
  try {
183
154
  const result = await client.getOperationStatuses(operationIds, chunkSize);
184
- this.logger.debug(`Operation statuses retrieved successfully`);
185
155
  return result;
186
156
  }
187
157
  catch (error) {
188
- this.logger.warn(`Failed to get operation statuses using one of the endpoints`);
189
158
  lastError = error;
190
159
  }
191
160
  }
192
- this.logger.error('All endpoints failed to get operation statuses');
193
161
  throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
194
162
  };
195
163
  return waitOptions === null
196
164
  ? await requestFn()
197
- : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, 'OperationTracker: Getting operation statuses');
165
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting operation statuses for operations: ${(0, Utils_1.formatObjectForLogging)(operationIds)} chunkSize=${chunkSize}`);
198
166
  }
199
167
  async getOperationStatus(operationId, waitOptions) {
200
- this.logger.debug(`Getting operation status for ${(0, Utils_1.formatObjectForLogging)(operationId)}`);
201
168
  const requestFn = async () => {
202
169
  let lastError;
203
170
  for (const client of this.clients) {
@@ -205,27 +172,23 @@ class OperationTracker {
205
172
  const map = await client.getOperationStatuses([operationId]);
206
173
  const result = map[operationId];
207
174
  if (!result) {
208
- this.logger.warn(`No operation status for operationId=${operationId}`);
209
175
  throw new Error(`No operation status for operationId=${operationId}`);
210
176
  }
211
177
  return result;
212
178
  }
213
179
  catch (error) {
214
- this.logger.warn(`Failed to get operation status using one of the endpoints`);
215
180
  lastError = error;
216
181
  }
217
182
  }
218
- this.logger.error('All endpoints failed to get operation status');
219
183
  throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
220
184
  };
221
185
  const status = waitOptions === null
222
186
  ? await requestFn()
223
- : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, 'OperationTracker: Getting operation status');
187
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting operation status for ${(0, Utils_1.formatObjectForLogging)(operationId)}`);
224
188
  this.logger.debug(`operation status resolved stage=${status.stage ?? 'unknown'} success=${(String(status.success))}`);
225
189
  return status;
226
190
  }
227
191
  async getSimplifiedOperationStatus(transactionLinker) {
228
- this.logger.debug(`Getting simplified operation status for transaction linker: ${(0, Utils_1.formatObjectForLogging)(transactionLinker)}`);
229
192
  const operationId = await this.getOperationId(transactionLinker);
230
193
  if (operationId == '') {
231
194
  this.logger.warn('Operation ID not found');
@@ -244,71 +207,59 @@ class OperationTracker {
244
207
  if (params.value <= 0n) {
245
208
  throw instances_1.convertCurrencyNegativeOrZeroValueError;
246
209
  }
247
- this.logger.debug(`Converting currency: ${(0, Utils_1.formatObjectForLogging)(params)}`);
248
210
  const requestFn = async () => {
249
211
  let lastError;
250
212
  for (const client of this.clients) {
251
213
  try {
252
214
  const result = await client.convertCurrency(params);
253
- this.logger.debug(`Conversion result retrieved successfully`);
254
215
  return result;
255
216
  }
256
217
  catch (error) {
257
- this.logger.warn(`Failed to convert currency using one of the endpoints`);
258
218
  lastError = error;
259
219
  }
260
220
  }
261
- this.logger.error('All endpoints failed to convert currency');
262
221
  throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
263
222
  };
264
223
  return waitOptions === null
265
224
  ? await requestFn()
266
- : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, 'OperationTracker: Converting currency');
225
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Converting currency ${(0, Utils_1.formatObjectForLogging)(params)}`);
267
226
  }
268
227
  async simulateTACMessage(params, waitOptions) {
269
228
  Validator_1.Validator.validateTACSimulationParams(params);
270
- this.logger.debug(`Simulating TAC message: ${(0, Utils_1.formatObjectForLogging)(params)}`);
271
229
  const requestFn = async () => {
272
230
  let lastError;
273
231
  for (const client of this.clients) {
274
232
  try {
275
233
  const result = await client.simulateTACMessage(params);
276
- this.logger.debug(`Simulation result retrieved successfully`);
277
234
  return result;
278
235
  }
279
236
  catch (error) {
280
- this.logger.warn(`Failed to simulate TAC message using one of the endpoints`);
281
237
  lastError = error;
282
238
  }
283
239
  }
284
- this.logger.error('All endpoints failed to simulate TAC message');
285
240
  throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
286
241
  };
287
242
  return waitOptions === null
288
243
  ? await requestFn()
289
- : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, 'OperationTracker: Simulating TAC message');
244
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Simulating TAC message ${(0, Utils_1.formatObjectForLogging)(params)}`);
290
245
  }
291
246
  async getTVMExecutorFee(params, waitOptions) {
292
- this.logger.debug(`get TVM executor fee: ${(0, Utils_1.formatObjectForLogging)(params)}`);
293
247
  const requestFn = async () => {
294
248
  let lastError;
295
249
  for (const client of this.clients) {
296
250
  try {
297
251
  const result = await client.getTVMExecutorFee(params);
298
- this.logger.debug(`Suggested TVM executor fee retrieved successfully`);
299
252
  return result;
300
253
  }
301
254
  catch (error) {
302
- this.logger.warn(`Failed to get TVM executor fee using one of the endpoints`);
303
255
  lastError = error;
304
256
  }
305
257
  }
306
- this.logger.error('All endpoints failed to get TVM executor fee');
307
258
  throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
308
259
  };
309
260
  return waitOptions === null
310
261
  ? await requestFn()
311
- : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, 'OperationTracker: Getting TVM executor fee');
262
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting TVM executor fee ${(0, Utils_1.formatObjectForLogging)(params)}`);
312
263
  }
313
264
  }
314
265
  exports.OperationTracker = OperationTracker;
@@ -42,7 +42,7 @@ class TacSdk {
42
42
  throw new Error(`Unsupported network: ${network}`);
43
43
  }
44
44
  const config = await Configuration_1.Configuration.create(network, artifacts, sdkParams.TONParams, sdkParams.TACParams, sdkParams.customLiteSequencerEndpoints, delay, logger, passLoggerToOpeners);
45
- const operationTracker = new OperationTracker_1.OperationTracker(network, config.liteSequencerEndpoints);
45
+ const operationTracker = new OperationTracker_1.OperationTracker(network, config.liteSequencerEndpoints, logger);
46
46
  const explorerClient = new TacExplorerClient_1.TacExplorerClient(artifacts.TAC_EXPLORER_API_ENDPOINT);
47
47
  const simulator = new Simulator_1.Simulator(config, operationTracker, logger);
48
48
  const tonTransactionManager = new TONTransactionManager_1.TONTransactionManager(config, simulator, operationTracker, logger);
@@ -157,7 +157,6 @@ async function waitUntilSuccess(options = {}, operation, operationDescription, .
157
157
  const successCheck = options.successCheck;
158
158
  const context = options.context;
159
159
  const contextPrefix = operationDescription ? `[${operationDescription}] ` : '';
160
- options.logger?.debug(`${contextPrefix}Starting wait for success with timeout=${timeout}ms, maxAttempts=${maxAttempts}, delay=${delay}ms`);
161
160
  const startTime = Date.now();
162
161
  let attempt = 1;
163
162
  while (true) {
@@ -171,8 +170,7 @@ async function waitUntilSuccess(options = {}, operation, operationDescription, .
171
170
  if (successCheck && !successCheck(result, context)) {
172
171
  throw new Error(`Result is not successful: ${formatObjectForLogging(result)}`);
173
172
  }
174
- options.logger?.debug(`${contextPrefix}Attempt ${attempt} successful`);
175
- // Execute custom onSuccess callback if provided
173
+ options.logger?.debug(`${contextPrefix}Success (attempt ${attempt}/${maxAttempts})`);
176
174
  if (options.onSuccess) {
177
175
  try {
178
176
  await options.onSuccess(result, context);
@@ -197,7 +195,11 @@ async function waitUntilSuccess(options = {}, operation, operationDescription, .
197
195
  options.logger?.debug(`${contextPrefix}${pendingMessage}`);
198
196
  }
199
197
  else {
200
- options.logger?.debug(`${contextPrefix}attempt=${attempt}/${maxAttempts} failed; retry_in=${delay}ms; error=${String(error)}`);
198
+ let errorMessage = error instanceof Error ? error.message : String(error);
199
+ if (errorMessage.includes('<!doctype html>') || errorMessage.includes('<html')) {
200
+ errorMessage = errorMessage.replace(/<!doctype html>[\s\S]*?<\/html>/gi, '[HTML response]');
201
+ }
202
+ options.logger?.debug(`${contextPrefix}attempt=${attempt}/${maxAttempts} failed; retry_in=${delay}ms; error=${errorMessage}`);
201
203
  }
202
204
  await (0, exports.sleep)(delay);
203
205
  attempt++;
@@ -496,11 +496,21 @@ export type TrackTransactionTreeParams = {
496
496
  */
497
497
  direction?: 'forward' | 'backward' | 'both';
498
498
  /**
499
- * Internal option: wait for the root transaction to appear before failing with `not_found`.
500
- * Useful right after sending a message when transaction indexing is eventually consistent.
499
+ * Retry transaction lookup when `not_found` error occurs.
500
+ * Useful when transaction indexing has delays or when transactions appear gradually.
501
501
  * @default true
502
502
  */
503
- waitForRootTransaction?: boolean;
503
+ retryOnNotFound?: boolean;
504
+ /**
505
+ * Delay in milliseconds between retry attempts for transaction lookup
506
+ * @default 5000
507
+ */
508
+ retryDelayMs?: number;
509
+ /**
510
+ * Number of retry attempts for transaction lookup
511
+ * @default 10
512
+ */
513
+ retries?: number;
504
514
  };
505
515
  /**
506
516
  * Details about a transaction validation error
@@ -570,6 +580,8 @@ export type GetTransactionsOptions = {
570
580
  timeoutMs?: number;
571
581
  /** Delay between retry attempts in milliseconds */
572
582
  retryDelayMs?: number;
583
+ /** Number of retry attempts */
584
+ retries?: number;
573
585
  /** Internal scan guard: maximum transactions to inspect while traversing history */
574
586
  maxScannedTransactions?: number;
575
587
  };
@@ -59,9 +59,9 @@ var TokenSymbol;
59
59
  TokenSymbol["TON_SYMBOL"] = "TON";
60
60
  })(TokenSymbol || (exports.TokenSymbol = TokenSymbol = {}));
61
61
  exports.defaultWaitOptions = {
62
- timeout: Consts_1.DEFAULT_TIMEOUT_MS,
63
- maxAttempts: Consts_1.DEFAULT_RETRY_MAX_COUNT,
64
- delay: Consts_1.DEFAULT_RETRY_DELAY_MS,
62
+ timeout: Consts_1.DEFAULT_WAIT_TIMEOUT_MS,
63
+ maxAttempts: Consts_1.DEFAULT_WAIT_MAX_ATTEMPTS,
64
+ delay: Consts_1.DEFAULT_WAIT_DELAY_MS,
65
65
  };
66
66
  var Origin;
67
67
  (function (Origin) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonappchain/sdk",
3
- "version": "0.7.2-alpha-21",
3
+ "version": "0.7.2-alpha-22",
4
4
  "repository": "https://github.com/TacBuild/tac-sdk.git",
5
5
  "author": "TAC. <developers@tac>",
6
6
  "license": "MIT",