@tonappchain/sdk 0.7.3-rc5 → 0.7.3-rc7

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.
@@ -1,8 +1,9 @@
1
1
  import { SandboxContract } from '@ton/sandbox';
2
+ import type { Message } from '@ton/ton';
2
3
  import { Address, Contract, OpenedContract, Transaction } from '@ton/ton';
3
4
  import { ContractOpener, ILogger } from '../interfaces';
4
5
  import { AddressInformation, GetTransactionsOptions } from '../structs/Struct';
5
- import { ContractState, TrackTransactionTreeParams, TrackTransactionTreeResult } from '../structs/Struct';
6
+ import { ContractState, TrackTransactionTreeParams, TrackTransactionTreeResult, TransactionValidationError } from '../structs/Struct';
6
7
  /**
7
8
  * Base class for ContractOpener implementations with common functionality
8
9
  */
@@ -56,15 +57,15 @@ export declare abstract class BaseContractOpener implements ContractOpener {
56
57
  /**
57
58
  * Validate transaction phases and return error details
58
59
  */
59
- private validateTransactionWithResult;
60
+ protected validateTransactionWithResult(tx: Transaction, ignoreOpcodeList: number[]): TransactionValidationError | null;
60
61
  /**
61
62
  * Find transaction by hash type
62
63
  */
63
- private findTransactionByHashType;
64
+ protected findTransactionByHashType(address: Address, hash: string, hashType: 'unknown' | 'in' | 'out' | undefined, opts: GetTransactionsOptions, message?: Message): Promise<Transaction | null>;
64
65
  /**
65
66
  * Find transaction with retry logic
66
67
  */
67
- private findTransactionWithRetry;
68
+ protected findTransactionWithRetry(address: Address, hash: string, hashType: 'unknown' | 'in' | 'out' | undefined, opts: GetTransactionsOptions, depth: number, message?: Message): Promise<Transaction | null>;
68
69
  /**
69
70
  * Track transaction tree and validate all transactions
70
71
  */
@@ -27,24 +27,33 @@ class BaseContractOpener {
27
27
  */
28
28
  async scanTransactionHistory(addr, opts, predicate) {
29
29
  const limit = opts?.limit ?? Consts_1.DEFAULT_FIND_TX_LIMIT;
30
- const inclusive = opts?.inclusive ?? true;
30
+ const toLtInclusive = opts?.inclusive ?? true;
31
31
  const toLt = opts?.to_lt ? BigInt(opts.to_lt) : undefined;
32
32
  let currentLt = opts?.lt;
33
33
  let currentHash = opts?.hash ? (0, Utils_1.normalizeHashToBase64)(opts.hash) : undefined;
34
- const seenCursors = new Set();
34
+ let requestInclusive = toLtInclusive;
35
+ const seenRequests = new Set();
35
36
  let scannedTransactions = 0;
36
37
  const maxScannedTransactions = opts?.maxScannedTransactions ?? Consts_1.DEFAULT_MAX_SCANNED_TRANSACTIONS;
37
38
  while (true) {
38
- const list = await this.getTransactions(addr, {
39
+ const requestKey = `${currentLt ?? ''}:${currentHash ?? ''}:${requestInclusive}`;
40
+ if (seenRequests.has(requestKey)) {
41
+ break;
42
+ }
43
+ seenRequests.add(requestKey);
44
+ const requestOpts = {
39
45
  limit,
40
46
  lt: currentLt,
41
47
  hash: currentHash,
42
48
  to_lt: opts?.to_lt,
43
- inclusive,
44
- archival: opts?.archival ?? Consts_1.DEFAULT_FIND_TX_ARCHIVAL,
49
+ inclusive: requestInclusive,
45
50
  timeoutMs: opts?.timeoutMs,
46
51
  retryDelayMs: opts?.retryDelayMs,
47
- });
52
+ };
53
+ if (opts?.archival !== undefined) {
54
+ requestOpts.archival = opts.archival;
55
+ }
56
+ const list = await this.getTransactions(addr, requestOpts);
48
57
  if (list.length === 0) {
49
58
  break;
50
59
  }
@@ -54,7 +63,7 @@ class BaseContractOpener {
54
63
  currentHash &&
55
64
  firstTx.lt.toString() === currentLt &&
56
65
  firstTx.hash().toString('base64') === currentHash;
57
- if (firstTxMatchesCursor) {
66
+ if (firstTxMatchesCursor && !requestInclusive) {
58
67
  startIndex = 1;
59
68
  if (list.length === 1) {
60
69
  if (firstTx.prevTransactionLt === 0n) {
@@ -65,13 +74,9 @@ class BaseContractOpener {
65
74
  if (currentLt && BigInt(nextLt) >= BigInt(currentLt)) {
66
75
  break;
67
76
  }
68
- const cursorKey = `${nextLt}:${nextHash}`;
69
- if (seenCursors.has(cursorKey)) {
70
- break;
71
- }
72
- seenCursors.add(cursorKey);
73
77
  currentLt = nextLt;
74
78
  currentHash = nextHash;
79
+ requestInclusive = true;
75
80
  continue;
76
81
  }
77
82
  }
@@ -90,21 +95,17 @@ class BaseContractOpener {
90
95
  if (oldestTx.prevTransactionLt === 0n)
91
96
  break;
92
97
  if (toLt !== undefined) {
93
- if (inclusive ? oldestTx.lt <= toLt : oldestTx.lt < toLt)
98
+ if (toLtInclusive ? oldestTx.lt <= toLt : oldestTx.lt < toLt)
94
99
  break;
95
100
  }
96
101
  const nextLt = oldestTx.lt.toString();
97
102
  const nextHash = oldestTx.hash().toString('base64');
98
- if (currentLt && BigInt(nextLt) >= BigInt(currentLt)) {
103
+ if (currentLt && currentHash && nextLt === currentLt && nextHash === currentHash && !requestInclusive) {
99
104
  break;
100
105
  }
101
- const cursorKey = `${nextLt}:${nextHash}`;
102
- if (seenCursors.has(cursorKey)) {
103
- break;
104
- }
105
- seenCursors.add(cursorKey);
106
106
  currentLt = nextLt;
107
107
  currentHash = nextHash;
108
+ requestInclusive = false;
108
109
  }
109
110
  return null;
110
111
  }
@@ -281,37 +282,31 @@ class BaseContractOpener {
281
282
  /**
282
283
  * Find transaction by hash type
283
284
  */
284
- async findTransactionByHashType(address, hash, hashType, opts) {
285
- const searchOpts = { archival: true, ...opts };
285
+ async findTransactionByHashType(address, hash, hashType, opts, message) {
286
+ const targetHash = message ? (0, ton_1.beginCell)().store((0, ton_1.storeMessage)(message)).endCell().hash().toString('base64') : hash;
286
287
  if (hashType === 'in') {
287
- return this.getTransactionByInMsgHash(address, hash, searchOpts);
288
+ return this.getTransactionByInMsgHash(address, targetHash, opts);
288
289
  }
289
290
  else if (hashType === 'out') {
290
- return this.getTransactionByOutMsgHash(address, hash, searchOpts);
291
+ return this.getTransactionByOutMsgHash(address, targetHash, opts);
291
292
  }
292
293
  else {
293
- return this.getTransactionByHash(address, hash, searchOpts);
294
+ return this.getTransactionByHash(address, targetHash, opts);
294
295
  }
295
296
  }
296
297
  /**
297
298
  * Find transaction with retry logic
298
299
  */
299
- async findTransactionWithRetry(address, hash, hashType, opts, depth) {
300
+ async findTransactionWithRetry(address, hash, hashType, opts, depth, message) {
300
301
  const retryDelayMs = opts.retryDelayMs ?? Consts_1.DEFAULT_RETRY_ON_NOT_FOUND_DELAY_MS;
301
302
  const maxRetries = opts.retries ?? Consts_1.DEFAULT_RETRY_ON_NOT_FOUND_RETRIES;
302
303
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
303
- let errorMsg;
304
- try {
305
- const tx = await this.findTransactionByHashType(address, hash, hashType, opts);
306
- if (tx) {
307
- return tx;
308
- }
309
- }
310
- catch (error) {
311
- errorMsg = error instanceof Error ? error.message : String(error);
304
+ const tx = await this.findTransactionByHashType(address, hash, hashType, opts, message);
305
+ if (tx) {
306
+ return tx;
312
307
  }
313
308
  const isLastAttempt = attempt >= maxRetries;
314
- const reason = errorMsg ?? 'not found';
309
+ const reason = 'not found';
315
310
  const retryInfo = isLastAttempt ? '' : `, retrying in ${retryDelayMs}ms`;
316
311
  this.logger?.debug(`Transaction not found at depth ${depth} (attempt ${attempt + 1}/${maxRetries + 1}): ${reason}${retryInfo}`);
317
312
  if (isLastAttempt) {
@@ -357,7 +352,7 @@ class BaseContractOpener {
357
352
  direction: Struct_1.TransactionTreeDirection.FORWARD,
358
353
  retryOnNotFound: Consts_1.DEFAULT_RETRY_ON_NOT_FOUND,
359
354
  }) {
360
- 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 = Struct_1.TransactionTreeDirection.FORWARD, retryOnNotFound = Consts_1.DEFAULT_RETRY_ON_NOT_FOUND, retryDelayMs, retries, } = params;
355
+ 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, archival, rootLt, direction = Struct_1.TransactionTreeDirection.FORWARD, retryOnNotFound = Consts_1.DEFAULT_RETRY_ON_NOT_FOUND, retryDelayMs, retries, } = params;
361
356
  const parsedAddress = ton_1.Address.parse(address);
362
357
  const normalizedRootHash = (0, Utils_1.normalizeHashToBase64)(hash);
363
358
  const visitedSearchKeys = new Set();
@@ -365,25 +360,30 @@ class BaseContractOpener {
365
360
  let checkedCount = 0;
366
361
  const searchOpts = {
367
362
  limit,
368
- archival: true,
369
363
  maxScannedTransactions,
370
364
  retryDelayMs,
371
365
  retries,
372
366
  };
367
+ if (archival !== undefined) {
368
+ searchOpts.archival = archival;
369
+ }
373
370
  const queue = [
374
371
  { address: parsedAddress, hash: normalizedRootHash, depth: 0, hashType: 'unknown' },
375
372
  ];
376
373
  while (queue.length > 0) {
377
- const { hash: currentHash, depth: currentDepth, address: currentAddress, hashType } = queue.shift();
374
+ const { hash: currentHash, depth: currentDepth, address: currentAddress, hashType, message, } = queue.shift();
378
375
  const visitedKey = `${currentAddress.toString()}:${currentHash}:${hashType}`;
379
376
  if (visitedSearchKeys.has(visitedKey))
380
377
  continue;
381
378
  visitedSearchKeys.add(visitedKey);
379
+ const currentSearchOpts = currentDepth === 0 && hashType === 'unknown' && rootLt
380
+ ? { ...searchOpts, lt: rootLt, hash: currentHash, inclusive: true }
381
+ : searchOpts;
382
382
  const tx = retryOnNotFound
383
- ? await this.findTransactionWithRetry(currentAddress, currentHash, hashType, searchOpts, currentDepth)
384
- : await this.findTransactionByHashType(currentAddress, currentHash, hashType, searchOpts);
383
+ ? await this.findTransactionWithRetry(currentAddress, currentHash, hashType, currentSearchOpts, currentDepth, message)
384
+ : await this.findTransactionByHashType(currentAddress, currentHash, hashType, currentSearchOpts, message);
385
385
  if (!tx) {
386
- this.logger?.debug(`Transaction not found for hash: ${currentHash} (address=${currentAddress?.toString()}, hashType=${hashType ?? 'unknown'})`);
386
+ this.logger?.debug(`Transaction not found for hash: ${currentHash} (address=${currentAddress.toString()}, hashType=${hashType})`);
387
387
  return {
388
388
  success: false,
389
389
  checkedCount,
@@ -392,8 +392,8 @@ class BaseContractOpener {
392
392
  exitCode: 'N/A',
393
393
  resultCode: 'N/A',
394
394
  reason: 'not_found',
395
- address: currentAddress?.toString(),
396
- hashType: hashType ?? 'unknown',
395
+ address: currentAddress.toString(),
396
+ hashType,
397
397
  },
398
398
  };
399
399
  }
@@ -422,6 +422,7 @@ class BaseContractOpener {
422
422
  address: dst,
423
423
  depth: currentDepth + 1,
424
424
  hashType: 'in',
425
+ message: msg,
425
426
  });
426
427
  }
427
428
  }
@@ -433,6 +434,7 @@ class BaseContractOpener {
433
434
  address: tx.inMessage.info.src,
434
435
  depth: currentDepth + 1,
435
436
  hashType: 'out',
437
+ message: tx.inMessage,
436
438
  });
437
439
  }
438
440
  }
@@ -42,4 +42,4 @@ export declare class RetryableContractOpener implements ContractOpener {
42
42
  private createRetryableContract;
43
43
  private callMethodAcrossOpeners;
44
44
  }
45
- export declare function createDefaultRetryableOpener(tonRpcEndpoint: string, networkType: Network, maxRetries?: number, retryDelay?: number, logger?: ILogger): Promise<RetryableContractOpener>;
45
+ export declare function createDefaultRetryableOpener(tonRpcEndpoint: string, networkType: Network, maxRetries?: number, retryDelay?: number, logger?: ILogger, toncenterV3Endpoint?: string): Promise<RetryableContractOpener>;
@@ -7,6 +7,8 @@ const errors_1 = require("../errors");
7
7
  const instances_1 = require("../errors/instances");
8
8
  const Consts_1 = require("../sdk/Consts");
9
9
  const Struct_1 = require("../structs/Struct");
10
+ const ToncenterV3Indexer_1 = require("./ToncenterV3Indexer");
11
+ const ToncenterV3Opener_1 = require("./ToncenterV3Opener");
10
12
  const TonClient4Opener_1 = require("./TonClient4Opener");
11
13
  const TonClientOpener_1 = require("./TonClientOpener");
12
14
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -271,12 +273,21 @@ class RetryableContractOpener {
271
273
  }
272
274
  }
273
275
  exports.RetryableContractOpener = RetryableContractOpener;
274
- async function createDefaultRetryableOpener(tonRpcEndpoint, networkType, maxRetries = Consts_1.DEFAULT_RETRY_MAX_COUNT, retryDelay = Consts_1.DEFAULT_RETRY_DELAY_MS, logger) {
276
+ async function createDefaultRetryableOpener(tonRpcEndpoint, networkType, maxRetries = Consts_1.DEFAULT_RETRY_MAX_COUNT, retryDelay = Consts_1.DEFAULT_RETRY_DELAY_MS, logger, toncenterV3Endpoint) {
275
277
  const openers = [];
276
278
  const tonClient = new ton_1.TonClient({
277
279
  endpoint: new URL('api/v2/jsonRPC', tonRpcEndpoint).toString(),
278
280
  timeout: Consts_1.DEFAULT_HTTP_CLIENT_TIMEOUT_MS,
279
281
  });
282
+ if (toncenterV3Endpoint) {
283
+ openers.push({
284
+ opener: new ToncenterV3Opener_1.ToncenterV3Opener(new ToncenterV3Indexer_1.ToncenterV3Indexer(toncenterV3Endpoint), tonClient, logger),
285
+ retries: maxRetries,
286
+ retryDelay,
287
+ maxRetryDelay: Consts_1.DEFAULT_RETRY_MAX_DELAY_MS,
288
+ retryBackoffMultiplier: Consts_1.DEFAULT_RETRY_BACKOFF_MULTIPLIER,
289
+ });
290
+ }
280
291
  const opener = (0, TonClientOpener_1.tonClientOpener)(tonClient, logger);
281
292
  openers.push({
282
293
  opener,
@@ -1,3 +1,4 @@
1
+ import type { Message } from '@ton/ton';
1
2
  import { Address, Contract, OpenedContract, TonClient, Transaction } from '@ton/ton';
2
3
  import { ILogger } from '../interfaces';
3
4
  import { AddressInformation, ContractState, GetTransactionsOptions, Network } from '../structs/Struct';
@@ -12,6 +13,7 @@ export declare class TonClientOpener extends BaseContractOpener {
12
13
  getContractState(address: Address): Promise<ContractState>;
13
14
  getTransactions(address: Address, opts: GetTransactionsOptions): Promise<Transaction[]>;
14
15
  getAddressInformation(addr: Address): Promise<AddressInformation>;
16
+ protected findTransactionByHashType(address: Address, hash: string, hashType: 'unknown' | 'in' | 'out' | undefined, opts: GetTransactionsOptions, message?: Message): Promise<Transaction | null>;
15
17
  getConfig(): Promise<string>;
16
18
  }
17
19
  export declare function tonClientOpener(client: TonClient, logger?: ILogger): TonClientOpener;
@@ -38,7 +38,7 @@ class TonClientOpener extends BaseContractOpener_1.BaseContractOpener {
38
38
  hash: opts.hash ? (0, Utils_1.normalizeHashToBase64)(opts.hash) : undefined,
39
39
  to_lt: opts.to_lt,
40
40
  inclusive: opts.inclusive,
41
- archival: opts.archival,
41
+ ...(opts.archival === undefined ? {} : { archival: opts.archival }),
42
42
  };
43
43
  return this.client.getTransactions(address, clientOpts);
44
44
  }
@@ -51,6 +51,40 @@ class TonClientOpener extends BaseContractOpener_1.BaseContractOpener {
51
51
  },
52
52
  };
53
53
  }
54
+ async findTransactionByHashType(address, hash, hashType, opts, message) {
55
+ if (opts.archival === true && message?.info.type === 'internal') {
56
+ const { src, dest, createdLt } = message.info;
57
+ const targetHash = (0, Utils_1.normalizeHashToBase64)(hash);
58
+ if (hashType === 'in') {
59
+ try {
60
+ const tx = await this.client.tryLocateResultTx(src, dest, createdLt.toString());
61
+ if (tx.inMessage &&
62
+ (0, ton_1.beginCell)().store((0, ton_1.storeMessage)(tx.inMessage)).endCell().hash().toString('base64') ===
63
+ targetHash) {
64
+ return tx;
65
+ }
66
+ }
67
+ catch {
68
+ // Keep the regular hash scan semantics when Toncenter cannot locate a delivered result.
69
+ }
70
+ }
71
+ else if (hashType === 'out') {
72
+ try {
73
+ const tx = await this.client.tryLocateSourceTx(src, dest, createdLt.toString());
74
+ for (const outMessage of tx.outMessages.values()) {
75
+ if ((0, ton_1.beginCell)().store((0, ton_1.storeMessage)(outMessage)).endCell().hash().toString('base64') ===
76
+ targetHash) {
77
+ return tx;
78
+ }
79
+ }
80
+ }
81
+ catch {
82
+ // Keep the regular hash scan semantics when Toncenter cannot locate the source.
83
+ }
84
+ }
85
+ }
86
+ return super.findTransactionByHashType(address, hash, hashType, opts, message);
87
+ }
54
88
  async getConfig() {
55
89
  const info = await this.client.getMasterchainInfo();
56
90
  const url = new URL('getConfigAll', this.client.parameters.endpoint);
@@ -14,6 +14,7 @@ export declare class ToncenterV3Indexer implements IToncenterV3Indexer {
14
14
  * @returns Indexed transaction with owning account context, or null on 404 / empty result.
15
15
  */
16
16
  getTransactionByHash(transactionHash: string): Promise<ToncenterV3IndexedTransaction | null>;
17
+ getTransactionsByMessageHash(messageHash: string, direction: 'in' | 'out'): Promise<ToncenterV3IndexedTransaction[]>;
17
18
  /**
18
19
  * Queries Toncenter v3 indexed `/adjacentTransactions` endpoint by hash.
19
20
  * @param transactionHash TON transaction hash accepted by the indexer.
@@ -27,20 +27,41 @@ class ToncenterV3Indexer {
27
27
  const response = await this.httpClient.get(endpoint, {
28
28
  params: {
29
29
  hash: transactionHash,
30
- limit: 1,
30
+ limit: Consts_1.DEFAULT_FIND_TX_LIMIT,
31
31
  },
32
32
  transformResponse: [Utils_1.toCamelCaseTransformer],
33
33
  });
34
34
  return response.data.transactions?.[0] ?? null;
35
35
  }
36
36
  catch (error) {
37
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
- if (error?.response?.status === 404) {
37
+ if (error.response?.status === Consts_1.HTTP_NOT_FOUND_STATUS_CODE) {
39
38
  return null;
40
39
  }
41
40
  throw (0, errors_1.operationFetchError)(`request ${requestLabel} failed to resolve TON indexed transaction`, error);
42
41
  }
43
42
  }
43
+ async getTransactionsByMessageHash(messageHash, direction) {
44
+ const endpoint = this.endpoint.endsWith('/')
45
+ ? `${this.endpoint}transactionsByMessage`
46
+ : `${this.endpoint}/transactionsByMessage`;
47
+ try {
48
+ const { data } = await this.httpClient.get(endpoint, {
49
+ params: {
50
+ msg_hash: messageHash,
51
+ direction,
52
+ limit: Consts_1.DEFAULT_FIND_TX_LIMIT,
53
+ },
54
+ transformResponse: [Utils_1.toCamelCaseTransformer],
55
+ });
56
+ return data.transactions ?? [];
57
+ }
58
+ catch (error) {
59
+ if (error.response?.status === Consts_1.HTTP_NOT_FOUND_STATUS_CODE) {
60
+ return [];
61
+ }
62
+ throw (0, errors_1.operationFetchError)(`request GET ${endpoint} failed to resolve TON indexed transactions by message`, error);
63
+ }
64
+ }
44
65
  /**
45
66
  * Queries Toncenter v3 indexed `/adjacentTransactions` endpoint by hash.
46
67
  * @param transactionHash TON transaction hash accepted by the indexer.
@@ -59,8 +80,7 @@ class ToncenterV3Indexer {
59
80
  return response.data.transactions ?? [];
60
81
  }
61
82
  catch (error) {
62
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
- if (error?.response?.status === 404) {
83
+ if (error.response?.status === Consts_1.HTTP_NOT_FOUND_STATUS_CODE) {
64
84
  return [];
65
85
  }
66
86
  throw (0, errors_1.operationFetchError)(`request ${requestLabel} failed to resolve adjacent TON indexed transactions`, error);
@@ -86,20 +106,19 @@ class ToncenterV3Indexer {
86
106
  return rootTransaction;
87
107
  }
88
108
  const queue = [{ hash: rootTransaction.hash, depth: 0 }];
89
- const visitedHashes = new Set([(0, Utils_1.normalizeHashToHex)(rootTransaction.hash)]);
109
+ const visitedHashes = new Set([rootTransaction.hash]);
90
110
  let scannedTransactions = 0;
91
- while (queue.length > 0) {
92
- const { hash: currentHash, depth } = queue.shift();
111
+ for (let i = 0; i < queue.length; i++) {
112
+ const { hash: currentHash, depth } = queue[i];
93
113
  if (depth >= maxDepth || scannedTransactions >= maxScannedTransactions) {
94
114
  continue;
95
115
  }
96
116
  const adjacentTransactions = await this.getAdjacentTransactions(currentHash);
97
117
  for (const transaction of adjacentTransactions) {
98
- const normalizedHash = (0, Utils_1.normalizeHashToHex)(transaction.hash);
99
- if (visitedHashes.has(normalizedHash)) {
118
+ if (visitedHashes.has(transaction.hash)) {
100
119
  continue;
101
120
  }
102
- visitedHashes.add(normalizedHash);
121
+ visitedHashes.add(transaction.hash);
103
122
  scannedTransactions += 1;
104
123
  if (this.isCollectibleEventTransactionOnAccount(transaction, crossChainLayer)) {
105
124
  return transaction;
@@ -0,0 +1,11 @@
1
+ import { TonClient } from '@ton/ton';
2
+ import { ILogger, IToncenterV3Indexer } from '../interfaces';
3
+ import { TrackTransactionTreeParams, TrackTransactionTreeResult } from '../structs/Struct';
4
+ import { TonClientOpener } from './TonClientOpener';
5
+ export declare class ToncenterV3Opener extends TonClientOpener {
6
+ private readonly indexer;
7
+ constructor(indexer: IToncenterV3Indexer, client: TonClient, logger?: ILogger);
8
+ trackTransactionTreeWithResult(address: string, hash: string, params?: TrackTransactionTreeParams): Promise<TrackTransactionTreeResult>;
9
+ private findRootTransaction;
10
+ private validateIndexedTransactionWithResult;
11
+ }
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToncenterV3Opener = void 0;
4
+ const ton_1 = require("@ton/ton");
5
+ const Consts_1 = require("../sdk/Consts");
6
+ const Utils_1 = require("../sdk/Utils");
7
+ const Struct_1 = require("../structs/Struct");
8
+ const TonClientOpener_1 = require("./TonClientOpener");
9
+ class ToncenterV3Opener extends TonClientOpener_1.TonClientOpener {
10
+ constructor(indexer, client, logger) {
11
+ super(client, logger);
12
+ this.indexer = indexer;
13
+ }
14
+ async trackTransactionTreeWithResult(address, hash, params = {}) {
15
+ const { maxDepth = Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, direction = Struct_1.TransactionTreeDirection.FORWARD, retryOnNotFound = Consts_1.DEFAULT_RETRY_ON_NOT_FOUND, retryDelayMs = Consts_1.DEFAULT_RETRY_ON_NOT_FOUND_DELAY_MS, retries = Consts_1.DEFAULT_RETRY_ON_NOT_FOUND_RETRIES, } = params;
16
+ const rootAddress = ton_1.Address.parse(address);
17
+ const rootHash = (0, Utils_1.normalizeHashToBase64)(hash);
18
+ const attempts = retryOnNotFound ? retries + 1 : 1;
19
+ let rootTransaction = null;
20
+ for (let attempt = 0; attempt < attempts; attempt++) {
21
+ rootTransaction = await this.findRootTransaction(rootAddress, rootHash);
22
+ if (rootTransaction) {
23
+ break;
24
+ }
25
+ if (attempt < attempts - 1) {
26
+ await (0, Utils_1.sleep)(retryDelayMs);
27
+ }
28
+ }
29
+ if (!rootTransaction) {
30
+ return {
31
+ success: false,
32
+ checkedCount: 0,
33
+ error: {
34
+ txHash: rootHash,
35
+ exitCode: 'N/A',
36
+ resultCode: 'N/A',
37
+ reason: 'not_found',
38
+ address: rootAddress.toString(),
39
+ },
40
+ };
41
+ }
42
+ const queue = [{ transaction: rootTransaction, depth: 0 }];
43
+ const processedTxHashes = new Set();
44
+ let checkedCount = 0;
45
+ for (let i = 0; i < queue.length; i++) {
46
+ const { transaction: tx, depth } = queue[i];
47
+ if (processedTxHashes.has(tx.hash)) {
48
+ continue;
49
+ }
50
+ processedTxHashes.add(tx.hash);
51
+ checkedCount += 1;
52
+ const validationError = this.validateIndexedTransactionWithResult(tx);
53
+ if (validationError) {
54
+ return { success: false, checkedCount, error: validationError };
55
+ }
56
+ if (depth >= maxDepth) {
57
+ continue;
58
+ }
59
+ const adjacentTransactions = await this.indexer.getAdjacentTransactions(tx.hash);
60
+ for (const adjacentTransaction of adjacentTransactions) {
61
+ if ((direction !== Struct_1.TransactionTreeDirection.BACKWARD &&
62
+ tx.outMsgs.some((message) => message.hash && message.hash === adjacentTransaction.inMsg?.hash)) ||
63
+ (direction !== Struct_1.TransactionTreeDirection.FORWARD &&
64
+ adjacentTransaction.outMsgs.some((message) => message.hash && message.hash === tx.inMsg?.hash))) {
65
+ queue.push({ transaction: adjacentTransaction, depth: depth + 1 });
66
+ }
67
+ }
68
+ }
69
+ return { success: true, checkedCount };
70
+ }
71
+ async findRootTransaction(address, hash) {
72
+ const tx = await this.indexer.getTransactionByHash(hash);
73
+ if (tx && ton_1.Address.parse(tx.account).equals(address)) {
74
+ return tx;
75
+ }
76
+ for (const direction of ['in', 'out']) {
77
+ const transactions = await this.indexer.getTransactionsByMessageHash(hash, direction);
78
+ const transaction = transactions.find((tx) => ton_1.Address.parse(tx.account).equals(address));
79
+ if (transaction) {
80
+ return transaction;
81
+ }
82
+ }
83
+ return null;
84
+ }
85
+ validateIndexedTransactionWithResult(tx) {
86
+ const { description } = tx;
87
+ if (description?.type && description.type !== 'generic') {
88
+ return null;
89
+ }
90
+ const computePh = description?.computePh;
91
+ const action = description?.action;
92
+ const exitCode = computePh && !computePh.skipped ? computePh.exitCode ?? 'N/A' : 'N/A';
93
+ const resultCode = action ? action.resultCode ?? 'N/A' : 'N/A';
94
+ let reason = null;
95
+ if (description?.aborted) {
96
+ reason = 'aborted';
97
+ }
98
+ else if (!computePh) {
99
+ reason = 'compute_phase_missing';
100
+ }
101
+ else if (!computePh.skipped && (computePh.success !== true || computePh.exitCode !== 0)) {
102
+ reason = 'compute_phase_failed';
103
+ }
104
+ else if (action && (action.success !== true || action.resultCode !== 0)) {
105
+ reason = 'action_phase_failed';
106
+ }
107
+ return reason ? { txHash: tx.hash, exitCode, resultCode, reason } : null;
108
+ }
109
+ }
110
+ exports.ToncenterV3Opener = ToncenterV3Opener;
@@ -4,5 +4,6 @@ export * from './OpenerUtils';
4
4
  export * from './RetryableContractOpener';
5
5
  export * from './SandboxOpener';
6
6
  export * from './ToncenterV3Indexer';
7
+ export * from './ToncenterV3Opener';
7
8
  export * from './TonClient4Opener';
8
9
  export * from './TonClientOpener';
@@ -20,5 +20,6 @@ __exportStar(require("./OpenerUtils"), exports);
20
20
  __exportStar(require("./RetryableContractOpener"), exports);
21
21
  __exportStar(require("./SandboxOpener"), exports);
22
22
  __exportStar(require("./ToncenterV3Indexer"), exports);
23
+ __exportStar(require("./ToncenterV3Opener"), exports);
23
24
  __exportStar(require("./TonClient4Opener"), exports);
24
25
  __exportStar(require("./TonClientOpener"), exports);
@@ -15,6 +15,7 @@ export interface IToncenterV3Indexer {
15
15
  * @returns Indexed transaction with owning account context, or null if not found.
16
16
  */
17
17
  getTransactionByHash(transactionHash: string): Promise<ToncenterV3IndexedTransaction | null>;
18
+ getTransactionsByMessageHash(messageHash: string, direction: 'in' | 'out'): Promise<ToncenterV3IndexedTransaction[]>;
18
19
  /**
19
20
  * Resolves adjacent indexed transactions for the provided hash from the same linked chain of TON transactions.
20
21
  * The result may contain both parent and child transactions.
@@ -53,7 +53,7 @@ class Configuration {
53
53
  else {
54
54
  contractOpener =
55
55
  TONParams?.contractOpener ??
56
- (await (0, adapters_1.createDefaultRetryableOpener)(artifacts.TON_RPC_ENDPOINT_BY_TAC, network, Consts_1.DEFAULT_RETRY_MAX_COUNT, delay, passLoggerToOpeners ? logger : undefined));
56
+ (await (0, adapters_1.createDefaultRetryableOpener)(artifacts.TON_RPC_ENDPOINT_BY_TAC, network, Consts_1.DEFAULT_RETRY_MAX_COUNT, delay, passLoggerToOpeners ? logger : undefined, artifacts.TONCENTER_V3_INDEXER_ENDPOINT));
57
57
  settingsAddress = TONParams?.settingsAddress ?? artifacts.TON_SETTINGS_ADDRESS;
58
58
  }
59
59
  if (passLoggerToOpeners) {
@@ -41,7 +41,6 @@ export declare const DEFAULT_WAIT_MAX_ATTEMPTS = 30;
41
41
  export declare const DEFAULT_WAIT_DELAY_MS = 10000;
42
42
  export declare const DEFAULT_FIND_TX_LIMIT = 100;
43
43
  export declare const DEFAULT_MAX_SCANNED_TRANSACTIONS = 100;
44
- export declare const DEFAULT_FIND_TX_ARCHIVAL = true;
45
44
  export declare const DEFAULT_FIND_TX_MAX_DEPTH = 10;
46
45
  export declare const DEFAULT_RETRY_ON_NOT_FOUND = true;
47
46
  export declare const DEFAULT_RETRY_ON_NOT_FOUND_RETRIES = 10;
@@ -52,3 +51,4 @@ export declare const NFT_BRIDGE_AMOUNT = 1n;
52
51
  export declare const DEFAULT_EIP1559_PRIORITY_FEE = 0n;
53
52
  export declare const SHARDS_KEY_RANDOM_RANGE = 1000000000000000000;
54
53
  export declare const IGNORE_OPCODE: number[];
54
+ export declare const HTTP_NOT_FOUND_STATUS_CODE = 404;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CROSS_CHAIN_MESSAGE_VERSION_V1 = 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_BACKOFF_MULTIPLIER = exports.DEFAULT_RETRY_MAX_DELAY_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.FIXED_POINT_SHIFT = exports.DYNAMIC_JETTON_WALLET_CODE_HASHES = exports.USDT_JETTON_WALLET_CODE_HASH = exports.LEGACY_NFT_TRANSFER_WITH_FORWARD_OUTBOUND_MESSAGE_COUNT = exports.LEGACY_NFT_TRANSFER_BASE_OUTBOUND_MESSAGE_COUNT = exports.LEGACY_NFT_ITEM_MIN_TONS_FOR_STORAGE = exports.LEGACY_JETTON_WALLET_TRANSFER_GAS_AND_STORAGE = exports.LEGACY_JETTON_TRANSFER_WITH_FORWARD_OUTBOUND_MESSAGE_COUNT = exports.LEGACY_JETTON_TRANSFER_BASE_OUTBOUND_MESSAGE_COUNT = exports.LEGACY_JETTON_WALLET_GAS_CONSUMPTION_COUNT = exports.LEGACY_JETTON_WALLET_GAS_CONSUMPTION = exports.LEGACY_JETTON_WALLET_MIN_TONS_FOR_STORAGE = exports.LEGACY_STRICTLY_GREATER_THAN_FEE_EPSILON = exports.LEGACY_FORWARD_FEE_ESTIMATE_DENOMINATOR = exports.LEGACY_FORWARD_FEE_ESTIMATE_NUMERATOR = exports.NFT_TRANSFER_FORWARD_TON_AMOUNT = exports.JETTON_TRANSFER_FORWARD_TON_AMOUNT = void 0;
4
- exports.IGNORE_OPCODE = exports.SHARDS_KEY_RANDOM_RANGE = exports.DEFAULT_EIP1559_PRIORITY_FEE = exports.NFT_BRIDGE_AMOUNT = void 0;
3
+ exports.NFT_BRIDGE_AMOUNT = exports.CROSS_CHAIN_MESSAGE_VERSION_V1 = 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_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_BACKOFF_MULTIPLIER = exports.DEFAULT_RETRY_MAX_DELAY_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.FIXED_POINT_SHIFT = exports.DYNAMIC_JETTON_WALLET_CODE_HASHES = exports.USDT_JETTON_WALLET_CODE_HASH = exports.LEGACY_NFT_TRANSFER_WITH_FORWARD_OUTBOUND_MESSAGE_COUNT = exports.LEGACY_NFT_TRANSFER_BASE_OUTBOUND_MESSAGE_COUNT = exports.LEGACY_NFT_ITEM_MIN_TONS_FOR_STORAGE = exports.LEGACY_JETTON_WALLET_TRANSFER_GAS_AND_STORAGE = exports.LEGACY_JETTON_TRANSFER_WITH_FORWARD_OUTBOUND_MESSAGE_COUNT = exports.LEGACY_JETTON_TRANSFER_BASE_OUTBOUND_MESSAGE_COUNT = exports.LEGACY_JETTON_WALLET_GAS_CONSUMPTION_COUNT = exports.LEGACY_JETTON_WALLET_GAS_CONSUMPTION = exports.LEGACY_JETTON_WALLET_MIN_TONS_FOR_STORAGE = exports.LEGACY_STRICTLY_GREATER_THAN_FEE_EPSILON = exports.LEGACY_FORWARD_FEE_ESTIMATE_DENOMINATOR = exports.LEGACY_FORWARD_FEE_ESTIMATE_NUMERATOR = exports.NFT_TRANSFER_FORWARD_TON_AMOUNT = exports.JETTON_TRANSFER_FORWARD_TON_AMOUNT = void 0;
4
+ exports.HTTP_NOT_FOUND_STATUS_CODE = exports.IGNORE_OPCODE = exports.SHARDS_KEY_RANDOM_RANGE = exports.DEFAULT_EIP1559_PRIORITY_FEE = void 0;
5
5
  const ton_1 = require("@ton/ton");
6
6
  exports.JETTON_TRANSFER_FORWARD_TON_AMOUNT = (0, ton_1.toNano)(0.2);
7
7
  exports.NFT_TRANSFER_FORWARD_TON_AMOUNT = (0, ton_1.toNano)(0.3);
@@ -47,7 +47,6 @@ exports.DEFAULT_WAIT_MAX_ATTEMPTS = 30;
47
47
  exports.DEFAULT_WAIT_DELAY_MS = 10000; // 10 seconds
48
48
  exports.DEFAULT_FIND_TX_LIMIT = 100;
49
49
  exports.DEFAULT_MAX_SCANNED_TRANSACTIONS = 100;
50
- exports.DEFAULT_FIND_TX_ARCHIVAL = true;
51
50
  exports.DEFAULT_FIND_TX_MAX_DEPTH = 10;
52
51
  exports.DEFAULT_RETRY_ON_NOT_FOUND = true;
53
52
  exports.DEFAULT_RETRY_ON_NOT_FOUND_RETRIES = 10;
@@ -60,3 +59,4 @@ exports.SHARDS_KEY_RANDOM_RANGE = 1e18;
60
59
  exports.IGNORE_OPCODE = [
61
60
  0xd53276db, // Excess
62
61
  ];
62
+ exports.HTTP_NOT_FOUND_STATUS_CODE = 404;
@@ -7,7 +7,7 @@ export declare const createCrossChainLayerTvmMsgToEvmStep: (params: ContractFeeU
7
7
  export declare const createJettonWalletInternalTransferStep: (params: ContractFeeUsageParams, msgBits: number, msgCells: number) => TransactionFeeCalculationStep;
8
8
  export declare const createJettonWalletReceiveStep: (params: ContractFeeUsageParams, msgBits: number, msgCells: number) => TransactionFeeCalculationStep;
9
9
  export declare const createJettonWalletBurnStep: (params: ContractFeeUsageParams, msgBits: number, msgCells: number) => TransactionFeeCalculationStep;
10
- export declare const createJettonProxyOwnershipAssignedStep: (params: ContractFeeUsageParams, msgBits: number, msgCells: number) => TransactionFeeCalculationStep;
10
+ export declare const createJettonProxyTransferNotificationStep: (params: ContractFeeUsageParams, msgBits: number, msgCells: number) => TransactionFeeCalculationStep;
11
11
  export declare const createJettonMinterBurnNotificationStep: (params: ContractFeeUsageParams, msgBits: number, msgCells: number) => TransactionFeeCalculationStep;
12
12
  export declare const createNftItemSendStep: (params: ContractFeeUsageParams, msgBits: number, msgCells: number) => TransactionFeeCalculationStep;
13
13
  export declare const createNftItemBurnStep: (params: ContractFeeUsageParams, msgBits: number, msgCells: number) => TransactionFeeCalculationStep;
@@ -1,16 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createNftItemErrorNotificationStep = exports.createNftProxyErrorNotificationStep = exports.createMintAfterErrorGasStep = exports.createEstimatedReceiveTransferGasStep = exports.createEstimatedSendTransferGasStep = exports.createErrorNotificationGasStep = exports.createNftProxyOwnershipAssignedStep = exports.createNftItemBurnStep = exports.createNftItemSendStep = exports.createJettonMinterBurnNotificationStep = exports.createJettonProxyOwnershipAssignedStep = exports.createJettonWalletBurnStep = exports.createJettonWalletReceiveStep = exports.createJettonWalletInternalTransferStep = exports.createCrossChainLayerTvmMsgToEvmStep = exports.DEFAULT_CONTRACT_FEE_USAGE_PARAMS = void 0;
3
+ exports.createNftItemErrorNotificationStep = exports.createNftProxyErrorNotificationStep = exports.createMintAfterErrorGasStep = exports.createEstimatedReceiveTransferGasStep = exports.createEstimatedSendTransferGasStep = exports.createErrorNotificationGasStep = exports.createNftProxyOwnershipAssignedStep = exports.createNftItemBurnStep = exports.createNftItemSendStep = exports.createJettonMinterBurnNotificationStep = exports.createJettonProxyTransferNotificationStep = exports.createJettonWalletBurnStep = exports.createJettonWalletReceiveStep = exports.createJettonWalletInternalTransferStep = exports.createCrossChainLayerTvmMsgToEvmStep = exports.DEFAULT_CONTRACT_FEE_USAGE_PARAMS = void 0;
4
4
  const Consts_1 = require("./Consts");
5
5
  /**
6
6
  * Default contract fee usage parameters used as fallback.
7
7
  */
8
8
  exports.DEFAULT_CONTRACT_FEE_USAGE_PARAMS = {
9
9
  crossChainLayer: {
10
- accountBits: 43514,
11
- accountCells: 100,
10
+ accountBits: 51611,
11
+ accountCells: 105,
12
12
  gas: {
13
- tvmMsgToEvm: 14619,
13
+ tvmMsgToEvm: 15505,
14
14
  },
15
15
  },
16
16
  jettonWallet: {
@@ -32,7 +32,6 @@ exports.DEFAULT_CONTRACT_FEE_USAGE_PARAMS = {
32
32
  accountBits: 7760,
33
33
  accountCells: 16,
34
34
  gas: {
35
- ownershipAssigned: 8515,
36
35
  transferNotification: 8515,
37
36
  errorNotification: 5556,
38
37
  },
@@ -48,6 +47,8 @@ exports.DEFAULT_CONTRACT_FEE_USAGE_PARAMS = {
48
47
  nftItem: {
49
48
  accountBits: 1422,
50
49
  accountCells: 5,
50
+ estimatedAccountBits: 9877,
51
+ estimatedAccountCells: 25,
51
52
  gas: {
52
53
  send: 11722,
53
54
  burn: 11552,
@@ -55,7 +56,7 @@ exports.DEFAULT_CONTRACT_FEE_USAGE_PARAMS = {
55
56
  },
56
57
  },
57
58
  nftProxy: {
58
- accountBits: 7512,
59
+ accountBits: 7680,
59
60
  accountCells: 15,
60
61
  gas: {
61
62
  ownershipAssigned: 7688,
@@ -99,15 +100,15 @@ const createJettonWalletBurnStep = (params, msgBits, msgCells) => ({
99
100
  timeDelta: Consts_1.ONE_YEAR_SECONDS,
100
101
  });
101
102
  exports.createJettonWalletBurnStep = createJettonWalletBurnStep;
102
- const createJettonProxyOwnershipAssignedStep = (params, msgBits, msgCells) => ({
103
+ const createJettonProxyTransferNotificationStep = (params, msgBits, msgCells) => ({
103
104
  accountBits: 0,
104
105
  accountCells: 0,
105
- gasUsed: params.jettonProxy.gas.ownershipAssigned,
106
+ gasUsed: params.jettonProxy.gas.transferNotification,
106
107
  msgBits,
107
108
  msgCells,
108
109
  timeDelta: Consts_1.ONE_YEAR_SECONDS,
109
110
  });
110
- exports.createJettonProxyOwnershipAssignedStep = createJettonProxyOwnershipAssignedStep;
111
+ exports.createJettonProxyTransferNotificationStep = createJettonProxyTransferNotificationStep;
111
112
  const createJettonMinterBurnNotificationStep = (params, msgBits, msgCells) => ({
112
113
  accountBits: params.jettonMinter.accountBits,
113
114
  accountCells: params.jettonMinter.accountCells,
@@ -123,7 +123,7 @@ class Simulator {
123
123
  return this.calculateTransactionPipeline([
124
124
  (0, Fees_1.createJettonWalletInternalTransferStep)(this.config.TONParams.contractFeeUsageParams, msgBits, msgCells),
125
125
  (0, Fees_1.createJettonWalletReceiveStep)(this.config.TONParams.contractFeeUsageParams, msgBits, msgCells),
126
- (0, Fees_1.createJettonProxyOwnershipAssignedStep)(this.config.TONParams.contractFeeUsageParams, msgBits, msgCells),
126
+ (0, Fees_1.createJettonProxyTransferNotificationStep)(this.config.TONParams.contractFeeUsageParams, msgBits, msgCells),
127
127
  (0, Fees_1.createCrossChainLayerTvmMsgToEvmStep)(this.config.TONParams.contractFeeUsageParams, msgBits, msgCells),
128
128
  (0, Fees_1.createErrorNotificationGasStep)(this.config.TONParams.contractFeeUsageParams, msgBits, msgCells),
129
129
  (0, Fees_1.createEstimatedSendTransferGasStep)(this.config.TONParams.contractFeeUsageParams, msgBits, msgCells),
@@ -136,9 +136,7 @@ class Simulator {
136
136
  return dynamicFee > legacyNetworkFee ? dynamicFee : legacyNetworkFee;
137
137
  }
138
138
  calculateLegacyNftTransferNetworkFee(params, msgBits, msgCells) {
139
- const forwardTonAmount = Consts_1.NFT_TRANSFER_FORWARD_TON_AMOUNT +
140
- (params.forwardFeeTonAmount ?? 0n) +
141
- (params.crossChainTonAmount ?? 0n);
139
+ const forwardTonAmount = Consts_1.NFT_TRANSFER_FORWARD_TON_AMOUNT + (params.forwardFeeTonAmount ?? 0n) + (params.crossChainTonAmount ?? 0n);
142
140
  const outboundMessageCount = forwardTonAmount > 0n
143
141
  ? Consts_1.LEGACY_NFT_TRANSFER_WITH_FORWARD_OUTBOUND_MESSAGE_COUNT
144
142
  : Consts_1.LEGACY_NFT_TRANSFER_BASE_OUTBOUND_MESSAGE_COUNT;
@@ -1,4 +1,4 @@
1
- import { Address, Cell } from '@ton/ton';
1
+ import type { Address, Cell, Message } from '@ton/ton';
2
2
  import { AbstractProvider, ethers } from 'ethers';
3
3
  import { ICrossChainLayer, ISAFactory, ISettings, ITokenUtils } from '../../artifacts/tacTypes';
4
4
  import { ContractOpener } from '../interfaces';
@@ -130,6 +130,13 @@ export type TransactionDepth = {
130
130
  depth: number;
131
131
  hashType?: 'unknown' | 'in' | 'out';
132
132
  };
133
+ export type TransactionQueueItem = {
134
+ address: Address;
135
+ hash: string;
136
+ depth: number;
137
+ hashType: 'unknown' | 'in' | 'out';
138
+ message?: Message;
139
+ };
133
140
  export type AdjacentTransactionsResponse = {
134
141
  transactions: ToncenterTransaction[];
135
142
  };
@@ -196,7 +203,6 @@ export type ContractFeeUsageParams = {
196
203
  accountBits: number;
197
204
  accountCells: number;
198
205
  gas: {
199
- ownershipAssigned: number;
200
206
  transferNotification: number;
201
207
  errorNotification: number;
202
208
  };
@@ -212,6 +218,8 @@ export type ContractFeeUsageParams = {
212
218
  nftItem: {
213
219
  accountBits: number;
214
220
  accountCells: number;
221
+ estimatedAccountBits: number;
222
+ estimatedAccountCells: number;
215
223
  gas: {
216
224
  send: number;
217
225
  burn: number;
@@ -197,8 +197,24 @@ export type ToncenterV3IndexedTransaction = {
197
197
  hash: string;
198
198
  /** Optional trace identifier returned by Toncenter v3. */
199
199
  traceId?: string;
200
+ /** Transaction phase data returned by Toncenter v3. */
201
+ description?: {
202
+ type?: string;
203
+ aborted?: boolean;
204
+ computePh?: {
205
+ skipped?: boolean;
206
+ success?: boolean;
207
+ exitCode?: number;
208
+ } | null;
209
+ action?: {
210
+ success?: boolean;
211
+ resultCode?: number;
212
+ } | null;
213
+ } | null;
200
214
  /** Incoming message of the indexed transaction, when present in the response. */
201
215
  inMsg?: {
216
+ /** Indexed message hash. */
217
+ hash?: string | null;
202
218
  /** Message source address. */
203
219
  source?: string | null;
204
220
  /** Message destination address. */
@@ -213,6 +229,8 @@ export type ToncenterV3IndexedTransaction = {
213
229
  } | null;
214
230
  /** Outgoing messages of the indexed transaction. */
215
231
  outMsgs: Array<{
232
+ /** Indexed message hash. */
233
+ hash?: string | null;
216
234
  /** Message destination address. `null` means external outbound log message. */
217
235
  destination?: string | null;
218
236
  /** Raw message content returned by Toncenter v3. */
@@ -693,6 +711,15 @@ export type TrackTransactionTreeParams = {
693
711
  * @default 100
694
712
  */
695
713
  maxScannedTransactions?: number;
714
+ /**
715
+ * Whether to search archival nodes for historical data.
716
+ * Omitted by default; set true for old transactions when the provider has archival nodes.
717
+ */
718
+ archival?: boolean;
719
+ /**
720
+ * Logical time of the root transaction. Use with a root transaction hash to avoid scanning from latest history.
721
+ */
722
+ rootLt?: string;
696
723
  /**
697
724
  * List of operation codes (opcodes) to skip for extra checks.
698
725
  * Core phase validation is still applied.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonappchain/sdk",
3
- "version": "0.7.3-rc5",
3
+ "version": "0.7.3-rc7",
4
4
  "repository": "https://github.com/TacBuild/tac-sdk.git",
5
5
  "author": "TAC. <developers@tac>",
6
6
  "license": "MIT",
@@ -61,6 +61,8 @@
61
61
  "build:artifacts:tac:all": "npm run build:artifacts:tac:dev && npm run build:artifacts:tac:testnet && npm run build:artifacts:tac:mainnet",
62
62
  "build:artifacts": "npm run build:artifacts:ton:all && npm run build:artifacts:tac:all",
63
63
  "test": "jest --verbose --runInBand",
64
+ "test:ton-providers": "RUN_TON_PROVIDER_TESTS=1 jest --verbose --runInBand tests/ton_providers",
65
+ "test:toncenter-v2-tree": "RUN_TON_PROVIDER_TESTS=1 jest --verbose --runInBand tests/ton_providers/contractOpeners/toncenterV2HistoricalTree.spec.ts",
64
66
  "release": "npm run build && npx release-it",
65
67
  "lint": "eslint .",
66
68
  "lint:fix": "eslint . --fix",