@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.
- package/dist/src/adapters/BaseContractOpener.d.ts +2 -2
- package/dist/src/adapters/BaseContractOpener.js +40 -43
- package/dist/src/adapters/RetryableContractOpener.js +2 -3
- package/dist/src/errors/instances.js +8 -4
- package/dist/src/sdk/Consts.d.ts +6 -4
- package/dist/src/sdk/Consts.js +7 -5
- package/dist/src/sdk/OperationTracker.js +11 -60
- package/dist/src/sdk/TacSdk.js +1 -1
- package/dist/src/sdk/Utils.js +6 -4
- package/dist/src/structs/Struct.d.ts +15 -3
- package/dist/src/structs/Struct.js +3 -3
- package/package.json +1 -1
|
@@ -62,9 +62,9 @@ export declare abstract class BaseContractOpener implements ContractOpener {
|
|
|
62
62
|
*/
|
|
63
63
|
private findTransactionByHashType;
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
65
|
+
* Find transaction with retry logic
|
|
66
66
|
*/
|
|
67
|
-
private
|
|
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
|
-
*
|
|
296
|
+
* Find transaction with retry logic
|
|
297
297
|
*/
|
|
298
|
-
async
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
-
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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',
|
|
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 = {
|
|
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 =
|
|
387
|
-
? await this.
|
|
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}
|
|
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;
|
package/dist/src/sdk/Consts.d.ts
CHANGED
|
@@ -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
|
|
28
|
-
export declare const
|
|
29
|
-
export declare const
|
|
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[];
|
package/dist/src/sdk/Consts.js
CHANGED
|
@@ -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.
|
|
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.
|
|
32
|
-
exports.
|
|
33
|
-
exports.
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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;
|
package/dist/src/sdk/TacSdk.js
CHANGED
|
@@ -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);
|
package/dist/src/sdk/Utils.js
CHANGED
|
@@ -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}
|
|
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
|
-
|
|
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
|
-
*
|
|
500
|
-
* Useful
|
|
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
|
-
|
|
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.
|
|
63
|
-
maxAttempts: Consts_1.
|
|
64
|
-
delay: Consts_1.
|
|
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) {
|