@tonappchain/sdk 0.7.2-payload-builder-0.1 → 0.7.2-payload-builder-0.3

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.
Files changed (39) hide show
  1. package/dist/artifacts/testnet/ton/internal/build/CrossChainLayer.compiled.json +1 -1
  2. package/dist/artifacts/testnet/ton/internal/build/Executor.compiled.json +1 -1
  3. package/dist/artifacts/testnet/ton/internal/build/JettonMinter.compiled.json +1 -1
  4. package/dist/artifacts/testnet/ton/internal/build/JettonProxy.compiled.json +1 -1
  5. package/dist/artifacts/testnet/ton/internal/build/JettonWallet.compiled.json +1 -1
  6. package/dist/artifacts/testnet/ton/internal/build/NFTItem.compiled.json +1 -1
  7. package/dist/artifacts/testnet/ton/internal/build/NFTProxy.compiled.json +1 -1
  8. package/dist/artifacts/testnet/ton/internal/wrappers/CrossChainLayer.d.ts +13 -1
  9. package/dist/artifacts/testnet/ton/internal/wrappers/CrossChainLayer.js +45 -7
  10. package/dist/artifacts/testnet/ton/internal/wrappers/JettonMinter.d.ts +2 -2
  11. package/dist/artifacts/testnet/ton/internal/wrappers/JettonMinter.js +2 -2
  12. package/dist/src/adapters/contractOpener.d.ts +4 -0
  13. package/dist/src/adapters/contractOpener.js +165 -1
  14. package/dist/src/adapters/retryableContractOpener.d.ts +5 -1
  15. package/dist/src/adapters/retryableContractOpener.js +22 -4
  16. package/dist/src/index.d.ts +0 -1
  17. package/dist/src/index.js +1 -4
  18. package/dist/src/interfaces/ContractOpener.d.ts +5 -1
  19. package/dist/src/interfaces/ITxFinalizer.d.ts +5 -0
  20. package/dist/src/interfaces/ITxFinalizer.js +2 -0
  21. package/dist/src/interfaces/WalletInstanse.d.ts +4 -8
  22. package/dist/src/sdk/StartTracking.d.ts +5 -3
  23. package/dist/src/sdk/StartTracking.js +60 -40
  24. package/dist/src/sdk/TONTransactionManager.d.ts +3 -1
  25. package/dist/src/sdk/TONTransactionManager.js +16 -3
  26. package/dist/src/sdk/TacSdk.js +3 -1
  27. package/dist/src/sdk/TxFinalizer.d.ts +15 -4
  28. package/dist/src/sdk/TxFinalizer.js +102 -23
  29. package/dist/src/sdk/Utils.d.ts +6 -1
  30. package/dist/src/sdk/Utils.js +37 -0
  31. package/dist/src/sender/BatchSender.js +19 -0
  32. package/dist/src/sender/RawSender.js +34 -1
  33. package/dist/src/sender/SenderFactory.js +1 -1
  34. package/dist/src/sender/TonConnectSender.js +2 -0
  35. package/dist/src/structs/InternalStruct.d.ts +19 -1
  36. package/dist/src/structs/Struct.d.ts +13 -1
  37. package/dist/src/wrappers/HighloadWalletV3.d.ts +5 -3
  38. package/dist/src/wrappers/HighloadWalletV3.js +14 -3
  39. package/package.json +2 -3
@@ -10,7 +10,6 @@ export { LiteSequencerClient } from './sdk/LiteSequencerClient';
10
10
  export { ConsoleLogger, NoopLogger } from './sdk/Logger';
11
11
  export { OperationTracker } from './sdk/OperationTracker';
12
12
  export { Simulator } from './sdk/Simulator';
13
- export { startTracking, startTrackingMultiple } from './sdk/StartTracking';
14
13
  export { TacSdk } from './sdk/TacSdk';
15
14
  export { TACTransactionManager } from './sdk/TACTransactionManager';
16
15
  export { TONTransactionManager } from './sdk/TONTransactionManager';
package/dist/src/index.js CHANGED
@@ -36,7 +36,7 @@ var __importStar = (this && this.__importStar) || (function () {
36
36
  };
37
37
  })();
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.TONTransactionManager = exports.TACTransactionManager = exports.TacSdk = exports.startTrackingMultiple = exports.startTracking = exports.Simulator = exports.OperationTracker = exports.NoopLogger = exports.ConsoleLogger = exports.LiteSequencerClient = exports.Configuration = exports.AxiosHttpClient = exports.AgnosticStructs = exports.AgnosticProxySDK = void 0;
39
+ exports.TONTransactionManager = exports.TACTransactionManager = exports.TacSdk = exports.Simulator = exports.OperationTracker = exports.NoopLogger = exports.ConsoleLogger = exports.LiteSequencerClient = exports.Configuration = exports.AxiosHttpClient = exports.AgnosticStructs = exports.AgnosticProxySDK = void 0;
40
40
  __exportStar(require("./adapters"), exports);
