@tonappchain/sdk 0.7.2-alpha-11 → 0.7.2-alpha-13
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/artifacts/dev/ton/internal/build/CrossChainLayer.compiled.json +1 -1
- package/dist/src/adapters/BaseContractOpener.d.ts +71 -0
- package/dist/src/adapters/BaseContractOpener.js +290 -0
- package/dist/src/adapters/LiteClientOpener.d.ts +33 -0
- package/dist/src/adapters/LiteClientOpener.js +117 -0
- package/dist/src/adapters/OpenerUtils.d.ts +3 -0
- package/dist/src/adapters/OpenerUtils.js +39 -0
- package/dist/src/adapters/RetryableContractOpener.d.ts +35 -0
- package/dist/src/adapters/{retryableContractOpener.js → RetryableContractOpener.js} +60 -12
- package/dist/src/adapters/SandboxOpener.d.ts +15 -0
- package/dist/src/adapters/SandboxOpener.js +35 -0
- package/dist/src/adapters/TonClient4Opener.d.ts +21 -0
- package/dist/src/adapters/TonClient4Opener.js +86 -0
- package/dist/src/adapters/TonClientOpener.d.ts +16 -0
- package/dist/src/adapters/TonClientOpener.js +70 -0
- package/dist/src/adapters/index.d.ts +7 -2
- package/dist/src/adapters/index.js +7 -2
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +3 -2
- package/dist/src/interfaces/ContractOpener.d.ts +69 -2
- package/dist/src/interfaces/ITacSDK.d.ts +5 -0
- package/dist/src/sdk/Configuration.js +1 -1
- package/dist/src/sdk/Consts.d.ts +5 -2
- package/dist/src/sdk/Consts.js +8 -4
- package/dist/src/sdk/StartTracking.d.ts +3 -4
- package/dist/src/sdk/StartTracking.js +7 -7
- package/dist/src/sdk/TONTransactionManager.d.ts +1 -3
- package/dist/src/sdk/TONTransactionManager.js +2 -3
- package/dist/src/sdk/TacSdk.d.ts +3 -1
- package/dist/src/sdk/TacSdk.js +5 -3
- package/dist/src/sdk/TxFinalizer.d.ts +1 -8
- package/dist/src/sdk/TxFinalizer.js +10 -122
- package/dist/src/sdk/Utils.d.ts +5 -0
- package/dist/src/sdk/Utils.js +24 -0
- package/dist/src/structs/InternalStruct.d.ts +1 -16
- package/dist/src/structs/Struct.d.ts +90 -5
- package/package.json +1 -1
- package/dist/src/adapters/contractOpener.d.ts +0 -24
- package/dist/src/adapters/contractOpener.js +0 -310
- package/dist/src/adapters/retryableContractOpener.d.ts +0 -29
|
@@ -9,7 +9,7 @@ const Logger_1 = require("./Logger");
|
|
|
9
9
|
const OperationTracker_1 = require("./OperationTracker");
|
|
10
10
|
const Utils_1 = require("./Utils");
|
|
11
11
|
async function startTracking(transactionLinker, network, options) {
|
|
12
|
-
const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true, logger = new Logger_1.NoopLogger(),
|
|
12
|
+
const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true, logger = new Logger_1.NoopLogger(), contractOpener, cclAddress, } = options || {};
|
|
13
13
|
const tracker = new OperationTracker_1.OperationTracker(network, customLiteSequencerEndpoints, logger);
|
|
14
14
|
logger.debug(`Start tracking operation\n` +
|
|
15
15
|
`caller: ${transactionLinker.caller}\n` +
|
|
@@ -63,15 +63,15 @@ async function startTracking(transactionLinker, network, options) {
|
|
|
63
63
|
logger.debug(errorMessage);
|
|
64
64
|
}
|
|
65
65
|
const profilingData = await tracker.getStageProfiling(operationId);
|
|
66
|
-
// Check if EXECUTED_IN_TON stage exists and use
|
|
66
|
+
// Check if EXECUTED_IN_TON stage exists and use ContractOpener to verify transaction success
|
|
67
67
|
if (profilingData.executedInTON.exists && profilingData.executedInTON.stageData?.transactions) {
|
|
68
68
|
logger.debug('EXECUTED_IN_TON stage found, verifying transaction success in TON...');
|
|
69
|
-
if (
|
|
69
|
+
if (contractOpener && cclAddress) {
|
|
70
70
|
const transactions = profilingData.executedInTON.stageData.transactions;
|
|
71
71
|
for (const tx of transactions) {
|
|
72
72
|
try {
|
|
73
73
|
logger.debug(`Verifying transaction: ${tx.hash}`);
|
|
74
|
-
await
|
|
74
|
+
await contractOpener.trackTransactionTree(cclAddress, tx.hash, { maxDepth: Consts_1.DEFAULT_FIND_TX_MAX_DEPTH });
|
|
75
75
|
logger.debug(`Transaction ${tx.hash} verified successfully in TON`);
|
|
76
76
|
}
|
|
77
77
|
catch (error) {
|
|
@@ -83,7 +83,7 @@ async function startTracking(transactionLinker, network, options) {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
else {
|
|
86
|
-
logger.debug('
|
|
86
|
+
logger.debug('ContractOpener or CCL address is not provided, skipping TON transaction verification');
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
if (returnValue) {
|
|
@@ -99,7 +99,7 @@ async function startTracking(transactionLinker, network, options) {
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
async function startTrackingMultiple(transactionLinkers, network, options) {
|
|
102
|
-
const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true,
|
|
102
|
+
const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true, contractOpener, logger = new Logger_1.NoopLogger(), } = options || {};
|
|
103
103
|
logger.debug(`Start tracking ${transactionLinkers.length} operations`);
|
|
104
104
|
const results = await Promise.all(transactionLinkers.map((linker, index) => {
|
|
105
105
|
logger.debug(`\nProcessing operation ${index + 1}/${transactionLinkers.length}`);
|
|
@@ -109,7 +109,7 @@ async function startTrackingMultiple(transactionLinkers, network, options) {
|
|
|
109
109
|
maxIterationCount,
|
|
110
110
|
returnValue: true,
|
|
111
111
|
tableView: false,
|
|
112
|
-
|
|
112
|
+
contractOpener,
|
|
113
113
|
logger,
|
|
114
114
|
});
|
|
115
115
|
}));
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Asset, IConfiguration, ILogger, IOperationTracker, ISimulator, ITONTransactionManager } from '../interfaces';
|
|
2
|
-
import { ITxFinalizer } from '../interfaces/ITxFinalizer';
|
|
3
2
|
import { type SenderAbstraction } from '../sender';
|
|
4
3
|
import { BatchCrossChainTx, CrossChainPayloadResult, CrossChainTransactionOptions, CrossChainTransactionsOptions, CrosschainTx, EvmProxyMsg, FeeParams, TransactionLinkerWithOperationId } from '../structs/Struct';
|
|
5
4
|
export declare class TONTransactionManager implements ITONTransactionManager {
|
|
@@ -7,8 +6,7 @@ export declare class TONTransactionManager implements ITONTransactionManager {
|
|
|
7
6
|
private readonly simulator;
|
|
8
7
|
private readonly operationTracker;
|
|
9
8
|
private readonly logger;
|
|
10
|
-
|
|
11
|
-
constructor(config: IConfiguration, simulator: ISimulator, operationTracker: IOperationTracker, logger: ILogger | undefined, txFinalizer: ITxFinalizer);
|
|
9
|
+
constructor(config: IConfiguration, simulator: ISimulator, operationTracker: IOperationTracker, logger?: ILogger);
|
|
12
10
|
buildFeeParams(options: CrossChainTransactionOptions, evmProxyMsg: EvmProxyMsg, sender: SenderAbstraction, tx: CrosschainTx): Promise<FeeParams>;
|
|
13
11
|
private prepareCrossChainTransaction;
|
|
14
12
|
private generateCrossChainMessages;
|
|
@@ -11,12 +11,11 @@ const Logger_1 = require("./Logger");
|
|
|
11
11
|
const Utils_1 = require("./Utils");
|
|
12
12
|
const Validator_1 = require("./Validator");
|
|
13
13
|
class TONTransactionManager {
|
|
14
|
-
constructor(config, simulator, operationTracker, logger = new Logger_1.NoopLogger()
|
|
14
|
+
constructor(config, simulator, operationTracker, logger = new Logger_1.NoopLogger()) {
|
|
15
15
|
this.config = config;
|
|
16
16
|
this.simulator = simulator;
|
|
17
17
|
this.operationTracker = operationTracker;
|
|
18
18
|
this.logger = logger;
|
|
19
|
-
this.txFinalizer = txFinalizer;
|
|
20
19
|
}
|
|
21
20
|
async buildFeeParams(options, evmProxyMsg, sender, tx) {
|
|
22
21
|
const { withoutSimulation, protocolFee, evmExecutorFee, tvmExecutorFee, isRoundTrip } = options;
|
|
@@ -175,7 +174,7 @@ class TONTransactionManager {
|
|
|
175
174
|
if (waitOptions.ensureTxExecuted && sendTransactionResult.boc) {
|
|
176
175
|
const hash = (0, Utils_1.getNormalizedExtMessageHash)((0, ton_1.loadMessage)(ton_1.Cell.fromBase64(sendTransactionResult.boc).beginParse()));
|
|
177
176
|
this.logger.info(`Tracking transaction tree for hash: ${hash}`);
|
|
178
|
-
await this.
|
|
177
|
+
await this.config.TONParams.contractOpener.trackTransactionTree(sender.getSenderAddress(), hash, {
|
|
179
178
|
maxDepth: Consts_1.DEFAULT_FIND_TX_MAX_DEPTH,
|
|
180
179
|
});
|
|
181
180
|
this.logger.info(`Transaction tree successful`);
|
package/dist/src/sdk/TacSdk.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Wallet } from 'ethers';
|
|
2
2
|
import { JettonMinterData, NFTItemData } from '../../artifacts/tonTypes';
|
|
3
3
|
import { FT, NFT } from '../assets';
|
|
4
|
-
import { IConfiguration, ILogger, IOperationTracker, ITacExplorerClient, ITacSDK } from '../interfaces';
|
|
4
|
+
import { ContractOpener, IConfiguration, ILogger, IOperationTracker, ITacExplorerClient, ITacSDK } from '../interfaces';
|
|
5
5
|
import type { SenderAbstraction } from '../sender';
|
|
6
6
|
import { AssetFromFTArg, AssetFromNFTCollectionArg, AssetFromNFTItemArg, AssetLike, BatchCrossChainTxWithAssetLike, CrossChainPayloadResult, CrossChainTransactionOptions, CrossChainTransactionsOptions, CrosschainTx, EVMAddress, EvmProxyMsg, ExecutionFeeEstimationResult, NFTAddressType, SDKParams, SuggestedTVMExecutorFee, TacGasPrice, TACSimulationParams, TACSimulationResult, TransactionLinkerWithOperationId, TVMAddress, UserWalletBalanceExtended } from '../structs/Struct';
|
|
7
7
|
export declare class TacSdk implements ITacSDK {
|
|
8
8
|
readonly config: IConfiguration;
|
|
9
|
+
readonly contactOpener: ContractOpener;
|
|
9
10
|
readonly operationTracker: IOperationTracker;
|
|
10
11
|
readonly explorerClient: ITacExplorerClient;
|
|
11
12
|
private readonly simulator;
|
|
@@ -45,4 +46,5 @@ export declare class TacSdk implements ITacSDK {
|
|
|
45
46
|
getTacExplorerClient(): ITacExplorerClient;
|
|
46
47
|
prepareCrossChainTransactionPayload(evmProxyMsg: EvmProxyMsg, senderAddress: string, assets?: AssetLike[], options?: CrossChainTransactionOptions): Promise<CrossChainPayloadResult[]>;
|
|
47
48
|
getTACGasPrice(): Promise<TacGasPrice>;
|
|
49
|
+
getTonContractOpener(): ContractOpener;
|
|
48
50
|
}
|
package/dist/src/sdk/TacSdk.js
CHANGED
|
@@ -12,11 +12,11 @@ const Simulator_1 = require("./Simulator");
|
|
|
12
12
|
const TacExplorerClient_1 = require("./TacExplorerClient");
|
|
13
13
|
const TACTransactionManager_1 = require("./TACTransactionManager");
|
|
14
14
|
const TONTransactionManager_1 = require("./TONTransactionManager");
|
|
15
|
-
const TxFinalizer_1 = require("./TxFinalizer");
|
|
16
15
|
const Utils_1 = require("./Utils");
|
|
17
16
|
class TacSdk {
|
|
18
17
|
constructor(config, simulator, tonTransactionManager, tacTransactionManager, operationTracker, explorerClient) {
|
|
19
18
|
this.config = config;
|
|
19
|
+
this.contactOpener = config.TONParams.contractOpener;
|
|
20
20
|
this.simulator = simulator;
|
|
21
21
|
this.tonTransactionManager = tonTransactionManager;
|
|
22
22
|
this.tacTransactionManager = tacTransactionManager;
|
|
@@ -44,8 +44,7 @@ class TacSdk {
|
|
|
44
44
|
const operationTracker = new OperationTracker_1.OperationTracker(network, config.liteSequencerEndpoints);
|
|
45
45
|
const explorerClient = new TacExplorerClient_1.TacExplorerClient(artifacts.TAC_EXPLORER_API_ENDPOINT);
|
|
46
46
|
const simulator = new Simulator_1.Simulator(config, operationTracker, logger);
|
|
47
|
-
const
|
|
48
|
-
const tonTransactionManager = new TONTransactionManager_1.TONTransactionManager(config, simulator, operationTracker, logger, txFinalizer);
|
|
47
|
+
const tonTransactionManager = new TONTransactionManager_1.TONTransactionManager(config, simulator, operationTracker, logger);
|
|
49
48
|
const tacTransactionManager = new TACTransactionManager_1.TACTransactionManager(config, operationTracker, logger);
|
|
50
49
|
return new TacSdk(config, simulator, tonTransactionManager, tacTransactionManager, operationTracker, explorerClient);
|
|
51
50
|
}
|
|
@@ -197,5 +196,8 @@ class TacSdk {
|
|
|
197
196
|
slow: response.gasPrices.slow,
|
|
198
197
|
};
|
|
199
198
|
}
|
|
199
|
+
getTonContractOpener() {
|
|
200
|
+
return this.contactOpener;
|
|
201
|
+
}
|
|
200
202
|
}
|
|
201
203
|
exports.TacSdk = TacSdk;
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IHttpClient, ILogger } from '../interfaces';
|
|
2
2
|
import { ITxFinalizer } from '../interfaces/ITxFinalizer';
|
|
3
3
|
import { TxFinalizerConfig } from '../structs/InternalStruct';
|
|
4
4
|
import { TrackTransactionTreeParams } from '../structs/Struct';
|
|
5
5
|
export declare class TonTxFinalizer implements ITxFinalizer {
|
|
6
|
-
private logger;
|
|
7
|
-
private contractOpener;
|
|
8
|
-
constructor(contractOpener: ContractOpener, logger?: ILogger);
|
|
9
|
-
private fetchAdjacentTransactions;
|
|
10
|
-
trackTransactionTree(address: string, hash: string, params?: TrackTransactionTreeParams): Promise<void>;
|
|
11
|
-
}
|
|
12
|
-
export declare class TonIndexerTxFinalizer implements ITxFinalizer {
|
|
13
6
|
private logger;
|
|
14
7
|
private apiConfig;
|
|
15
8
|
private readonly httpClient;
|
|
@@ -1,133 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const ton_1 = require("@ton/ton");
|
|
3
|
+
exports.TonTxFinalizer = void 0;
|
|
5
4
|
const errors_1 = require("../errors");
|
|
6
5
|
const AxiosHttpClient_1 = require("./AxiosHttpClient");
|
|
7
6
|
const Consts_1 = require("./Consts");
|
|
8
7
|
const Logger_1 = require("./Logger");
|
|
9
8
|
const Utils_1 = require("./Utils");
|
|
10
|
-
const IGNORE_OPCODE = [
|
|
11
|
-
0xd53276db, // Excess
|
|
12
|
-
];
|
|
13
9
|
class TonTxFinalizer {
|
|
14
|
-
constructor(contractOpener, logger = new Logger_1.NoopLogger()) {
|
|
15
|
-
this.contractOpener = contractOpener;
|
|
16
|
-
this.logger = logger;
|
|
17
|
-
}
|
|
18
|
-
// Fetches adjacent transactions from toncenter
|
|
19
|
-
async fetchAdjacentTransactions(address, hash, retries = 5, delay = 1000, opts) {
|
|
20
|
-
for (let i = retries; i >= 0; i--) {
|
|
21
|
-
try {
|
|
22
|
-
const txs = await this.contractOpener.getAdjacentTransactions(address, hash, opts);
|
|
23
|
-
return txs;
|
|
24
|
-
}
|
|
25
|
-
catch (error) {
|
|
26
|
-
const errorMessage = error.message;
|
|
27
|
-
// Rate limit error (429) - retry
|
|
28
|
-
if (errorMessage.includes('429')) {
|
|
29
|
-
if (i > 0) {
|
|
30
|
-
await (0, Utils_1.sleep)(delay);
|
|
31
|
-
}
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
// Log all errors except 404 Not Found
|
|
35
|
-
if (!errorMessage.includes('404')) {
|
|
36
|
-
const logMessage = error instanceof Error ? error.message : error;
|
|
37
|
-
this.logger.warn(`Failed to fetch adjacent transactions for ${hash}:`, logMessage);
|
|
38
|
-
}
|
|
39
|
-
if (i > 0) {
|
|
40
|
-
await (0, Utils_1.sleep)(delay);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return [];
|
|
45
|
-
}
|
|
46
|
-
// Checks if all transactions in the tree are successful
|
|
47
|
-
async trackTransactionTree(address, hash, params = { maxDepth: Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, ignoreOpcodeList: IGNORE_OPCODE }) {
|
|
48
|
-
const { maxDepth = Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, ignoreOpcodeList = IGNORE_OPCODE } = params;
|
|
49
|
-
const parsedAddress = ton_1.Address.parse(address);
|
|
50
|
-
const visitedHashes = new Set();
|
|
51
|
-
const queue = [{ address: parsedAddress, hash, depth: 0 }];
|
|
52
|
-
while (queue.length > 0) {
|
|
53
|
-
const { hash: currentHash, depth: currentDepth, address: currentAddress } = queue.shift();
|
|
54
|
-
if (visitedHashes.has(currentHash)) {
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
visitedHashes.add(currentHash);
|
|
58
|
-
this.logger.debug(`Checking hash (depth ${currentDepth}): ${currentHash}`);
|
|
59
|
-
const transactions = await this.fetchAdjacentTransactions(currentAddress, currentHash, 5, 1000, {
|
|
60
|
-
limit: 10,
|
|
61
|
-
archival: true,
|
|
62
|
-
});
|
|
63
|
-
this.logger.debug(`Found ${transactions.length} adjacent transactions for ${currentHash}`);
|
|
64
|
-
if (transactions.length === 0)
|
|
65
|
-
continue;
|
|
66
|
-
for (const tx of transactions) {
|
|
67
|
-
if (tx.description.type !== 'generic' || !tx.inMessage)
|
|
68
|
-
continue;
|
|
69
|
-
if (tx.inMessage.info.type === 'internal' && tx.inMessage.info.value.coins === Consts_1.IGNORE_MSG_VALUE_1_NANO)
|
|
70
|
-
continue; // we ignore messages with 1 nanoton value as they are for notification purpose only
|
|
71
|
-
const bodySlice = tx.inMessage.body.beginParse();
|
|
72
|
-
if (bodySlice.remainingBits < 32)
|
|
73
|
-
continue;
|
|
74
|
-
const opcode = bodySlice.loadUint(32);
|
|
75
|
-
if (!ignoreOpcodeList.includes(opcode)) {
|
|
76
|
-
const { aborted, computePhase, actionPhase } = tx.description;
|
|
77
|
-
const failureCase = (() => {
|
|
78
|
-
if (aborted) {
|
|
79
|
-
return 'Transaction was aborted';
|
|
80
|
-
}
|
|
81
|
-
if (!computePhase) {
|
|
82
|
-
return 'computePhase not present';
|
|
83
|
-
}
|
|
84
|
-
if (computePhase.type === 'skipped') {
|
|
85
|
-
return 'computePhase was skipped';
|
|
86
|
-
}
|
|
87
|
-
if (!computePhase.success) {
|
|
88
|
-
return 'computePhase not successful';
|
|
89
|
-
}
|
|
90
|
-
if (computePhase.exitCode !== 0) {
|
|
91
|
-
return `computePhase.exitCode was not zero (exitCode=${computePhase.exitCode})`;
|
|
92
|
-
}
|
|
93
|
-
if (actionPhase && !actionPhase.success) {
|
|
94
|
-
return 'actionPhase not successful';
|
|
95
|
-
}
|
|
96
|
-
if (actionPhase && actionPhase.resultCode !== 0) {
|
|
97
|
-
return `actionPhase.resultCode was not zero (resultCode=${actionPhase.resultCode})`;
|
|
98
|
-
}
|
|
99
|
-
return null;
|
|
100
|
-
})();
|
|
101
|
-
if (failureCase) {
|
|
102
|
-
throw (0, errors_1.txFinalizationError)(`${tx.hash().toString('base64')}: ${failureCase}`);
|
|
103
|
-
}
|
|
104
|
-
if (currentDepth + 1 < maxDepth) {
|
|
105
|
-
if (tx.outMessages.size > 0) {
|
|
106
|
-
queue.push({
|
|
107
|
-
hash: tx.hash().toString('base64'),
|
|
108
|
-
address: tx.inMessage.info.dest,
|
|
109
|
-
depth: currentDepth + 1,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
this.logger.debug(`Skipping hash (depth ${currentDepth}): ${tx.hash().toString('base64')}`);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
this.logger.debug(`Finished checking hash (depth ${currentDepth}): ${currentHash}`);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
exports.TonTxFinalizer = TonTxFinalizer;
|
|
123
|
-
class TonIndexerTxFinalizer {
|
|
124
10
|
constructor(apiConfig, logger = new Logger_1.NoopLogger(), httpClient = new AxiosHttpClient_1.AxiosHttpClient()) {
|
|
125
11
|
this.apiConfig = apiConfig;
|
|
126
12
|
this.logger = logger;
|
|
127
13
|
this.httpClient = httpClient;
|
|
128
14
|
}
|
|
129
15
|
// Fetches adjacent transactions from toncenter
|
|
130
|
-
async fetchAdjacentTransactions(hash, retries =
|
|
16
|
+
async fetchAdjacentTransactions(hash, retries = Consts_1.DEFAULT_RETRY_MAX_COUNT, delay = Consts_1.DEFAULT_RETRY_DELAY_MS) {
|
|
131
17
|
for (let i = retries; i >= 0; i--) {
|
|
132
18
|
try {
|
|
133
19
|
const url = this.apiConfig.urlBuilder(hash);
|
|
@@ -161,8 +47,8 @@ class TonIndexerTxFinalizer {
|
|
|
161
47
|
return [];
|
|
162
48
|
}
|
|
163
49
|
// Checks if all transactions in the tree are successful
|
|
164
|
-
async trackTransactionTree(_, hash, params = { maxDepth: Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, ignoreOpcodeList: IGNORE_OPCODE }) {
|
|
165
|
-
const { maxDepth = Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, ignoreOpcodeList = IGNORE_OPCODE } = params;
|
|
50
|
+
async trackTransactionTree(_, hash, params = { maxDepth: Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, ignoreOpcodeList: Consts_1.IGNORE_OPCODE }) {
|
|
51
|
+
const { maxDepth = Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, ignoreOpcodeList = Consts_1.IGNORE_OPCODE } = params;
|
|
166
52
|
const visitedHashes = new Set();
|
|
167
53
|
const queue = [{ hash, depth: 0 }];
|
|
168
54
|
while (queue.length > 0) {
|
|
@@ -191,18 +77,20 @@ class TonIndexerTxFinalizer {
|
|
|
191
77
|
return 'computePh not successful';
|
|
192
78
|
}
|
|
193
79
|
if (computePh.exitCode !== 0) {
|
|
194
|
-
return `computePh.exitCode was not zero
|
|
80
|
+
return `computePh.exitCode was not zero`;
|
|
195
81
|
}
|
|
196
82
|
if (action && !action.success) {
|
|
197
83
|
return 'action not successful';
|
|
198
84
|
}
|
|
199
85
|
if (action && action.resultCode !== 0) {
|
|
200
|
-
return `action.resultCode was not zero
|
|
86
|
+
return `action.resultCode was not zero`;
|
|
201
87
|
}
|
|
202
88
|
return null;
|
|
203
89
|
})();
|
|
204
90
|
if (failureCase) {
|
|
205
|
-
|
|
91
|
+
const exitCode = computePh ? computePh.exitCode : 'N/A';
|
|
92
|
+
const resultCode = action ? action.resultCode : 'N/A';
|
|
93
|
+
throw (0, errors_1.txFinalizationError)(`${tx.hash}: ${failureCase} (exitCode=${exitCode}, resultCode=${resultCode})`);
|
|
206
94
|
}
|
|
207
95
|
if (currentDepth + 1 < maxDepth) {
|
|
208
96
|
if (tx.outMsgs.length > 0) {
|
|
@@ -217,4 +105,4 @@ class TonIndexerTxFinalizer {
|
|
|
217
105
|
}
|
|
218
106
|
}
|
|
219
107
|
}
|
|
220
|
-
exports.
|
|
108
|
+
exports.TonTxFinalizer = TonTxFinalizer;
|
package/dist/src/sdk/Utils.d.ts
CHANGED
|
@@ -37,6 +37,11 @@ export declare function getString(cell?: Cell): string;
|
|
|
37
37
|
* Calculates (a * b + c / 2) / c with proper rounding
|
|
38
38
|
*/
|
|
39
39
|
export declare function muldivr(a: bigint, b: bigint, c: bigint): bigint;
|
|
40
|
+
/**
|
|
41
|
+
* Normalize hash string to base64 format
|
|
42
|
+
* Accepts: base64, hex, or raw string
|
|
43
|
+
*/
|
|
44
|
+
export declare function normalizeHashToBase64(hash: string): string;
|
|
40
45
|
export declare function getNormalizedExtMessageHash(message: Message): string;
|
|
41
46
|
export declare function retry<T>(fn: () => Promise<T>, options: {
|
|
42
47
|
retries: number;
|
package/dist/src/sdk/Utils.js
CHANGED
|
@@ -20,6 +20,7 @@ exports.getAddressString = getAddressString;
|
|
|
20
20
|
exports.getNumber = getNumber;
|
|
21
21
|
exports.getString = getString;
|
|
22
22
|
exports.muldivr = muldivr;
|
|
23
|
+
exports.normalizeHashToBase64 = normalizeHashToBase64;
|
|
23
24
|
exports.getNormalizedExtMessageHash = getNormalizedExtMessageHash;
|
|
24
25
|
exports.retry = retry;
|
|
25
26
|
exports.recurisivelyCollectCellStats = recurisivelyCollectCellStats;
|
|
@@ -316,6 +317,29 @@ function muldivr(a, b, c) {
|
|
|
316
317
|
}
|
|
317
318
|
return (a * b + c / 2n) / c;
|
|
318
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* Normalize hash string to base64 format
|
|
322
|
+
* Accepts: base64, hex, or raw string
|
|
323
|
+
*/
|
|
324
|
+
function normalizeHashToBase64(hash) {
|
|
325
|
+
// If already base64 (contains +, /, = or matches base64 pattern)
|
|
326
|
+
if (/^[A-Za-z0-9+/]+={0,2}$/.test(hash)) {
|
|
327
|
+
try {
|
|
328
|
+
// Validate it's valid base64
|
|
329
|
+
Buffer.from(hash, 'base64');
|
|
330
|
+
return hash;
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// Fall through to hex conversion
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// Try as hex
|
|
337
|
+
if (/^[0-9a-fA-F]+$/.test(hash)) {
|
|
338
|
+
return Buffer.from(hash, 'hex').toString('base64');
|
|
339
|
+
}
|
|
340
|
+
// Assume it's already base64
|
|
341
|
+
return hash;
|
|
342
|
+
}
|
|
319
343
|
function getNormalizedExtMessageHash(message) {
|
|
320
344
|
if (message.info.type !== 'external-in') {
|
|
321
345
|
throw new Error(`Message must be "external-in", got ${message.info.type}`);
|
|
@@ -99,6 +99,7 @@ export type TransactionDepth = {
|
|
|
99
99
|
address?: Address;
|
|
100
100
|
hash: string;
|
|
101
101
|
depth: number;
|
|
102
|
+
hashType?: 'unknown' | 'in' | 'out';
|
|
102
103
|
};
|
|
103
104
|
export type AdjacentTransactionsResponse = {
|
|
104
105
|
transactions: ToncenterTransaction[];
|
|
@@ -123,22 +124,6 @@ export type ConvertedCurrencyRawResult = {
|
|
|
123
124
|
tacPrice: USDPriceInfoRaw;
|
|
124
125
|
tonPrice: USDPriceInfoRaw;
|
|
125
126
|
};
|
|
126
|
-
export type GetTransactionsOptions = {
|
|
127
|
-
limit: number;
|
|
128
|
-
lt?: string;
|
|
129
|
-
hash?: string;
|
|
130
|
-
to_lt?: string;
|
|
131
|
-
inclusive?: boolean;
|
|
132
|
-
archival?: boolean;
|
|
133
|
-
timeoutMs?: number;
|
|
134
|
-
retryDelayMs?: number;
|
|
135
|
-
};
|
|
136
|
-
export type AddressInformation = {
|
|
137
|
-
lastTransaction: {
|
|
138
|
-
lt: string;
|
|
139
|
-
hash: string;
|
|
140
|
-
};
|
|
141
|
-
};
|
|
142
127
|
export type TONFeesParams = {
|
|
143
128
|
accountBitPrice: number;
|
|
144
129
|
accountCellPrice: number;
|
|
@@ -4,7 +4,6 @@ import { AbstractProvider } from 'ethers';
|
|
|
4
4
|
import { JettonMinter, JettonMinterData } from '../../artifacts/tonTypes';
|
|
5
5
|
import type { FT, NFT } from '../assets';
|
|
6
6
|
import type { Asset, ContractOpener, ILogger } from '../interfaces';
|
|
7
|
-
import { ITxFinalizer } from '../interfaces/ITxFinalizer';
|
|
8
7
|
import { SendResult } from './InternalStruct';
|
|
9
8
|
export type ContractState = {
|
|
10
9
|
balance: bigint;
|
|
@@ -61,10 +60,6 @@ export type TONParams = {
|
|
|
61
60
|
* Address of TON settings contract. Use only for tests.
|
|
62
61
|
*/
|
|
63
62
|
settingsAddress?: string;
|
|
64
|
-
/**
|
|
65
|
-
* TxFinalizer for tracking transaction tree
|
|
66
|
-
*/
|
|
67
|
-
txFinalizer?: ITxFinalizer;
|
|
68
63
|
};
|
|
69
64
|
export type SDKParams = {
|
|
70
65
|
/**
|
|
@@ -451,7 +446,97 @@ export type TacGasPrice = {
|
|
|
451
446
|
fast: number;
|
|
452
447
|
slow: number;
|
|
453
448
|
};
|
|
449
|
+
/**
|
|
450
|
+
* Parameters for tracking and validating transaction trees
|
|
451
|
+
*/
|
|
454
452
|
export type TrackTransactionTreeParams = {
|
|
453
|
+
/**
|
|
454
|
+
* Maximum number of transactions to fetch per pagination request
|
|
455
|
+
* @default 100
|
|
456
|
+
*/
|
|
457
|
+
limit?: number;
|
|
458
|
+
/**
|
|
459
|
+
* Maximum depth to traverse in the transaction tree (prevents infinite loops)
|
|
460
|
+
* @default 10
|
|
461
|
+
*/
|
|
455
462
|
maxDepth?: number;
|
|
463
|
+
/**
|
|
464
|
+
* List of operation codes (opcodes) to skip during validation.
|
|
465
|
+
* Transactions with these opcodes in their incoming message will not be validated.
|
|
466
|
+
* @default [ 0xd53276db ] // Excess
|
|
467
|
+
*/
|
|
456
468
|
ignoreOpcodeList?: number[];
|
|
469
|
+
/**
|
|
470
|
+
* Direction to search the transaction tree:
|
|
471
|
+
* - 'forward': only search children (outgoing messages)
|
|
472
|
+
* - 'backward': only search parents (incoming messages)
|
|
473
|
+
* - 'both': search in both directions (default)
|
|
474
|
+
* @default 'both'
|
|
475
|
+
*/
|
|
476
|
+
direction?: 'forward' | 'backward' | 'both';
|
|
477
|
+
};
|
|
478
|
+
/**
|
|
479
|
+
* Details about a transaction validation error
|
|
480
|
+
*/
|
|
481
|
+
export type TransactionValidationError = {
|
|
482
|
+
/**
|
|
483
|
+
* Base64-encoded hash of the failed transaction
|
|
484
|
+
*/
|
|
485
|
+
txHash: string;
|
|
486
|
+
/**
|
|
487
|
+
* Exit code from the compute phase, or 'N/A' if compute phase is missing
|
|
488
|
+
*/
|
|
489
|
+
exitCode: number | 'N/A';
|
|
490
|
+
/**
|
|
491
|
+
* Result code from the action phase, or 'N/A' if action phase is missing
|
|
492
|
+
*/
|
|
493
|
+
resultCode: number | 'N/A';
|
|
494
|
+
/**
|
|
495
|
+
* Reason for validation failure:
|
|
496
|
+
* - 'aborted': default: transaction was aborted
|
|
497
|
+
* - 'compute_phase_missing': compute phase is missing or skipped
|
|
498
|
+
* - 'compute_phase_failed': compute phase failed (exitCode !== 0)
|
|
499
|
+
* - 'action_phase_failed': action phase failed (resultCode !== 0)
|
|
500
|
+
*/
|
|
501
|
+
reason: 'aborted' | 'compute_phase_missing' | 'compute_phase_failed' | 'action_phase_failed';
|
|
502
|
+
};
|
|
503
|
+
/**
|
|
504
|
+
* Result of transaction tree tracking and validation
|
|
505
|
+
*/
|
|
506
|
+
export type TrackTransactionTreeResult = {
|
|
507
|
+
/**
|
|
508
|
+
* Whether all transactions in the tree passed validation
|
|
509
|
+
*/
|
|
510
|
+
success: boolean;
|
|
511
|
+
/**
|
|
512
|
+
* Details about the first validation error encountered (if any)
|
|
513
|
+
*/
|
|
514
|
+
error?: TransactionValidationError;
|
|
515
|
+
};
|
|
516
|
+
export type GetTransactionsOptions = {
|
|
517
|
+
/** Maximum number of transactions to retrieve */
|
|
518
|
+
limit?: number;
|
|
519
|
+
/** Logical time of the transaction to start from */
|
|
520
|
+
lt?: string;
|
|
521
|
+
/** Hash of the transaction to start from */
|
|
522
|
+
hash?: string;
|
|
523
|
+
/** Logical time of the transaction to end at */
|
|
524
|
+
to_lt?: string;
|
|
525
|
+
/** Whether to include the starting transaction in the results */
|
|
526
|
+
inclusive?: boolean;
|
|
527
|
+
/** Whether to search in archival nodes for historical data */
|
|
528
|
+
archival?: boolean;
|
|
529
|
+
/** Request timeout in milliseconds */
|
|
530
|
+
timeoutMs?: number;
|
|
531
|
+
/** Delay between retry attempts in milliseconds */
|
|
532
|
+
retryDelayMs?: number;
|
|
533
|
+
};
|
|
534
|
+
export type AddressInformation = {
|
|
535
|
+
/** Information about the last transaction of the address */
|
|
536
|
+
lastTransaction: {
|
|
537
|
+
/** Logical time of the last transaction */
|
|
538
|
+
lt: string;
|
|
539
|
+
/** Hash of the last transaction */
|
|
540
|
+
hash: string;
|
|
541
|
+
};
|
|
457
542
|
};
|
package/package.json
CHANGED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Blockchain } from '@ton/sandbox';
|
|
2
|
-
import { Address, TonClient, Transaction } from '@ton/ton';
|
|
3
|
-
import { ContractOpener } from '../interfaces';
|
|
4
|
-
import { GetTransactionsOptions } from '../structs/InternalStruct';
|
|
5
|
-
import { Network } from '../structs/Struct';
|
|
6
|
-
export declare function getAdjacentTransactionsHelper(addr: Address, hashB64: string, getTransactions: (addr: Address, opts: GetTransactionsOptions) => Promise<Transaction[]>, opts?: GetTransactionsOptions): Promise<Transaction[]>;
|
|
7
|
-
type LiteServer = {
|
|
8
|
-
ip: number;
|
|
9
|
-
port: number;
|
|
10
|
-
id: {
|
|
11
|
-
'@type': string;
|
|
12
|
-
key: string;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
export declare function liteClientOpener(options: {
|
|
16
|
-
liteservers: LiteServer[];
|
|
17
|
-
} | {
|
|
18
|
-
network: Network;
|
|
19
|
-
}): Promise<ContractOpener>;
|
|
20
|
-
export declare function sandboxOpener(blockchain: Blockchain): ContractOpener;
|
|
21
|
-
export declare function orbsOpener(network: Network): Promise<ContractOpener>;
|
|
22
|
-
export declare function orbsOpener4(network: Network, timeout?: number): Promise<ContractOpener>;
|
|
23
|
-
export declare function tonClientOpener(client: TonClient): ContractOpener;
|
|
24
|
-
export {};
|