@tonappchain/sdk 0.7.1 → 0.7.2-alpha-1

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 (74) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +198 -198
  3. package/dist/artifacts/dev/ton/internal/build/CrossChainLayer.compiled.json +1 -1
  4. package/dist/artifacts/dev/ton/internal/build/Executor.compiled.json +1 -1
  5. package/dist/artifacts/dev/ton/internal/build/JettonMinter.compiled.json +1 -1
  6. package/dist/artifacts/dev/ton/internal/build/JettonProxy.compiled.json +1 -1
  7. package/dist/artifacts/dev/ton/internal/build/JettonWallet.compiled.json +1 -1
  8. package/dist/artifacts/dev/ton/internal/build/NFTItem.compiled.json +1 -1
  9. package/dist/artifacts/dev/ton/internal/build/NFTProxy.compiled.json +1 -1
  10. package/dist/artifacts/dev/ton/internal/wrappers/CrossChainLayer.d.ts +13 -1
  11. package/dist/artifacts/dev/ton/internal/wrappers/CrossChainLayer.js +45 -7
  12. package/dist/artifacts/dev/ton/internal/wrappers/JettonMinter.d.ts +2 -2
  13. package/dist/artifacts/dev/ton/internal/wrappers/JettonMinter.js +2 -2
  14. package/dist/artifacts/testnet/ton/internal/build/CrossChainLayer.compiled.json +1 -1
  15. package/dist/artifacts/testnet/ton/internal/build/Executor.compiled.json +1 -1
  16. package/dist/artifacts/testnet/ton/internal/build/JettonMinter.compiled.json +1 -1
  17. package/dist/artifacts/testnet/ton/internal/build/JettonProxy.compiled.json +1 -1
  18. package/dist/artifacts/testnet/ton/internal/build/JettonWallet.compiled.json +1 -1
  19. package/dist/artifacts/testnet/ton/internal/build/NFTItem.compiled.json +1 -1
  20. package/dist/artifacts/testnet/ton/internal/build/NFTProxy.compiled.json +1 -1
  21. package/dist/artifacts/testnet/ton/internal/wrappers/CrossChainLayer.d.ts +13 -1
  22. package/dist/artifacts/testnet/ton/internal/wrappers/CrossChainLayer.js +45 -7
  23. package/dist/artifacts/testnet/ton/internal/wrappers/JettonMinter.d.ts +2 -2
  24. package/dist/artifacts/testnet/ton/internal/wrappers/JettonMinter.js +2 -2
  25. package/dist/src/adapters/contractOpener.d.ts +4 -0
  26. package/dist/src/adapters/contractOpener.js +165 -1
  27. package/dist/src/adapters/retryableContractOpener.d.ts +5 -1
  28. package/dist/src/adapters/retryableContractOpener.js +36 -7
  29. package/dist/src/assets/AssetFactory.js +8 -2
  30. package/dist/src/assets/FT.d.ts +1 -1
  31. package/dist/src/assets/FT.js +1 -1
  32. package/dist/src/assets/NFT.d.ts +1 -1
  33. package/dist/src/assets/NFT.js +1 -1
  34. package/dist/src/assets/TON.d.ts +3 -2
  35. package/dist/src/assets/TON.js +2 -1
  36. package/dist/src/errors/instances.d.ts +2 -0
  37. package/dist/src/errors/instances.js +3 -1
  38. package/dist/src/index.d.ts +1 -1
  39. package/dist/src/index.js +2 -4
  40. package/dist/src/interfaces/Asset.d.ts +4 -9
  41. package/dist/src/interfaces/ContractOpener.d.ts +5 -1
  42. package/dist/src/interfaces/ISimulator.d.ts +15 -1
  43. package/dist/src/interfaces/ITONTransactionManager.d.ts +20 -1
  44. package/dist/src/interfaces/ITacSDK.d.ts +10 -1
  45. package/dist/src/interfaces/ITxFinalizer.d.ts +5 -0
  46. package/dist/src/interfaces/ITxFinalizer.js +2 -0
  47. package/dist/src/interfaces/WalletInstanse.d.ts +4 -8
  48. package/dist/src/sdk/Consts.d.ts +50 -1
  49. package/dist/src/sdk/Consts.js +52 -2
  50. package/dist/src/sdk/Simulator.d.ts +11 -2
  51. package/dist/src/sdk/Simulator.js +190 -0
  52. package/dist/src/sdk/StartTracking.d.ts +5 -3
  53. package/dist/src/sdk/StartTracking.js +60 -40
  54. package/dist/src/sdk/TONTransactionManager.d.ts +8 -5
  55. package/dist/src/sdk/TONTransactionManager.js +50 -7
  56. package/dist/src/sdk/TacSdk.d.ts +2 -1
  57. package/dist/src/sdk/TacSdk.js +7 -1
  58. package/dist/src/sdk/TxFinalizer.d.ts +15 -4
  59. package/dist/src/sdk/TxFinalizer.js +102 -23
  60. package/dist/src/sdk/Utils.d.ts +10 -1
  61. package/dist/src/sdk/Utils.js +48 -0
  62. package/dist/src/sender/BatchSender.js +19 -0
  63. package/dist/src/sender/MockSender.d.ts +2 -0
  64. package/dist/src/sender/MockSender.js +13 -0
  65. package/dist/src/sender/RawSender.js +34 -1
  66. package/dist/src/sender/SenderFactory.js +1 -1
  67. package/dist/src/sender/TonConnectSender.js +2 -0
  68. package/dist/src/sender/index.d.ts +1 -0
  69. package/dist/src/sender/index.js +1 -0
  70. package/dist/src/structs/InternalStruct.d.ts +45 -1
  71. package/dist/src/structs/Struct.d.ts +29 -2
  72. package/dist/src/wrappers/HighloadWalletV3.d.ts +5 -3
  73. package/dist/src/wrappers/HighloadWalletV3.js +14 -3
  74. package/package.json +116 -118