41
41
  var AgnosticSdk_1 = require("./agnosticSdk/AgnosticSdk");
42
42
  Object.defineProperty(exports, "AgnosticProxySDK", { enumerable: true, get: function () { return AgnosticSdk_1.AgnosticProxySDK; } });
@@ -57,9 +57,6 @@ var OperationTracker_1 = require("./sdk/OperationTracker");
57
57
  Object.defineProperty(exports, "OperationTracker", { enumerable: true, get: function () { return OperationTracker_1.OperationTracker; } });
58
58
  var Simulator_1 = require("./sdk/Simulator");
59
59
  Object.defineProperty(exports, "Simulator", { enumerable: true, get: function () { return Simulator_1.Simulator; } });
60
- var StartTracking_1 = require("./sdk/StartTracking");
61
- Object.defineProperty(exports, "startTracking", { enumerable: true, get: function () { return StartTracking_1.startTracking; } });
62
- Object.defineProperty(exports, "startTrackingMultiple", { enumerable: true, get: function () { return StartTracking_1.startTrackingMultiple; } });
63
60
  var TacSdk_1 = require("./sdk/TacSdk");
64
61
  Object.defineProperty(exports, "TacSdk", { enumerable: true, get: function () { return TacSdk_1.TacSdk; } });
65
62
  var TACTransactionManager_1 = require("./sdk/TACTransactionManager");
@@ -1,5 +1,6 @@
1
1
  import { SandboxContract } from '@ton/sandbox';
2
- import type { Address, Contract, OpenedContract } from '@ton/ton';
2
+ import type { Address, Contract, OpenedContract, Transaction } from '@ton/ton';
3
+ import { AddressInformation, GetTransactionsOptions } from '../structs/InternalStruct';
3
4
  import { ContractState } from '../structs/Struct';
4
5
  export interface ContractOpener {
5
6
  /**
@@ -18,4 +19,7 @@ export interface ContractOpener {
18
19
  * Closes any underlying connections if supported by the implementation.
19
20
  */
20
21
  closeConnections?: () => unknown;
22
+ getTransactionByHash(address: Address, hash: string, opts?: GetTransactionsOptions): Promise<Transaction | null>;
23
+ getAdjacentTransactions(address: Address, hash: string, opts?: GetTransactionsOptions): Promise<Transaction[]>;
24
+ getAddressInformation(address: Address): Promise<AddressInformation>;
21
25
  }
