@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.
- package/dist/src/adapters/BaseContractOpener.d.ts +5 -4
- package/dist/src/adapters/BaseContractOpener.js +45 -43
- package/dist/src/adapters/RetryableContractOpener.d.ts +1 -1
- package/dist/src/adapters/RetryableContractOpener.js +12 -1
- package/dist/src/adapters/TonClientOpener.d.ts +2 -0
- package/dist/src/adapters/TonClientOpener.js +35 -1
- package/dist/src/adapters/ToncenterV3Indexer.d.ts +1 -0
- package/dist/src/adapters/ToncenterV3Indexer.js +30 -11
- package/dist/src/adapters/ToncenterV3Opener.d.ts +11 -0
- package/dist/src/adapters/ToncenterV3Opener.js +110 -0
- package/dist/src/adapters/index.d.ts +1 -0
- package/dist/src/adapters/index.js +1 -0
- package/dist/src/interfaces/IToncenterV3Indexer.d.ts +1 -0
- package/dist/src/sdk/Configuration.js +1 -1
- package/dist/src/sdk/Consts.d.ts +1 -1
- package/dist/src/sdk/Consts.js +3 -3
- package/dist/src/sdk/Fees.d.ts +1 -1
- package/dist/src/sdk/Fees.js +10 -9
- package/dist/src/sdk/Simulator.js +2 -4
- package/dist/src/structs/InternalStruct.d.ts +10 -2
- package/dist/src/structs/Struct.d.ts +27 -0
- package/package.json +3 -1
|
@@ -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
|
-
|
|
60
|
+
protected validateTransactionWithResult(tx: Transaction, ignoreOpcodeList: number[]): TransactionValidationError | null;
|
|
60
61
|
/**
|
|
61
62
|
* Find transaction by hash type
|
|
62
63
|
*/
|
|
63
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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 &&
|
|
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
|
|
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,
|
|
288
|
+
return this.getTransactionByInMsgHash(address, targetHash, opts);
|
|
288
289
|
}
|
|
289
290
|
else if (hashType === 'out') {
|
|
290
|
-
return this.getTransactionByOutMsgHash(address,
|
|
291
|
+
return this.getTransactionByOutMsgHash(address, targetHash, opts);
|
|
291
292
|
}
|
|
292
293
|
else {
|
|
293
|
-
return this.getTransactionByHash(address,
|
|
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
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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 =
|
|
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,
|
|
384
|
-
: await this.findTransactionByHashType(currentAddress, currentHash, hashType,
|
|
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
|
|
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
|
|
396
|
-
hashType
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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([
|
|
109
|
+
const visitedHashes = new Set([rootTransaction.hash]);
|
|
90
110
|
let scannedTransactions = 0;
|
|
91
|
-
|
|
92
|
-
const { hash: currentHash, depth } = queue
|
|
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
|
-
|
|
99
|
-
if (visitedHashes.has(normalizedHash)) {
|
|
118
|
+
if (visitedHashes.has(transaction.hash)) {
|
|
100
119
|
continue;
|
|
101
120
|
}
|
|
102
|
-
visitedHashes.add(
|
|
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;
|
|
@@ -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) {
|
package/dist/src/sdk/Consts.d.ts
CHANGED
|
@@ -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;
|
package/dist/src/sdk/Consts.js
CHANGED
|
@@ -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.
|
|
4
|
-
exports.
|
|
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;
|
package/dist/src/sdk/Fees.d.ts
CHANGED
|
@@ -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
|
|
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;
|
package/dist/src/sdk/Fees.js
CHANGED
|
@@ -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.
|
|
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:
|
|
11
|
-
accountCells:
|
|
10
|
+
accountBits: 51611,
|
|
11
|
+
accountCells: 105,
|
|
12
12
|
gas: {
|
|
13
|
-
tvmMsgToEvm:
|
|
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:
|
|
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
|
|
103
|
+
const createJettonProxyTransferNotificationStep = (params, msgBits, msgCells) => ({
|
|
103
104
|
accountBits: 0,
|
|
104
105
|
accountCells: 0,
|
|
105
|
-
gasUsed: params.jettonProxy.gas.
|
|
106
|
+
gasUsed: params.jettonProxy.gas.transferNotification,
|
|
106
107
|
msgBits,
|
|
107
108
|
msgCells,
|
|
108
109
|
timeDelta: Consts_1.ONE_YEAR_SECONDS,
|
|
109
110
|
});
|
|
110
|
-
exports.
|
|
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.
|
|
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-
|
|
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",
|