@@ -1,19 +1,22 @@
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");
8
+ const sender_1 = require("../sender");
7
9
  const Consts_1 = require("./Consts");
8
10
  const Logger_1 = require("./Logger");
9
11
  const Utils_1 = require("./Utils");
10
12
  const Validator_1 = require("./Validator");
11
13
  class TONTransactionManager {
12
- constructor(config, simulator, operationTracker, logger = new Logger_1.NoopLogger()) {
14
+ constructor(config, simulator, operationTracker, logger = new Logger_1.NoopLogger(), txFinalizer) {
13
15
  this.config = config;
14
16
  this.simulator = simulator;
15
17
  this.operationTracker = operationTracker;
16
18
  this.logger = logger;
19
+ this.txFinalizer = txFinalizer;
17
20
  }
18
21
  async buildFeeParams(options, evmProxyMsg, sender, tx) {
19
22
  const { withoutSimulation, protocolFee, evmExecutorFee, tvmExecutorFee, isRoundTrip } = options;
@@ -46,6 +49,7 @@ class TONTransactionManager {
46
49
  : simulationResult.feeParams.tvmExecutorFee,
47
50
  gasLimit: evmProxyMsg.gasLimit ?? simulationResult.feeParams.gasLimit,
48
51
  isRoundTrip: isRoundTrip ?? simulationResult.feeParams.isRoundTrip,
52
+ evmEstimatedGas: simulationResult.simulation?.estimatedGas,
49
53
  };
50
54
  }
51
55
  async prepareCrossChainTransaction(evmProxyMsg, sender, assets, options, skipAssetsBalanceValidation = false) {
@@ -106,29 +110,45 @@ class TONTransactionManager {
106
110
  let feeTonAmount = feeParams.protocolFee + feeParams.evmExecutorFee + feeParams.tvmExecutorFee;
107
111
  this.logger.debug(`Crosschain ton amount: ${crossChainTonAmount}, Fee ton amount: ${feeTonAmount}`);
108
112
  if (!totalAssets.length) {
113
+ const tonNetworkFee = this.simulator.estimateTONFee(ton, {
114
+ excessReceiver: caller,
115
+ evmData,
116
+ feeParams,
117
+ });
109
118
  return [
110
119
  {
111
120
  address: this.config.TONParams.crossChainLayerAddress,
112
- value: crossChainTonAmount + feeTonAmount + Consts_1.TRANSACTION_TON_AMOUNT,
121
+ value: crossChainTonAmount + feeTonAmount + tonNetworkFee,
113
122
  payload: await ton.generatePayload({ excessReceiver: caller, evmData, feeParams }),
123
+ extra: {
124
+ tonNetworkFee,
125
+ tacEstimatedGas: feeParams.evmEstimatedGas,
126
+ },
114
127
  },
115
128
  ];
116
129
  }
117
130
  const messages = [];
118
131
  let currentFeeParams = feeParams;
119
132
  for (const asset of totalAssets) {
120
- const payload = await asset.generatePayload({
133
+ const params = {
121
134
  excessReceiver: caller,
122
135
  evmData,
123
136
  crossChainTonAmount,
124
137
  forwardFeeTonAmount: feeTonAmount,
125
138
  feeParams: currentFeeParams,
126
- });
139
+ };
140
+ const payload = await asset.generatePayload(params);
127
141
  const address = asset instanceof assets_1.FT ? await asset.getUserWalletAddress(caller) : asset.address;
142
+ const forwardAmount = asset instanceof assets_1.FT ? Consts_1.JETTON_TRANSFER_FORWARD_TON_AMOUNT : Consts_1.NFT_TRANSFER_FORWARD_TON_AMOUNT;
143
+ const tonNetworkFee = this.simulator.estimateTONFee(asset, params);
128
144
  messages.push({
129
145
  address,
130
- value: crossChainTonAmount + feeTonAmount + Consts_1.TRANSACTION_TON_AMOUNT,
146
+ value: crossChainTonAmount + feeTonAmount + tonNetworkFee + forwardAmount,
131
147
  payload,
148
+ extra: {
149
+ tonNetworkFee,
150
+ tacEstimatedGas: currentFeeParams?.evmEstimatedGas,
151
+ },
132
152
  });
133
153
  crossChainTonAmount = 0n;
134
154
  feeTonAmount = 0n;
@@ -149,7 +169,17 @@ class TONTransactionManager {
149
169
  if (!shouldWaitForOperationId) {
150
170
  return { sendTransactionResult, ...transactionLinker };
151
171
  }
152
- const waitOptions = tx.options?.waitOptions ?? {};
172
+ const waitOptions = tx.options?.waitOptions ?? {
173
+ ensureTxExecuted: true,
174
+ };
175
+ if (waitOptions.ensureTxExecuted && sendTransactionResult.boc) {
176
+ const hash = (0, Utils_1.getNormalizedExtMessageHash)((0, ton_1.loadMessage)(ton_1.Cell.fromBase64(sendTransactionResult.boc).beginParse()));
177
+ this.logger.info(`Tracking transaction tree for hash: ${hash}`);
178
+ await this.txFinalizer.trackTransactionTree(sender.getSenderAddress(), hash, {
179
+ maxDepth: 10,
180
+ });
181
+ this.logger.info(`Transaction tree successful`);
182
+ }
153
183
  waitOptions.successCheck = waitOptions.successCheck ?? ((id) => !!id);
154
184
  waitOptions.logger = waitOptions.logger ?? this.logger;
155
185
  const operationId = await this.operationTracker
@@ -208,7 +238,7 @@ class TONTransactionManager {
208
238
  this.logger.debug(`Operation IDs: ${(0, Utils_1.formatObjectForLogging)(operationIds)}`);
209
239
  return transactionLinkers.map((linker) => ({
210
240
  ...linker,
211
- operationId: operationIds[linker.shardsKey].operationIds.at(0),
241
+ operationId: operationIds[linker.shardsKey].operationIds[0],
212
242
  }));
213
243
  }
214
244
  catch (error) {
@@ -216,5 +246,18 @@ class TONTransactionManager {
216
246
  return transactionLinkers;
217
247
  }
218
248
  }
249
+ async prepareCrossChainTransactionPayload(evmProxyMsg, senderAddress, assets = [], options) {
250
+ this.logger.debug('Preparing cross-chain transaction payload');
251
+ const mockSender = (0, sender_1.getMockSender)(senderAddress);
252
+ const result = await this.prepareCrossChainTransaction(evmProxyMsg, mockSender, assets, options, true);
253
+ return result.transaction.messages.map((r) => ({
254
+ body: r.payload,
255
+ destinationAddress: r.address,
256
+ tonAmount: r.value,
257
+ tonNetworkFee: r.extra.tonNetworkFee,
258
+ tacEstimatedGas: r.extra.tacEstimatedGas,
259
+ transactionLinker: result.transactionLinker,
260
+ }));
261
+ }
219
262
  }
220
263
  exports.TONTransactionManager = TONTransactionManager;
@@ -3,7 +3,7 @@ import { JettonMinterData, NFTItemData } from '../../artifacts/tonTypes';
3
3
  import { FT, NFT } from '../assets';
4
4
  import { IConfiguration, ILogger, IOperationTracker, ITacSDK } from '../interfaces';
5
5
  import type { SenderAbstraction } from '../sender';
6
- import { AssetFromFTArg, AssetFromNFTCollectionArg, AssetFromNFTItemArg, AssetLike, BatchCrossChainTxWithAssetLike, CrossChainTransactionOptions, CrossChainTransactionsOptions, CrosschainTx, EVMAddress, EvmProxyMsg, ExecutionFeeEstimationResult, NFTAddressType, SDKParams, SuggestedTVMExecutorFee, TACSimulationParams, TACSimulationResult, TransactionLinkerWithOperationId, TVMAddress, UserWalletBalanceExtended } from '../structs/Struct';
6
+ import { AssetFromFTArg, AssetFromNFTCollectionArg, AssetFromNFTItemArg, AssetLike, BatchCrossChainTxWithAssetLike, CrossChainPayloadResult, CrossChainTransactionOptions, CrossChainTransactionsOptions, CrosschainTx, EVMAddress, EvmProxyMsg, ExecutionFeeEstimationResult, NFTAddressType, SDKParams, SuggestedTVMExecutorFee, TACSimulationParams, TACSimulationResult, TransactionLinkerWithOperationId, TVMAddress, UserWalletBalanceExtended } from '../structs/Struct';
7
7
  export declare class TacSdk implements ITacSDK {
8
8
  readonly config: IConfiguration;
9
9
  readonly operationTracker: IOperationTracker;
@@ -41,4 +41,5 @@ export declare class TacSdk implements ITacSDK {
41
41
  getTVMNFTAddress(evmNFTAddress: string, tokenId?: number | bigint): Promise<string>;
42
42
  getEVMNFTAddress(tvmNFTAddress: string, addressType: NFTAddressType): Promise<string>;
43
43
  getOperationTracker(): IOperationTracker;
44
+ prepareCrossChainTransactionPayload(evmProxyMsg: EvmProxyMsg, senderAddress: string, assets?: AssetLike[], options?: CrossChainTransactionOptions): Promise<CrossChainPayloadResult[]>;
44
45
  }
@@ -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
  }
@@ -177,5 +179,9 @@ class TacSdk {
177
179
  getOperationTracker() {
178
180
  return this.operationTracker;
179
181
  }
182
+ async prepareCrossChainTransactionPayload(evmProxyMsg, senderAddress, assets = [], options) {
183
+ const normalizedAssets = await (0, Utils_1.normalizeAssets)(this.config, assets);
184
+ return this.tonTransactionManager.prepareCrossChainTransactionPayload(evmProxyMsg, senderAddress, normalizedAssets, options);
185
+ }
180
186
  }
181
187
  exports.TacSdk = TacSdk;
@@ -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 TonIndexerTxFinalizer 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.TonIndexerTxFinalizer = 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 TonIndexerTxFinalizer {
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.TonIndexerTxFinalizer = TonIndexerTxFinalizer;
@@ -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,12 @@ 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>;
40
+ export declare function recurisivelyCollectCellStats(cell: Cell): {
41
+ bits: number;
42
+ cells: number;
43
+ };
@@ -19,6 +19,9 @@ 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;
24
+ exports.recurisivelyCollectCellStats = recurisivelyCollectCellStats;
22
25
  const ton_1 = require("@ton/ton");
23
26
  const ethers_1 = require("ethers");
24
27
  const ton_crypto_1 = require("ton-crypto");
@@ -299,3 +302,48 @@ function getNumber(len, cell) {
299
302
  function getString(cell) {
300
303
  return cell?.beginParse().loadStringTail() ?? '';
301
304
  }
305
+ function getNormalizedExtMessageHash(message) {
306
+ if (message.info.type !== 'external-in') {
307
+ throw new Error(`Message must be "external-in", got ${message.info.type}`);
308
+ }
309
+ const info = {
310
+ ...message.info,
311
+ src: undefined,
312
+ importFee: 0n,
313
+ };
314
+ const normalizedMessage = {
315
+ ...message,
316
+ init: null,
317
+ info: info,
318
+ };
319
+ return (0, ton_1.beginCell)()
320
+ .store((0, ton_1.storeMessage)(normalizedMessage, { forceRef: true }))
321
+ .endCell()
322
+ .hash()
323
+ .toString('base64');
324
+ }
325
+ async function retry(fn, options) {
326
+ let lastError;
327
+ for (let i = 0; i < options.retries; i++) {
328
+ try {
329
+ return await fn();
330
+ }
331
+ catch (e) {
332
+ if (e instanceof Error) {
333
+ lastError = e;
334
+ }
335
+ await new Promise((resolve) => setTimeout(resolve, options.delay));
336
+ }
337
+ }
338
+ throw lastError;
339
+ }
340
+ function recurisivelyCollectCellStats(cell) {
341
+ let bits = 0;
342
+ let cells = 0;
343
+ for (const ref of cell.refs) {
344
+ const stats = recurisivelyCollectCellStats(ref);
345
+ bits += stats.bits;
346
+ cells += stats.cells;
347
+ }
348
+ return { bits: cell.bits.length + bits, cells: 1 + cells };
349
+ }
@@ -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,
@@ -0,0 +1,2 @@
1
+ import { SenderAbstraction } from '../interfaces/SenderAbstraction';
2
+ export declare const getMockSender: (senderAddress: string) => SenderAbstraction;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getMockSender = void 0;
4
+ const getMockSender = (senderAddress) => {
5
+ return {
6
+ getSenderAddress: () => senderAddress,
7
+ sendShardTransaction: async () => ({ success: true, boc: '' }),
8
+ sendShardTransactions: async () => [],
9
+ getBalance: async () => 0n,
10
+ getBalanceOf: async () => 0n,
11
+ };
12
+ };
13
+ exports.getMockSender = getMockSender;
@@ -34,7 +34,16 @@ class RawSender {
34
34
  for (const batch of batches) {
35
35
  try {
36
36
  const result = await this.sendBatch(batch, contractOpener);
37
+ // Extract BoC if it's a string, or from sandbox result
38
+ let externalMsgBoc = '';
39
+ if (typeof result === 'string') {
40
+ externalMsgBoc = result;
41
+ }
42
+ else if (result?.result) {
43
+ externalMsgBoc = result.result;
44
+ }
37
45
  results.push({
46
+ boc: externalMsgBoc,
38
47
  success: true,
39
48
  result,
40
49
  lastMessageIndex: currentMessageIndex + batch.length - 1,
@@ -42,6 +51,7 @@ class RawSender {
42
51
  }
43
52
  catch (error) {
44
53
  results.push({
54
+ boc: '',
45
55
  success: false,
46
56
  error: error,
47
57
  lastMessageIndex: currentMessageIndex - 1,
@@ -63,12 +73,26 @@ class RawSender {
63
73
  async sendBatch(messages, contractOpener) {
64
74
  const walletContract = contractOpener.open(this.wallet);
65
75
  const seqno = await walletContract.getSeqno();
66
- return walletContract.sendTransfer({
76
+ // Try to create BoC locally for standard wallets
77
+ const msg = this.wallet.createTransfer({
67
78
  seqno,
68
79
  secretKey: this.secretKey,
69
80
  messages,
70
81
  sendMode: ton_2.SendMode.PAY_GAS_SEPARATELY,
71
82
  });
83
+ let neededInit = null;
84
+ if (this.wallet.init && (await contractOpener.getContractState(this.wallet.address)).state !== 'active') {
85
+ neededInit = this.wallet.init;
86
+ }
87
+ const ext = (0, ton_1.external)({
88
+ to: this.wallet.address,
89
+ init: neededInit,
90
+ body: msg,
91
+ });
92
+ const boc = (0, ton_1.beginCell)().store((0, ton_1.storeMessage)(ext)).endCell().toBoc().toString('base64');
93
+ // Send the transaction
94
+ const result = await walletContract.send(msg);
95
+ return result || boc;
72
96
  }
73
97
  getSenderAddress() {
74
98
  return this.wallet.address.toString();
@@ -84,7 +108,16 @@ class RawSender {
84
108
  }));
85
109
  }
86
110
  const result = await this.sendBatch(messages, contractOpener);
111
+ // Extract BoC if it's a string, or from sandbox result
112
+ let externalMsgBoc = '';
113
+ if (typeof result === 'string') {
114
+ externalMsgBoc = result;
115
+ }
116
+ else if (result?.result) {
117
+ externalMsgBoc = result.result;
118
+ }
87
119
  return {
120
+ boc: externalMsgBoc,
88
121
  success: true,
89
122
  result,
90
123
  lastMessageIndex: shardTransaction.messages.length - 1,
@@ -51,7 +51,7 @@ class SenderFactory {
51
51
  config.timeout = params.options?.highloadV3?.timeout ?? HighloadWalletV3_1.DEFAULT_TIMEOUT;
52
52
  }
53
53
  const wallet = exports.wallets[params.version].create(config);
54
- if (params.version === 'HIGHLOAD_V3') {
54
+ if (wallet instanceof HighloadWalletV3_1.HighloadWalletV3) {
55
55
  return new BatchSender_1.BatchSender(wallet, keypair.secretKey);
56
56
  }
57
57
  return new RawSender_1.RawSender(wallet, keypair.secretKey, params.version === 'V5R1' ? 254 : 4);
@@ -35,6 +35,7 @@ class TonConnectSender {
35
35
  responses.push({
36
36
  success: true,
37
37
  result: response,
38
+ boc: response.boc,
38
39
  lastMessageIndex: currentMessageIndex + chunk.length - 1,
39
40
  });
40
41
  currentMessageIndex += chunk.length;
@@ -42,6 +43,7 @@ class TonConnectSender {
42
43
  catch (error) {
43
44
  responses.push({
44
45
  success: false,
46
+ boc: '',
45
47
  error: error,
46
48
  lastMessageIndex: currentMessageIndex - 1,
47
49
  });
@@ -1,3 +1,4 @@
1
1
  export * from '../interfaces/SenderAbstraction';
2
2
  export * from './BatchSender';
3
+ export * from './MockSender';
3
4
  export * from './SenderFactory';
@@ -16,4 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("../interfaces/SenderAbstraction"), exports);
18
18
  __exportStar(require("./BatchSender"), exports);
19
+ __exportStar(require("./MockSender"), exports);
19
20
  __exportStar(require("./SenderFactory"), exports);