@@ -0,0 +1,5 @@
1
+ export interface ITxFinalizer {
2
+ trackTransactionTree(address: string, hash: string, params: {
3
+ maxDepth?: number;
4
+ }): Promise<void>;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,20 +1,16 @@
1
- import type { Contract, ContractProvider, MessageRelaxed, SendMode } from '@ton/ton';
1
+ import type { Cell, Contract, ContractProvider, MessageRelaxed, SendMode } from '@ton/ton';
2
2
  export interface WalletInstanse extends Contract {
3
3
  /**
4
4
  * Returns current wallet seqno, used for nonce/ordering.
5
5
  * @param provider Contract provider to query the wallet.
6
6
  */
7
7
  getSeqno(provider: ContractProvider): Promise<number>;
8
- /**
9
- * Sends a transfer with specified messages and send mode.
10
- * @param provider Contract provider used to send the transfer.
11
- * @param args Transfer arguments including seqno, secretKey, messages and sendMode.
12
- */
13
- sendTransfer(provider: ContractProvider, args: {
8
+ send(provider: ContractProvider, msg: Cell): Promise<string | void>;
9
+ createTransfer(args: {
14
10
  seqno: number;
15
11
  secretKey: Buffer;
16
12
  messages: MessageRelaxed[];
17
13
  sendMode: SendMode;
18
14
  timeout?: number;
19
- }): Promise<void>;
15
+ }): Cell;
20
16
  }
@@ -1,5 +1,5 @@
1
1
  import { ILogger } from '../interfaces';
2
- import { TxFinalizerConfig } from '../structs/InternalStruct';
2
+ import { ITxFinalizer } from '../interfaces/ITxFinalizer';
3
3
  import { ExecutionStages, Network, TransactionLinker } from '../structs/Struct';
4
4
  export declare function startTracking(transactionLinker: TransactionLinker, network: Network, options?: {
5
5
  customLiteSequencerEndpoints?: string[];
@@ -7,8 +7,9 @@ export declare function startTracking(transactionLinker: TransactionLinker, netw
7
7
  maxIterationCount?: number;
8
8
  returnValue?: boolean;
9
9
  tableView?: boolean;
10
- txFinalizerConfig?: TxFinalizerConfig;
11
10
  logger?: ILogger;
11
+ txFinalizer?: ITxFinalizer;
12
+ cclAddress?: string;
12
13
  }): Promise<void | ExecutionStages>;
13
14
  export declare function startTrackingMultiple(transactionLinkers: TransactionLinker[], network: Network, options?: {
14
15
  customLiteSequencerEndpoints?: string[];
@@ -16,6 +17,7 @@ export declare function startTrackingMultiple(transactionLinkers: TransactionLin
16
17
  maxIterationCount?: number;
17
18
  returnValue?: boolean;
18
19
  tableView?: boolean;
19
- txFinalizerConfig?: TxFinalizerConfig;
20
20
  logger?: ILogger;
21
+ txFinalizer?: ITxFinalizer;
21
22
  }): Promise<void | ExecutionStages[]>;
23
+ export declare function printExecutionStagesTable(stages: ExecutionStages, logger: ILogger): void;
@@ -1,19 +1,15 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.startTracking = startTracking;
7
4
  exports.startTrackingMultiple = startTrackingMultiple;
8
- const cli_table3_1 = __importDefault(require("cli-table3"));
5
+ exports.printExecutionStagesTable = printExecutionStagesTable;
9
6
  const Struct_1 = require("../structs/Struct");
10
7
  const Consts_1 = require("./Consts");
11
8
  const Logger_1 = require("./Logger");
12
9
  const OperationTracker_1 = require("./OperationTracker");
13
- const TxFinalizer_1 = require("./TxFinalizer");
14
10
  const Utils_1 = require("./Utils");
15
11
  async function startTracking(transactionLinker, network, options) {
16
- const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true, txFinalizerConfig, logger = new Logger_1.NoopLogger(), } = options || {};
12
+ const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true, logger = new Logger_1.NoopLogger(), txFinalizer, cclAddress, } = options || {};
17
13
  const tracker = new OperationTracker_1.OperationTracker(network, customLiteSequencerEndpoints, logger);
18
14
  logger.debug('Start tracking operation');
19
15
  logger.debug('caller: ' + transactionLinker.caller);
@@ -70,13 +66,12 @@ async function startTracking(transactionLinker, network, options) {
70
66
  // Check if EXECUTED_IN_TON stage exists and use TxFinalizer to verify transaction success
71
67
  if (profilingData.executedInTON.exists && profilingData.executedInTON.stageData?.transactions) {
72
68
  logger.debug('EXECUTED_IN_TON stage found, verifying transaction success in TON...');
73
- if (txFinalizerConfig) {
74
- const txFinalizer = new TxFinalizer_1.TonTxFinalizer(txFinalizerConfig, logger);
69
+ if (txFinalizer && cclAddress) {
75
70
  const transactions = profilingData.executedInTON.stageData.transactions;
76
71
  for (const tx of transactions) {
77
72
  try {
78
73
  logger.debug(`Verifying transaction: ${tx.hash}`);
79
- await txFinalizer.trackTransactionTree(tx.hash);
74
+ await txFinalizer.trackTransactionTree(cclAddress, tx.hash, { maxDepth: 10 });
80
75
  logger.debug(`Transaction ${tx.hash} verified successfully in TON`);
81
76
  }
82
77
  catch (error) {
@@ -104,7 +99,7 @@ async function startTracking(transactionLinker, network, options) {
104
99
  }
105
100
  }
106
101
  async function startTrackingMultiple(transactionLinkers, network, options) {
107
- const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true, txFinalizerConfig, logger = new Logger_1.NoopLogger(), } = options || {};
102
+ const { customLiteSequencerEndpoints, delay = 10, maxIterationCount = Consts_1.MAX_ITERATION_COUNT, returnValue = false, tableView = true, txFinalizer, logger = new Logger_1.NoopLogger(), } = options || {};
108
103
  logger.debug(`Start tracking ${transactionLinkers.length} operations`);
109
104
  const results = await Promise.all(transactionLinkers.map((linker, index) => {
110
105
  logger.debug(`\nProcessing operation ${index + 1}/${transactionLinkers.length}`);
@@ -114,7 +109,7 @@ async function startTrackingMultiple(transactionLinkers, network, options) {
114
109
  maxIterationCount,
115
110
  returnValue: true,
116
111
  tableView: false,
117
- txFinalizerConfig,
112
+ txFinalizer,
118
113
  logger,
119
114
  });
120
115
  }));
@@ -160,35 +155,60 @@ function formatExecutionStages(stages) {
160
155
  bytesError: data.exists && data.stageData && data.stageData.note != null ? data.stageData.note.internalBytesError : '-',
161
156
  }));
162
157
  }
163
- function printExecutionStagesTable(stages, logger) {
164
- const table = new cli_table3_1.default({
165
- head: [
166
- 'Stage',
167
- 'Exists',
168
- 'Success',
169
- 'Timestamp',
170
- 'Transactions',
171
- 'NoteContent',
172
- 'ErrorName',
173
- 'InternalMsg',
174
- 'BytesError',
175
- ],
176
- colWidths: [30, 8, 9, 13, 70, 13, 13, 13, 13],
177
- wordWrap: true,
158
+ /**
159
+ * Simple table formatter that works in both browser and Node.js without external dependencies
160
+ */
161
+ function createSimpleTable(headers, rows, colWidths) {
162
+ const lines = [];
163
+ // Helper to truncate and pad text to fit column width
164
+ const fitToWidth = (text, width) => {
165
+ // Handle multi-line text by taking only the first line for table cell
166
+ const firstLine = text.split('\n')[0];
167
+ if (firstLine.length > width - 2) {
168
+ return firstLine.substring(0, width - 5) + '...';
169
+ }
170
+ return firstLine.padEnd(width, ' ');
171
+ };
172
+ // Create separator line
173
+ const separator = '+' + colWidths.map((w) => '-'.repeat(w)).join('+') + '+';
174
+ // Create header row
175
+ const headerRow = '|' + headers.map((h, i) => fitToWidth(h, colWidths[i])).join('|') + '|';
176
+ lines.push(separator);
177
+ lines.push(headerRow);
178
+ lines.push(separator);
179
+ // Create data rows
180
+ rows.forEach((row) => {
181
+ const dataRow = '|' + row.map((cell, i) => fitToWidth(cell, colWidths[i])).join('|') + '|';
182
+ lines.push(dataRow);
178
183
  });
184
+ lines.push(separator);
185
+ return lines.join('\n');
186
+ }
187
+ function printExecutionStagesTable(stages, logger) {
188
+ const headers = [
189
+ 'Stage',
190
+ 'Exists',
191
+ 'Success',
192
+ 'Timestamp',
193
+ 'Transactions',
194
+ 'NoteContent',
195
+ 'ErrorName',
196
+ 'InternalMsg',
197
+ 'BytesError',
198
+ ];
199
+ const colWidths = [30, 8, 9, 13, 70, 13, 13, 13, 13];
179
200
  const tableData = formatExecutionStages(stages);
180
- tableData.forEach((row) => {
181
- table.push([
182
- row.stage,
183
- row.exists,
184
- row.success,
185
- row.timestamp,
186
- row.transactions,
187
- row.noteContent,
188
- row.errorName,
189
- row.internalMsg,
190
- row.bytesError,
191
- ]);
192
- });
193
- logger.debug(table.toString());
201
+ const rows = tableData.map((row) => [
202
+ row.stage,
203
+ row.exists,
204
+ row.success,
205
+ row.timestamp,
206
+ row.transactions,
207
+ row.noteContent,
208
+ row.errorName,
209
+ row.internalMsg,
210
+ row.bytesError,
211
+ ]);
212
+ const table = createSimpleTable(headers, rows, colWidths);
213
+ logger.debug(table);
194
214
  }
@@ -1,4 +1,5 @@
1
1
  import { Asset, IConfiguration, ILogger, IOperationTracker, ISimulator, ITONTransactionManager } from '../interfaces';
2
+ import { ITxFinalizer } from '../interfaces/ITxFinalizer';
2
3
  import type { SenderAbstraction } from '../sender';
3
4
  import { BatchCrossChainTx, CrossChainPayloadResult, CrossChainTransactionOptions, CrossChainTransactionsOptions, CrosschainTx, EvmProxyMsg, FeeParams, TransactionLinkerWithOperationId } from '../structs/Struct';
4
5
  export declare class TONTransactionManager implements ITONTransactionManager {
@@ -6,7 +7,8 @@ export declare class TONTransactionManager implements ITONTransactionManager {
6
7
  private readonly simulator;
7
8
  private readonly operationTracker;
8
9
  private readonly logger;
9
- constructor(config: IConfiguration, simulator: ISimulator, operationTracker: IOperationTracker, logger?: ILogger);
10
+ private readonly txFinalizer;
11
+ constructor(config: IConfiguration, simulator: ISimulator, operationTracker: IOperationTracker, logger: ILogger | undefined, txFinalizer: ITxFinalizer);
10
12
  buildFeeParams(options: CrossChainTransactionOptions, evmProxyMsg: EvmProxyMsg, sender: SenderAbstraction, tx: CrosschainTx): Promise<FeeParams>;
11
13
  private prepareCrossChainTransaction;
12
14
  private generateCrossChainMessages;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TONTransactionManager = void 0;
4
+ const ton_1 = require("@ton/ton");
4
5
  const assets_1 = require("../assets");
5
6
  const errors_1 = require("../errors");
6
7
  const instances_1 = require("../errors/instances");
@@ -9,11 +10,12 @@ const Logger_1 = require("./Logger");
9
10
  const Utils_1 = require("./Utils");
10
11
  const Validator_1 = require("./Validator");
11
12
  class TONTransactionManager {
12
- constructor(config, simulator, operationTracker, logger = new Logger_1.NoopLogger()) {
13
+ constructor(config, simulator, operationTracker, logger = new Logger_1.NoopLogger(), txFinalizer) {
13
14
  this.config = config;
14
15
  this.simulator = simulator;
15
16
  this.operationTracker = operationTracker;
16
17
  this.logger = logger;
18
+ this.txFinalizer = txFinalizer;
17
19
  }
18
20
  async buildFeeParams(options, evmProxyMsg, sender, tx) {
19
21
  const { withoutSimulation, protocolFee, evmExecutorFee, tvmExecutorFee, isRoundTrip } = options;
@@ -155,7 +157,17 @@ class TONTransactionManager {
155
157
  if (!shouldWaitForOperationId) {
156
158
  return { sendTransactionResult, ...transactionLinker };
157
159
  }
158
- const waitOptions = tx.options?.waitOptions ?? {};
160
+ const waitOptions = tx.options?.waitOptions ?? {
161
+ ensureTxExecuted: true,
162
+ };
163
+ if (waitOptions.ensureTxExecuted && sendTransactionResult.boc) {
164
+ const hash = (0, Utils_1.getNormalizedExtMessageHash)((0, ton_1.loadMessage)(ton_1.Cell.fromBase64(sendTransactionResult.boc).beginParse()));
165
+ this.logger.info(`Tracking transaction tree for hash: ${hash}`);
166
+ await this.txFinalizer.trackTransactionTree(sender.getSenderAddress(), hash, {
167
+ maxDepth: 10,
168
+ });
169
+ this.logger.info(`Transaction tree successful`);
170
+ }
159
171
  waitOptions.successCheck = waitOptions.successCheck ?? ((id) => !!id);
160
172
  waitOptions.logger = waitOptions.logger ?? this.logger;
161
173
  const operationId = await this.operationTracker
@@ -226,7 +238,7 @@ class TONTransactionManager {
226
238
  this.logger.debug('Preparing cross-chain transaction payload');
227
239
  const mockSender = {
228
240
  getSenderAddress: () => senderAddress,
229
- sendShardTransaction: async () => ({ success: true }),
241
+ sendShardTransaction: async () => ({ success: true, boc: '' }),
230
242
  sendShardTransactions: async () => [],
231
243
  getBalance: async () => 0n,
232
244
  getBalanceOf: async () => 0n,
@@ -237,6 +249,7 @@ class TONTransactionManager {
237
249
  destinationAddress: r.address,
238
250
  tonAmount: r.value,
239
251
  networkFee: r.extra.networkFeeIncluded,
252
+ transactionLinker: result.transactionLinker,
240
253
  }));
241
254
  }
242
255
  }
@@ -11,6 +11,7 @@ const OperationTracker_1 = require("./OperationTracker");
11
11
  const Simulator_1 = require("./Simulator");
12
12
  const TACTransactionManager_1 = require("./TACTransactionManager");
13
13
  const TONTransactionManager_1 = require("./TONTransactionManager");
14
+ const TxFinalizer_1 = require("./TxFinalizer");
14
15
  const Utils_1 = require("./Utils");
15
16
  class TacSdk {
16
17
  constructor(config, simulator, tonTransactionManager, tacTransactionManager, operationTracker) {
@@ -40,7 +41,8 @@ class TacSdk {
40
41
  const config = await Configuration_1.Configuration.create(network, artifacts, sdkParams.TONParams, sdkParams.TACParams, sdkParams.customLiteSequencerEndpoints, delay);
41
42
  const operationTracker = new OperationTracker_1.OperationTracker(network, config.liteSequencerEndpoints);
42
43
  const simulator = new Simulator_1.Simulator(config, operationTracker, logger);
43
- const tonTransactionManager = new TONTransactionManager_1.TONTransactionManager(config, simulator, operationTracker, logger);
44
+ const txFinalizer = sdkParams.TONParams?.txFinalizer ?? new TxFinalizer_1.TonTxFinalizer(config.TONParams.contractOpener, logger);
45
+ const tonTransactionManager = new TONTransactionManager_1.TONTransactionManager(config, simulator, operationTracker, logger, txFinalizer);
44
46
  const tacTransactionManager = new TACTransactionManager_1.TACTransactionManager(config, operationTracker, logger);
45
47
  return new TacSdk(config, simulator, tonTransactionManager, tacTransactionManager, operationTracker);
46
48
  }
@@ -1,11 +1,22 @@
1
- import { IHttpClient, ILogger } from '../interfaces';
1
+ import { ContractOpener, IHttpClient, ILogger } from '../interfaces';
2
+ import { ITxFinalizer } from '../interfaces/ITxFinalizer';
2
3
  import { TxFinalizerConfig } from '../structs/InternalStruct';
3
- export declare class TonTxFinalizer {
4
+ export declare class TonTxFinalizer implements ITxFinalizer {
5
+ private logger;
6
+ private contractOpener;
7
+ constructor(contractOpener: ContractOpener, logger?: ILogger);
8
+ private fetchAdjacentTransactions;
9
+ trackTransactionTree(address: string, hash: string, params: {
10
+ maxDepth?: number;
11
+ }): Promise<void>;
12
+ }
13
+ export declare class TonTxFinalizerV3 implements ITxFinalizer {
4
14
  private logger;
5
15
  private apiConfig;
6
16
  private readonly httpClient;
7
17
  constructor(apiConfig: TxFinalizerConfig, logger?: ILogger, httpClient?: IHttpClient);
8
- private logHashFormats;
9
18
  private fetchAdjacentTransactions;
10
- trackTransactionTree(hash: string, maxDepth?: number): Promise<void>;
19
+ trackTransactionTree(_: string, hash: string, params?: {
20
+ maxDepth?: number;
21
+ }): Promise<void>;
11
22
  }
@@ -1,33 +1,111 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TonTxFinalizer = void 0;
3
+ exports.TonTxFinalizerV3 = exports.TonTxFinalizer = void 0;
4
+ const ton_1 = require("@ton/ton");
4
5
  const AxiosHttpClient_1 = require("./AxiosHttpClient");
5
6
  const Logger_1 = require("./Logger");
6
7
  const Utils_1 = require("./Utils");
7
8
  const IGNORE_OPCODE = [
8
- '0xd53276db', // Excess
9
- '0x7362d09c', // Jetton Notify
9
+ 0xd53276db, // Excess
10
+ 0x7362d09c, // Jetton Notify
10
11
  ];
11
12
  class TonTxFinalizer {
12
- constructor(apiConfig, logger = new Logger_1.NoopLogger(), httpClient = new AxiosHttpClient_1.AxiosHttpClient()) {
13
- this.apiConfig = apiConfig;
13
+ constructor(contractOpener, logger = new Logger_1.NoopLogger()) {
14
+ this.contractOpener = contractOpener;
14
15
  this.logger = logger;
15
- this.httpClient = httpClient;
16
16
  }
17
- logHashFormats(hash) {
18
- let hex, base64;
19
- if (hash.startsWith('0x')) {
20
- hex = hash;
21
- const cleanHex = hex.slice(2);
22
- const buffer = Buffer.from(cleanHex, 'hex');
23
- base64 = buffer.toString('base64');
17
+ // Fetches adjacent transactions from toncenter
18
+ async fetchAdjacentTransactions(address, hash, retries = 5, delay = 1000, opts) {
19
+ for (let i = retries; i >= 0; i--) {
20
+ try {
21
+ const txs = await this.contractOpener.getAdjacentTransactions(address, hash, opts);
22
+ return txs;
23
+ }
24
+ catch (error) {
25
+ const errorMessage = error.message;
26
+ // Rate limit error (429) - retry
27
+ if (errorMessage.includes('429')) {
28
+ if (i > 0) {
29
+ await (0, Utils_1.sleep)(delay);
30
+ }
31
+ continue;
32
+ }
33
+ // Log all errors except 404 Not Found
34
+ if (!errorMessage.includes('404')) {
35
+ const logMessage = error instanceof Error ? error.message : error;
36
+ this.logger.warn(`Failed to fetch adjacent transactions for ${hash}:`, logMessage);
37
+ }
38
+ if (i > 0) {
39
+ await (0, Utils_1.sleep)(delay);
40
+ }
41
+ }
24
42
  }
25
- else {
26
- base64 = hash;
27
- const buffer = Buffer.from(base64, 'base64');
28
- hex = '0x' + buffer.toString('hex');
43
+ return [];
44
+ }
45
+ // Checks if all transactions in the tree are successful
46
+ async trackTransactionTree(address, hash, params) {
47
+ const { maxDepth = 10 } = params;
48
+ const parsedAddress = ton_1.Address.parse(address);
49
+ const visitedHashes = new Set();
50
+ const queue = [{ address: parsedAddress, hash, depth: 0 }];
51
+ while (queue.length > 0) {
52
+ const { hash: currentHash, depth: currentDepth, address: currentAddress } = queue.shift();
53
+ if (visitedHashes.has(currentHash)) {
54
+ continue;
55
+ }
56
+ visitedHashes.add(currentHash);
57
+ this.logger.debug(`Checking hash (depth ${currentDepth}): ${currentHash}`);
58
+ const transactions = await this.fetchAdjacentTransactions(currentAddress, currentHash, 5, 1000, {
59
+ limit: 10,
60
+ archival: true,
61
+ });
62
+ console.log(`Found ${transactions.length} adjacent transactions for ${currentHash}`);
63
+ if (transactions.length === 0)
64
+ continue;
65
+ for (const tx of transactions) {
66
+ if (tx.description.type !== 'generic' || !tx.inMessage)
67
+ continue;
68
+ const bodySlice = tx.inMessage.body.beginParse();
69
+ if (bodySlice.remainingBits < 32)
70
+ continue;
71
+ const opcode = bodySlice.loadUint(32);
72
+ if (!IGNORE_OPCODE.includes(opcode)) {
73
+ const { aborted, computePhase, actionPhase } = tx.description;
74
+ if (aborted ||
75
+ computePhase.type == 'skipped' ||
76
+ !computePhase.success ||
77
+ computePhase.exitCode !== 0 ||
78
+ (actionPhase && (!actionPhase.success || actionPhase.resultCode !== 0))) {
79
+ throw new Error(`Transaction failed:\n` +
80
+ `hash = ${currentHash}, ` +
81
+ `aborted = ${aborted}, ` +
82
+ `compute phase: ${computePhase.type === 'skipped' ? 'skipped' : `success = ${computePhase.success}, exit code = ${computePhase.exitCode}`}, ` +
83
+ `action phase: ${!actionPhase ? 'skipped' : `success = ${actionPhase.success}, result code = ${actionPhase.resultCode}`} `);
84
+ }
85
+ if (currentDepth + 1 < maxDepth) {
86
+ if (tx.outMessages.size > 0) {
87
+ queue.push({
88
+ hash: tx.hash().toString('base64'),
89
+ address: tx.inMessage.info.dest,
90
+ depth: currentDepth + 1,
91
+ });
92
+ }
93
+ }
94
+ }
95
+ else {
96
+ this.logger.debug(`Skipping hash (depth ${currentDepth}): ${tx.hash().toString('base64')}`);
97
+ }
98
+ }
99
+ this.logger.debug(`Finished checking hash (depth ${currentDepth}): ${currentHash}`);
29
100
  }
30
- return { hex: hex, base64: base64 };
101
+ }
102
+ }
103
+ exports.TonTxFinalizer = TonTxFinalizer;
104
+ class TonTxFinalizerV3 {
105
+ constructor(apiConfig, logger = new Logger_1.NoopLogger(), httpClient = new AxiosHttpClient_1.AxiosHttpClient()) {
106
+ this.apiConfig = apiConfig;
107
+ this.logger = logger;
108
+ this.httpClient = httpClient;
31
109
  }
32
110
  // Fetches adjacent transactions from toncenter
33
111
  async fetchAdjacentTransactions(hash, retries = 5, delay = 1000) {
@@ -64,7 +142,8 @@ class TonTxFinalizer {
64
142
  return [];
65
143
  }
66
144
  // Checks if all transactions in the tree are successful
67
- async trackTransactionTree(hash, maxDepth = 10) {
145
+ async trackTransactionTree(_, hash, params = { maxDepth: 10 }) {
146
+ const { maxDepth = 10 } = params;
68
147
  const visitedHashes = new Set();
69
148
  const queue = [{ hash, depth: 0 }];
70
149
  while (queue.length > 0) {
@@ -73,12 +152,12 @@ class TonTxFinalizer {
73
152
  continue;
74
153
  }
75
154
  visitedHashes.add(currentHash);
76
- this.logger.debug(`Checking hash (depth ${currentDepth}):\nhex: ${this.logHashFormats(currentHash).hex}\nbase64: ${this.logHashFormats(currentHash).base64}`);
155
+ this.logger.debug(`Checking hash (depth ${currentDepth}): ${currentHash}`);
77
156
  const transactions = await this.fetchAdjacentTransactions(currentHash);
78
157
  if (transactions.length === 0)
79
158
  continue;
80
159
  for (const tx of transactions) {
81
- if (!IGNORE_OPCODE.includes(tx.inMsg.opcode) && tx.inMsg.opcode !== null) {
160
+ if (!IGNORE_OPCODE.includes(Number(tx.inMsg.opcode)) && tx.inMsg.opcode !== null) {
82
161
  const { aborted, computePh: compute_ph, action } = tx.description;
83
162
  if (aborted ||
84
163
  !compute_ph.success ||
@@ -100,10 +179,10 @@ class TonTxFinalizer {
100
179
  }
101
180
  }
102
181
  else {
103
- this.logger.debug(`Skipping hash (depth ${currentDepth}):\nhex: ${this.logHashFormats(tx.hash).hex}\nbase64: ${this.logHashFormats(tx.hash).base64}`);
182
+ this.logger.debug(`Skipping hash (depth ${currentDepth}): ${tx.hash}`);
104
183
  }
105
184
  }
106
185
  }
107
186
  }
108
187
  }
109
- exports.TonTxFinalizer = TonTxFinalizer;
188
+ exports.TonTxFinalizerV3 = TonTxFinalizerV3;
@@ -1,4 +1,4 @@
1
- import { Address, Cell } from '@ton/ton';
1
+ import { Address, Cell, Message } from '@ton/ton';
2
2
  import { AbiCoder } from 'ethers';
3
3
  import type { FT, NFT, TON } from '../assets';
4
4
  import { Asset, IConfiguration } from '../interfaces';
@@ -32,3 +32,8 @@ export declare function normalizeAssets(config: IConfiguration, assets?: AssetLi
32
32
  export declare function getAddressString(cell?: Cell): string;
33
33
  export declare function getNumber(len: number, cell?: Cell): number;
34
34
  export declare function getString(cell?: Cell): string;
35
+ export declare function getNormalizedExtMessageHash(message: Message): string;
36
+ export declare function retry<T>(fn: () => Promise<T>, options: {
37
+ retries: number;
38
+ delay: number;
39
+ }): Promise<T>;
@@ -19,6 +19,8 @@ exports.normalizeAssets = normalizeAssets;
19
19
  exports.getAddressString = getAddressString;
20
20
  exports.getNumber = getNumber;
21
21
  exports.getString = getString;
22
+ exports.getNormalizedExtMessageHash = getNormalizedExtMessageHash;
23
+ exports.retry = retry;
22
24
  const ton_1 = require("@ton/ton");
23
25
  const ethers_1 = require("ethers");
24
26
  const ton_crypto_1 = require("ton-crypto");
@@ -299,3 +301,38 @@ function getNumber(len, cell) {
299
301
  function getString(cell) {
300
302
  return cell?.beginParse().loadStringTail() ?? '';
301
303
  }
304
+ function getNormalizedExtMessageHash(message) {
305
+ if (message.info.type !== 'external-in') {
306
+ throw new Error(`Message must be "external-in", got ${message.info.type}`);
307
+ }
308
+ const info = {
309
+ ...message.info,
310
+ src: undefined,
311
+ importFee: 0n,
312
+ };
313
+ const normalizedMessage = {
314
+ ...message,
315
+ init: null,
316
+ info: info,
317
+ };
318
+ return (0, ton_1.beginCell)()
319
+ .store((0, ton_1.storeMessage)(normalizedMessage, { forceRef: true }))
320
+ .endCell()
321
+ .hash()
322
+ .toString('base64');
323
+ }
324
+ async function retry(fn, options) {
325
+ let lastError;
326
+ for (let i = 0; i < options.retries; i++) {
327
+ try {
328
+ return await fn();
329
+ }
330
+ catch (e) {
331
+ if (e instanceof Error) {
332
+ lastError = e;
333
+ }
334
+ await new Promise((resolve) => setTimeout(resolve, options.delay));
335
+ }
336
+ }
337
+ throw lastError;
338
+ }
@@ -38,7 +38,16 @@ class BatchSender {
38
38
  for (const group of groups) {
39
39
  try {
40
40
  const result = await this.sendGroup(group, contractOpener);
41
+ // Extract BoC if it's a string, or from sandbox result
42
+ let externalMsgBoc = '';
43
+ if (typeof result === 'string') {
44
+ externalMsgBoc = result;
45
+ }
46
+ else if (result?.result) {
47
+ externalMsgBoc = result.result;
48
+ }
41
49
  results.push({
50
+ boc: externalMsgBoc,
42
51
  success: true,
43
52
  result,
44
53
  lastMessageIndex: currentMessageIndex + group.length - 1,
@@ -46,6 +55,7 @@ class BatchSender {
46
55
  }
47
56
  catch (error) {
48
57
  results.push({
58
+ boc: '',
49
59
  success: false,
50
60
  error: error,
51
61
  lastMessageIndex: currentMessageIndex - 1,
@@ -118,7 +128,16 @@ class BatchSender {
118
128
  }));
119
129
  }
120
130
  const result = await this.sendGroup(messages, contractOpener);
131
+ // Extract BoC if it's a string, or from sandbox result
132
+ let externalMsgBoc = '';
133
+ if (typeof result === 'string') {
134
+ externalMsgBoc = result;
135
+ }
136
+ else if (result?.result) {
137
+ externalMsgBoc = result.result;
138
+ }
121
139
  return {
140
+ boc: externalMsgBoc,
122
141
  success: true,
123
142
  result,
124
143
  lastMessageIndex: shardTransaction.messages.length - 1,