@tonappchain/sdk 0.6.5-mainnet-alpha → 0.6.5-smart-accounts-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.
@@ -4,32 +4,36 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.TacSdk = void 0;
7
- const axios_1 = __importDefault(require("axios"));
8
7
  const ton_1 = require("@ton/ton");
8
+ const artifacts_1 = require("@tonappchain/artifacts");
9
+ const wrappers_1 = require("@tonappchain/artifacts/dist/src/ton/wrappers");
10
+ const axios_1 = __importDefault(require("axios"));
9
11
  const ethers_1 = require("ethers");
10
- // import structs
11
- const Struct_1 = require("../structs/Struct");
12
+ const errors_1 = require("../errors");
13
+ const instances_1 = require("../errors/instances");
14
+ const retryableContractOpener_1 = require("../adapters/retryableContractOpener");
12
15
  // import internal structs
13
16
  const InternalStruct_1 = require("../structs/InternalStruct");
17
+ // import structs
18
+ const Struct_1 = require("../structs/Struct");
14
19
  // jetton imports
15
20
  const JettonMaster_1 = require("../wrappers/JettonMaster");
16
21
  const JettonWallet_1 = require("../wrappers/JettonWallet");
17
22
  // ton settings
18
23
  const Settings_1 = require("../wrappers/Settings");
19
24
  const Consts_1 = require("./Consts");
25
+ const OperationTracker_1 = require("./OperationTracker");
20
26
  const Utils_1 = require("./Utils");
21
- const artifacts_1 = require("@tonappchain/artifacts");
22
- const errors_1 = require("../errors");
23
- const wrappers_1 = require("@tonappchain/artifacts/dist/src/ton/wrappers");
24
- const instances_1 = require("../errors/instances");
25
27
  class TacSdk {
26
- constructor(network, delay, artifacts, TONParams, TACParams, liteSequencerEndpoints) {
28
+ constructor(network, delay, artifacts, TONParams, TACParams, liteSequencerEndpoints, debug) {
27
29
  this.network = network;
28
30
  this.delay = delay;
29
31
  this.artifacts = artifacts;
30
32
  this.TONParams = TONParams;
31
33
  this.TACParams = TACParams;
32
34
  this.liteSequencerEndpoints = liteSequencerEndpoints;
35
+ this.debug = debug;
36
+ this.operationTracker = new OperationTracker_1.OperationTracker(network, liteSequencerEndpoints, debug);
33
37
  }
34
38
  static async create(sdkParams) {
35
39
  const network = sdkParams.network;
@@ -37,19 +41,16 @@ class TacSdk {
37
41
  const artifacts = network === Struct_1.Network.TESTNET ? artifacts_1.testnet : artifacts_1.mainnet;
38
42
  const TONParams = await this.prepareTONParams(delay, artifacts, sdkParams.TONParams);
39
43
  const TACParams = await this.prepareTACParams(artifacts, delay, sdkParams.TACParams);
44
+ const debug = sdkParams.debug ?? false;
40
45
  const liteSequencerEndpoints = sdkParams.customLiteSequencerEndpoints ??
41
46
  (network === Struct_1.Network.TESTNET
42
47
  ? artifacts_1.testnet.PUBLIC_LITE_SEQUENCER_ENDPOINTS
43
48
  : artifacts_1.mainnet.PUBLIC_LITE_SEQUENCER_ENDPOINTS);
44
- return new TacSdk(network, delay, artifacts, TONParams, TACParams, liteSequencerEndpoints);
49
+ return new TacSdk(network, delay, artifacts, TONParams, TACParams, liteSequencerEndpoints, debug);
45
50
  }
46
51
  static async prepareTONParams(delay, artifacts, TONParams) {
47
- const contractOpener = TONParams?.contractOpener ??
48
- new ton_1.TonClient({
49
- endpoint: new URL('api/v2/jsonRPC', artifacts.TON_RPC_ENDPOINT_BY_TAC).toString()
50
- });
51
- const settingsAddress = TONParams?.settingsAddress
52
- ?? artifacts.TON_SETTINGS_ADDRESS;
52
+ const contractOpener = TONParams?.contractOpener ?? (await (0, retryableContractOpener_1.createDefaultRetryableOpener)(artifacts));
53
+ const settingsAddress = TONParams?.settingsAddress ?? artifacts.TON_SETTINGS_ADDRESS;
53
54
  const settings = contractOpener.open(new Settings_1.Settings(ton_1.Address.parse(settingsAddress)));
54
55
  const jettonProxyAddress = await settings.getAddressSetting('JettonProxyAddress');
55
56
  await (0, Utils_1.sleep)(delay * 1000);
@@ -78,8 +79,7 @@ class TacSdk {
78
79
  }
79
80
  static async prepareTACParams(artifacts, delay, TACParams) {
80
81
  const provider = TACParams?.provider ?? ethers_1.ethers.getDefaultProvider(artifacts.TAC_RPC_ENDPOINT);
81
- const settingsAddress = TACParams?.settingsAddress?.toString()
82
- ?? artifacts.TAC_SETTINGS_ADDRESS;
82
+ const settingsAddress = TACParams?.settingsAddress?.toString() ?? artifacts.TAC_SETTINGS_ADDRESS;
83
83
  const settings = artifacts.tac.wrappers.SettingsFactoryTAC.connect(settingsAddress, provider);
84
84
  const crossChainLayerABI = TACParams?.crossChainLayerABI ?? artifacts.tac.compilationArtifacts.CrossChainLayer.abi;
85
85
  const crossChainLayerAddress = await settings.getAddressSetting((0, ethers_1.keccak256)((0, ethers_1.toUtf8Bytes)('CrossChainLayerAddress')));
@@ -95,6 +95,7 @@ class TacSdk {
95
95
  const crossChainLayerTokenBytecode = TACParams?.crossChainLayerTokenBytecode ?? artifacts.tac.compilationArtifacts.CrossChainLayerToken.bytecode;
96
96
  const crossChainLayerNFTABI = TACParams?.crossChainLayerNFTABI ?? artifacts.tac.compilationArtifacts.CrossChainLayerNFT.abi;
97
97
  const crossChainLayerNFTBytecode = TACParams?.crossChainLayerNFTBytecode ?? artifacts.tac.compilationArtifacts.CrossChainLayerNFT.bytecode;
98
+ const smartAccountFactory = artifacts.tac.wrappers.TacSAFactory_factoryTAC.connect(artifacts.TAC_SMART_ACCOUNT_FACTORY_ADDRESS, provider);
98
99
  return {
99
100
  provider,
100
101
  settings,
@@ -108,6 +109,7 @@ class TacSdk {
108
109
  crossChainLayerTokenBytecode,
109
110
  crossChainLayerNFTABI,
110
111
  crossChainLayerNFTBytecode,
112
+ smartAccountFactory,
111
113
  };
112
114
  }
113
115
  closeConnections() {
@@ -130,6 +132,9 @@ class TacSdk {
130
132
  const userJettonWallet = this.TONParams.contractOpener.open(new JettonWallet_1.JettonWallet(ton_1.Address.parse(userJettonWalletAddress)));
131
133
  return userJettonWallet.getJettonBalance();
132
134
  }
135
+ async getTacSmartAccountAddress(tvmUserAddress, evmApplicationAddress) {
136
+ return await this.TACParams.smartAccountFactory.getSmartAccountForApplication(tvmUserAddress, evmApplicationAddress);
137
+ }
133
138
  async getUserJettonBalanceExtended(userAddress, tokenAddress) {
134
139
  const masterAddress = ton_1.Address.parse(tokenAddress);
135
140
  const masterState = await this.TONParams.contractOpener.getContractState(masterAddress);
@@ -186,7 +191,13 @@ class TacSdk {
186
191
  .storeMaybeRef(evmData)
187
192
  .endCell();
188
193
  }
194
+ debugLog(message) {
195
+ if (this.debug) {
196
+ console.log(`[TacSdk Debug] ${message}`);
197
+ }
198
+ }
189
199
  async getJettonOpType(asset) {
200
+ this.debugLog(`Getting jetton op type for ${(0, Utils_1.formatObjectForLogging)(asset)}`);
190
201
  const { code: givenMinterCodeBOC } = await this.TONParams.contractOpener.getContractState((0, ton_1.address)(asset.address));
191
202
  if (!givenMinterCodeBOC) {
192
203
  throw errors_1.emptyContractError;
@@ -194,11 +205,13 @@ class TacSdk {
194
205
  const givenMinterCode = ton_1.Cell.fromBoc(givenMinterCodeBOC)[0];
195
206
  await (0, Utils_1.sleep)(this.delay * 1000);
196
207
  if (!this.TONParams.jettonMinterCode.equals(givenMinterCode)) {
208
+ this.debugLog(`Jetton ${(0, Utils_1.formatObjectForLogging)(asset)} requires JETTON_TRANSFER operation`);
197
209
  return InternalStruct_1.AssetOpType.JETTON_TRANSFER;
198
210
  }
199
211
  const givenMinter = this.TONParams.contractOpener.open(new JettonMaster_1.JettonMaster((0, ton_1.address)(asset.address)));
200
212
  const evmAddress = await givenMinter.getEVMAddress();
201
213
  await (0, Utils_1.sleep)(this.delay * 1000);
214
+ this.debugLog(`Jetton ${(0, Utils_1.formatObjectForLogging)(asset)} has evm address ${evmAddress}`);
202
215
  const expectedMinterAddress = await (0, Utils_1.calculateContractAddress)(this.TONParams.jettonMinterCode, (0, ton_1.beginCell)()
203
216
  .storeCoins(0)
204
217
  .storeAddress((0, ton_1.address)(this.TONParams.crossChainLayerAddress))
@@ -208,11 +221,14 @@ class TacSdk {
208
221
  .storeStringTail(evmAddress)
209
222
  .endCell());
210
223
  if (!expectedMinterAddress.equals(givenMinter.address)) {
224
+ this.debugLog(`Jetton ${(0, Utils_1.formatObjectForLogging)(asset)} requires JETTON_TRANSFER operation`);
211
225
  return InternalStruct_1.AssetOpType.JETTON_TRANSFER;
212
226
  }
227
+ this.debugLog(`Jetton ${(0, Utils_1.formatObjectForLogging)(asset)} requires JETTON_BURN operation`);
213
228
  return InternalStruct_1.AssetOpType.JETTON_BURN;
214
229
  }
215
230
  async getNFTOpType(asset) {
231
+ this.debugLog(`Getting NFT op type for ${(0, Utils_1.formatObjectForLogging)(asset)}`);
216
232
  const { code: itemCodeBOC } = await this.TONParams.contractOpener.getContractState((0, ton_1.address)(asset.address));
217
233
  if (!itemCodeBOC) {
218
234
  throw errors_1.emptyContractError;
@@ -220,8 +236,10 @@ class TacSdk {
220
236
  const givenNFTItemCode = ton_1.Cell.fromBoc(itemCodeBOC)[0];
221
237
  await (0, Utils_1.sleep)(this.delay * 1000);
222
238
  if (!this.TONParams.nftItemCode.equals(givenNFTItemCode)) {
239
+ this.debugLog(`NFT ${(0, Utils_1.formatObjectForLogging)(asset)} requires NFT_TRANSFER operation`);
223
240
  return InternalStruct_1.AssetOpType.NFT_TRANSFER;
224
241
  }
242
+ this.debugLog(`NFT ${(0, Utils_1.formatObjectForLogging)(asset)} requires NFT_BURN operation`);
225
243
  return InternalStruct_1.AssetOpType.NFT_BURN;
226
244
  }
227
245
  async getNFTItemAddressTON(collectionAddress, itemIndex) {
@@ -235,6 +253,7 @@ class TacSdk {
235
253
  return await nftItem.getNFTData();
236
254
  }
237
255
  async aggregateTokens(assets) {
256
+ this.debugLog(`Aggregating tokens`);
238
257
  const uniqueAssetsMap = new Map();
239
258
  let crossChainTonAmount = 0n;
240
259
  for await (const asset of assets ?? []) {
@@ -255,6 +274,8 @@ class TacSdk {
255
274
  rawAmount,
256
275
  type: Struct_1.AssetType.FT,
257
276
  }));
277
+ this.debugLog(`Aggregated ${jettons.length} jettons`);
278
+ this.debugLog(`Crosschain ton amount: ${crossChainTonAmount}`);
258
279
  uniqueAssetsMap.clear();
259
280
  for await (const asset of assets ?? []) {
260
281
  if (asset.type !== Struct_1.AssetType.NFT)
@@ -267,6 +288,7 @@ class TacSdk {
267
288
  rawAmount,
268
289
  type: Struct_1.AssetType.NFT,
269
290
  }));
291
+ this.debugLog(`Aggregated ${nfts.length} nfts`);
270
292
  return {
271
293
  jettons,
272
294
  nfts,
@@ -274,9 +296,10 @@ class TacSdk {
274
296
  };
275
297
  }
276
298
  async generateJettonPayload(jetton, caller, evmData, crossChainTonAmount, forwardFeeTonAmount, feeParams) {
299
+ this.debugLog(`Generating jetton payload for ${(0, Utils_1.formatObjectForLogging)(jetton)}`);
277
300
  const opType = await this.getJettonOpType(jetton);
278
301
  await (0, Utils_1.sleep)(this.delay * 1000);
279
- console.log(`***** Jetton ${jetton.address} requires ${opType} operation`);
302
+ this.debugLog(`Generation fee data with params: ${(0, Utils_1.formatObjectForLogging)(feeParams)}`);
280
303
  const feeData = (0, Utils_1.generateFeeData)(feeParams);
281
304
  let payload;
282
305
  switch (opType) {
@@ -290,12 +313,14 @@ class TacSdk {
290
313
  payload = this.getJettonTransferPayload(jetton, caller, evmData, crossChainTonAmount, forwardFeeTonAmount, feeData);
291
314
  break;
292
315
  }
316
+ this.debugLog('Generating jetton payload success');
293
317
  return payload;
294
318
  }
295
319
  async generateNFTPayload(nft, caller, evmData, crossChainTonAmount, forwardFeeTonAmount, feeParams) {
320
+ this.debugLog(`Generating NFT payload for ${(0, Utils_1.formatObjectForLogging)(nft)}`);
296
321
  const opType = await this.getNFTOpType(nft);
297
322
  await (0, Utils_1.sleep)(this.delay * 1000);
298
- console.log(`***** NFT ${nft.address} requires ${opType} operation`);
323
+ this.debugLog(`Generation fee data with params: ${(0, Utils_1.formatObjectForLogging)(feeParams)}`);
299
324
  const feeData = (0, Utils_1.generateFeeData)(feeParams);
300
325
  let payload;
301
326
  switch (opType) {
@@ -319,11 +344,15 @@ class TacSdk {
319
344
  }, forwardFeeTonAmount);
320
345
  break;
321
346
  }
347
+ this.debugLog('Generating NFT payload success');
322
348
  return payload;
323
349
  }
324
350
  async generateCrossChainMessages(caller, evmData, aggregatedData, feeParams) {
351
+ this.debugLog(`Generating cross-chain messages`);
325
352
  let crossChainTonAmount = aggregatedData.crossChainTonAmount;
326
353
  let feeTonAmount = feeParams.protocolFee + feeParams.evmExecutorFee + feeParams.tvmExecutorFee;
354
+ this.debugLog(`Crosschain ton amount: ${crossChainTonAmount}`);
355
+ this.debugLog(`Fee ton amount: ${feeTonAmount}`);
327
356
  if (aggregatedData.jettons.length == 0 && aggregatedData.nfts.length == 0) {
328
357
  return [
329
358
  {
@@ -361,38 +390,51 @@ class TacSdk {
361
390
  feeTonAmount = 0n;
362
391
  currentFeeParams = undefined;
363
392
  }
393
+ this.debugLog('Generating cross-chain messages success');
364
394
  return messages;
365
395
  }
366
396
  async getRawAmount(asset, precalculatedAddress) {
397
+ this.debugLog(`Getting raw amount for ${(0, Utils_1.formatObjectForLogging)(precalculatedAddress ?? 'TON')}`);
367
398
  if ('rawAmount' in asset) {
368
- // User specified raw format amount
399
+ this.debugLog(`Provided raw amount: ${asset.rawAmount}`);
369
400
  return asset.rawAmount;
370
401
  }
371
402
  if (!precalculatedAddress) {
372
403
  // User specified TON Coin
373
- return (0, ton_1.toNano)(asset.amount);
404
+ const rawAmount = (0, ton_1.toNano)(asset.amount);
405
+ this.debugLog(`TON raw amount: ${rawAmount}`);
406
+ return rawAmount;
374
407
  }
375
408
  if (typeof asset.decimals === 'number') {
376
409
  // User manually set decimals
377
- return (0, Utils_1.calculateRawAmount)(asset.amount, asset.decimals);
410
+ const rawAmount = (0, Utils_1.calculateRawAmount)(asset.amount, asset.decimals);
411
+ this.debugLog(`Raw amount calculated from decimals: ${rawAmount}`);
412
+ return rawAmount;
378
413
  }
379
414
  // Get decimals from chain
380
415
  (0, Utils_1.validateTVMAddress)(precalculatedAddress);
416
+ this.debugLog('Getting decimals from chain');
381
417
  const contract = this.TONParams.contractOpener.open(new JettonMaster_1.JettonMaster((0, ton_1.address)(precalculatedAddress)));
382
418
  const { content } = await contract.getJettonData();
383
419
  await (0, Utils_1.sleep)(this.delay * 1000);
384
420
  if (!content.metadata.decimals) {
385
421
  // if decimals not specified use default value 9
422
+ this.debugLog('Decimals not specified, using default value 9');
386
423
  return (0, ton_1.toNano)(asset.amount);
387
424
  }
388
- return (0, Utils_1.calculateRawAmount)(asset.amount, Number(content.metadata.decimals));
425
+ const rawAmount = (0, Utils_1.calculateRawAmount)(asset.amount, Number(content.metadata.decimals));
426
+ this.debugLog(`Raw amount calculated from decimals(${content.metadata.decimals}): ${rawAmount}`);
427
+ return rawAmount;
389
428
  }
390
429
  async convertAssetsToRawFormat(assets) {
430
+ this.debugLog(`Converting assets to raw format`);
391
431
  return await Promise.all((assets ?? []).map(async (asset) => {
432
+ this.debugLog(`Converting asset to raw format: ${(0, Utils_1.formatObjectForLogging)(asset)}`);
392
433
  if (asset.type === Struct_1.AssetType.FT) {
393
434
  const address = (0, ethers_1.isAddress)(asset.address)
394
435
  ? await this.getTVMTokenAddress(asset.address)
395
436
  : asset.address;
437
+ this.debugLog(`Token address on TON: ${address}`);
396
438
  return {
397
439
  address,
398
440
  rawAmount: await this.getRawAmount(asset, address),
@@ -404,6 +446,7 @@ class TacSdk {
404
446
  const address = (0, ethers_1.isAddress)(asset.collectionAddress)
405
447
  ? await this.getTVMNFTAddress(asset.collectionAddress, asset.itemIndex)
406
448
  : await this.getNFTItemAddressTON(asset.collectionAddress, asset.itemIndex);
449
+ this.debugLog(`NFT address on TON: ${address}`);
407
450
  await (0, Utils_1.sleep)(this.delay * 1000);
408
451
  return {
409
452
  address,
@@ -421,9 +464,12 @@ class TacSdk {
421
464
  throw instances_1.invalidAssetType;
422
465
  }));
423
466
  }
424
- async getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, forceSend = false, isRoundTrip = true, evmValidExecutors = this.TACParams.trustedTACExecutors) {
467
+ async getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, forceSend = false, isRoundTrip = true, evmValidExecutors = this.TACParams.trustedTACExecutors, tvmValidExecutors = this.TACParams.trustedTONExecutors) {
468
+ this.debugLog('Getting fee info');
425
469
  const crossChainLayer = this.TONParams.contractOpener.open(this.artifacts.ton.wrappers.CrossChainLayer.createFromAddress(ton_1.Address.parse(this.TONParams.crossChainLayerAddress)));
426
470
  const fullStateCCL = await crossChainLayer.getFullData();
471
+ await (0, Utils_1.sleep)(this.delay * 1000);
472
+ this.debugLog(`Full state CCL: ${(0, Utils_1.formatObjectForLogging)(fullStateCCL)}`);
427
473
  const tacSimulationBody = {
428
474
  tacCallParams: {
429
475
  arguments: evmProxyMsg.encodedParameters ?? '0x',
@@ -431,6 +477,7 @@ class TacSdk {
431
477
  target: evmProxyMsg.evmTargetAddress,
432
478
  },
433
479
  evmValidExecutors: evmValidExecutors,
480
+ tvmValidExecutors: tvmValidExecutors,
434
481
  extraData: '0x',
435
482
  shardsKey: transactionLinker.shardsKey,
436
483
  tonAssets: rawAssets.map((asset) => ({
@@ -440,10 +487,13 @@ class TacSdk {
440
487
  })),
441
488
  tonCaller: transactionLinker.caller,
442
489
  };
443
- isRoundTrip = isRoundTrip ?? (rawAssets.length != 0);
490
+ isRoundTrip = isRoundTrip ?? rawAssets.length != 0;
491
+ this.debugLog(`Is round trip: ${isRoundTrip}`);
444
492
  const tacSimulationResult = await this.simulateTACMessage(tacSimulationBody);
493
+ this.debugLog(`TAC simulation ${tacSimulationResult.simulationStatus ? 'success' : 'failed'}`);
445
494
  if (!tacSimulationResult.simulationStatus) {
446
495
  if (forceSend) {
496
+ this.debugLog('Force send is true, returning fee params');
447
497
  return {
448
498
  feeParams: {
449
499
  isRoundTrip,
@@ -467,16 +517,21 @@ class TacSdk {
467
517
  evmExecutorFee: BigInt(tacSimulationResult.suggestedTacExecutionFee),
468
518
  tvmExecutorFee: BigInt(tacSimulationResult.suggestedTonExecutionFee) * BigInt(isRoundTrip),
469
519
  };
520
+ this.debugLog(`Collected fee params: ${(0, Utils_1.formatObjectForLogging)(feeParams)}`);
470
521
  return { feeParams: feeParams, simulation: tacSimulationResult };
471
522
  }
472
523
  async getTransactionSimulationInfo(evmProxyMsg, sender, assets) {
524
+ this.debugLog('Getting transaction simulation info');
473
525
  const rawAssets = await this.convertAssetsToRawFormat(assets);
474
526
  const aggregatedData = await this.aggregateTokens(rawAssets);
475
527
  const transactionLinkerShardCount = aggregatedData.jettons.length == 0 ? 1 : aggregatedData.jettons.length;
528
+ this.debugLog(`Transaction linker shard count: ${transactionLinkerShardCount}`);
476
529
  const transactionLinker = (0, Utils_1.generateTransactionLinker)(sender.getSenderAddress(), transactionLinkerShardCount);
530
+ this.debugLog(`Transaction linker: ${(0, Utils_1.formatObjectForLogging)(transactionLinker)}`);
477
531
  return await this.getFeeInfo(evmProxyMsg, transactionLinker, rawAssets);
478
532
  }
479
533
  async getTVMExecutorFeeInfo(assets, feeSymbol) {
534
+ this.debugLog('Getting TVM executor fee info');
480
535
  const rawAssets = await this.convertAssetsToRawFormat(assets);
481
536
  const requestBody = {
482
537
  tonAssets: rawAssets.map((asset) => ({
@@ -493,26 +548,32 @@ class TacSdk {
493
548
  return response.data.response;
494
549
  }
495
550
  catch (error) {
496
- console.error(`Error while calculating tvm executor fee ${endpoint}:`, error);
551
+ this.debugLog(`Error while calculating tvm executor fee ${endpoint}: ${error}`);
497
552
  lastError = error;
498
553
  }
499
554
  }
555
+ this.debugLog('Error while calculating tvm executor fee on all endpoints');
500
556
  throw (0, errors_1.simulationError)(lastError);
501
557
  }
502
558
  async prepareCrossChainTransaction(evmProxyMsg, caller, assets, options) {
503
- let { forceSend = false, isRoundTrip = undefined, protocolFee = undefined, evmValidExecutors = [], evmExecutorFee = undefined, tvmValidExecutors = [], tvmExecutorFee = undefined, } = options || {};
559
+ this.debugLog('Preparing cross-chain transaction');
560
+ const { forceSend = false, isRoundTrip = undefined, protocolFee = undefined, evmExecutorFee = undefined, tvmExecutorFee = undefined, } = options || {};
561
+ let { evmValidExecutors = [], tvmValidExecutors = [] } = options || {};
504
562
  const rawAssets = await this.convertAssetsToRawFormat(assets);
505
563
  const aggregatedData = await this.aggregateTokens(rawAssets);
506
564
  const tokensLength = aggregatedData.jettons.length + aggregatedData.nfts.length;
507
- let transactionLinkerShardCount = tokensLength == 0 ? 1 : tokensLength;
565
+ this.debugLog(`Tokens length: ${tokensLength}`);
566
+ const transactionLinkerShardCount = tokensLength == 0 ? 1 : tokensLength;
567
+ this.debugLog(`Transaction linker shard count: ${transactionLinkerShardCount}`);
508
568
  const transactionLinker = (0, Utils_1.generateTransactionLinker)(caller, transactionLinkerShardCount);
569
+ this.debugLog(`Generated transaction linker: ${(0, Utils_1.formatObjectForLogging)(transactionLinker)}`);
509
570
  if (evmValidExecutors.length == 0) {
510
571
  evmValidExecutors = this.TACParams.trustedTACExecutors;
511
572
  }
512
573
  if (tvmValidExecutors.length == 0) {
513
574
  tvmValidExecutors = this.TACParams.trustedTONExecutors;
514
575
  }
515
- const { feeParams } = await this.getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, forceSend, isRoundTrip, evmValidExecutors);
576
+ const { feeParams } = await this.getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, forceSend, isRoundTrip, evmValidExecutors, tvmValidExecutors);
516
577
  if (evmProxyMsg.gasLimit == undefined) {
517
578
  evmProxyMsg.gasLimit = feeParams.gasLimit;
518
579
  }
@@ -525,10 +586,12 @@ class TacSdk {
525
586
  if (protocolFee != undefined) {
526
587
  feeParams.protocolFee = protocolFee;
527
588
  }
589
+ this.debugLog(`Resulting fee params: ${(0, Utils_1.formatObjectForLogging)(feeParams)}`);
528
590
  const validExecutors = {
529
591
  tac: evmValidExecutors,
530
592
  ton: tvmValidExecutors,
531
593
  };
594
+ this.debugLog(`Valid executors: ${(0, Utils_1.formatObjectForLogging)(validExecutors)}`);
532
595
  const evmData = (0, Utils_1.buildEvmDataCell)(transactionLinker, evmProxyMsg, validExecutors);
533
596
  const messages = await this.generateCrossChainMessages(caller, evmData, aggregatedData, feeParams);
534
597
  await (0, Utils_1.sleep)(this.delay * 1000);
@@ -537,34 +600,70 @@ class TacSdk {
537
600
  messages,
538
601
  network: this.network,
539
602
  };
603
+ this.debugLog('Transaction prepared');
540
604
  return { transaction, transactionLinker };
541
605
  }
542
- async sendCrossChainTransaction(evmProxyMsg, sender, assets, options) {
606
+ async sendCrossChainTransaction(evmProxyMsg, sender, assets, options, waitOptions) {
543
607
  const caller = sender.getSenderAddress();
608
+ this.debugLog(`Caller: ${caller}`);
544
609
  const { transaction, transactionLinker } = await this.prepareCrossChainTransaction(evmProxyMsg, caller, assets, options);
545
- console.log('*****Sending transaction: ', transaction);
610
+ this.debugLog(`*****Sending transaction: ${(0, Utils_1.formatObjectForLogging)(transaction)}`);
546
611
  const sendTransactionResult = await sender.sendShardTransaction(transaction, this.delay, this.network, this.TONParams.contractOpener);
547
- return { sendTransactionResult, ...transactionLinker };
612
+ return waitOptions
613
+ ? {
614
+ sendTransactionResult,
615
+ operationId: await this.operationTracker.getOperationId(transactionLinker, {
616
+ ...waitOptions,
617
+ successCheck: (operationId) => !!operationId,
618
+ log: this.debugLog.bind(this),
619
+ }),
620
+ ...transactionLinker,
621
+ }
622
+ : { sendTransactionResult, ...transactionLinker };
548
623
  }
549
- async sendCrossChainTransactions(sender, txs) {
624
+ async sendCrossChainTransactions(sender, txs, waitOptions) {
550
625
  const transactions = [];
551
626
  const transactionLinkers = [];
552
627
  const caller = sender.getSenderAddress();
628
+ this.debugLog(`Caller: ${caller}`);
629
+ this.debugLog('Preparing multiple cross-chain transactions');
553
630
  for (const { options, assets, evmProxyMsg } of txs) {
554
631
  const { transaction, transactionLinker } = await this.prepareCrossChainTransaction(evmProxyMsg, caller, assets, options);
555
632
  transactions.push(transaction);
556
633
  transactionLinkers.push(transactionLinker);
557
634
  }
558
- console.log('*****Sending transactions: ', transactions);
635
+ this.debugLog(`*****Sending transactions: ${(0, Utils_1.formatObjectForLogging)(transactions)}`);
559
636
  await sender.sendShardTransactions(transactions, this.delay, this.network, this.TONParams.contractOpener);
637
+ if (waitOptions) {
638
+ this.debugLog(`Waiting for operation IDs`);
639
+ try {
640
+ const operationIds = await this.operationTracker.getOperationIdsByShardsKeys(transactionLinkers.map((linker) => linker.shardsKey), caller, {
641
+ ...waitOptions,
642
+ log: this.debugLog.bind(this),
643
+ successCheck: (operationIds) => {
644
+ return (Object.keys(operationIds).length == transactionLinkers.length &&
645
+ Object.values(operationIds).every((ids) => ids.operationIds.length > 0));
646
+ },
647
+ });
648
+ this.debugLog(`Operation IDs: ${(0, Utils_1.formatObjectForLogging)(operationIds)}`);
649
+ return transactionLinkers.map((linker) => ({
650
+ ...linker,
651
+ operationId: operationIds[linker.shardsKey].operationIds[0],
652
+ }));
653
+ }
654
+ catch (error) {
655
+ this.debugLog(`Error while waiting for operation IDs: ${error}`);
656
+ }
657
+ }
560
658
  return transactionLinkers;
561
659
  }
562
660
  // TODO move to sdk.TAC, sdk.TON
563
661
  async bridgeTokensToTON(signer, value, tonTarget, assets, tvmExecutorFee) {
662
+ this.debugLog('Bridging tokens to TON');
564
663
  if (assets == undefined) {
565
664
  assets = [];
566
665
  }
567
- let tonAssets = [];
666
+ const tonAssets = [];
568
667
  for (const asset of assets) {
569
668
  if (asset.type == Struct_1.AssetType.FT) {
570
669
  const tvmAddress = await this.getTVMTokenAddress(asset.address);
@@ -583,7 +682,9 @@ class TacSdk {
583
682
  });
584
683
  }
585
684
  }
685
+ this.debugLog(`TON assets: ${(0, Utils_1.formatObjectForLogging)(tonAssets)}`);
586
686
  if (value > 0) {
687
+ this.debugLog('Adding native TAC to TON assets');
587
688
  const tvmAddress = await this.getTVMTokenAddress(await this.nativeTACAddress());
588
689
  tonAssets.push({
589
690
  address: tvmAddress,
@@ -592,21 +693,28 @@ class TacSdk {
592
693
  });
593
694
  }
594
695
  const suggestedTONExecutorFee = await this.getTVMExecutorFeeInfo(tonAssets, Consts_1.TAC_SYMBOL);
696
+ this.debugLog(`Suggested TON executor fee: ${(0, Utils_1.formatObjectForLogging)(suggestedTONExecutorFee)}`);
595
697
  const crossChainLayerAddress = await this.TACParams.crossChainLayer.getAddress();
596
698
  for (const asset of assets) {
597
699
  if (asset.type == Struct_1.AssetType.FT) {
700
+ this.debugLog(`Approving token ${asset.address} for ${crossChainLayerAddress}`);
598
701
  const tokenContract = this.artifacts.tac.wrappers.ERC20FactoryTAC.connect(asset.address, this.TACParams.provider);
599
702
  const tx = await tokenContract.connect(signer).approve(crossChainLayerAddress, asset.rawAmount);
600
703
  await tx.wait();
704
+ this.debugLog(`Approved ${asset.address} for ${crossChainLayerAddress}`);
601
705
  }
602
706
  if (asset.type == Struct_1.AssetType.NFT) {
707
+ this.debugLog(`Approving collection ${asset.collectionAddress} for ${crossChainLayerAddress}`);
603
708
  const tokenContract = this.artifacts.tac.wrappers.ERC721FactoryTAC.connect(asset.collectionAddress, this.TACParams.provider);
604
709
  const tx = await tokenContract.connect(signer).approve(crossChainLayerAddress, asset.itemIndex);
605
710
  await tx.wait();
711
+ this.debugLog(`Approved ${asset.collectionAddress} for ${crossChainLayerAddress}`);
606
712
  }
607
713
  }
608
714
  const shardsKey = BigInt(Math.round(Math.random() * 1e18));
715
+ this.debugLog(`Shards key: ${shardsKey}`);
609
716
  const protocolFee = await this.TACParams.crossChainLayer.getProtocolFee();
717
+ this.debugLog(`Protocol fee: ${protocolFee}`);
610
718
  const outMessage = {
611
719
  shardsKey: shardsKey,
612
720
  tvmTarget: tonTarget,
@@ -631,10 +739,12 @@ class TacSdk {
631
739
  const encodedOutMessage = this.artifacts.tac.utils.encodeOutMessageV1(outMessage);
632
740
  const outMsgVersion = 1n;
633
741
  const totalValue = value + BigInt(outMessage.tvmProtocolFee) + BigInt(outMessage.tvmExecutorFee);
742
+ this.debugLog(`Total value: ${totalValue}`);
634
743
  const tx = await this.TACParams.crossChainLayer
635
744
  .connect(signer)
636
745
  .sendMessage(outMsgVersion, encodedOutMessage, { value: totalValue });
637
746
  await tx.wait();
747
+ this.debugLog(`Transaction hash: ${tx.hash}`);
638
748
  return tx.hash;
639
749
  }
640
750
  get getTrustedTACExecutors() {
@@ -644,28 +754,34 @@ class TacSdk {
644
754
  return this.TACParams.trustedTONExecutors;
645
755
  }
646
756
  async getEVMTokenAddress(tvmTokenAddress) {
757
+ this.debugLog(`Getting EVM token address for ${tvmTokenAddress}`);
647
758
  if (tvmTokenAddress !== this.nativeTONAddress) {
648
759
  (0, Utils_1.validateTVMAddress)(tvmTokenAddress);
649
760
  tvmTokenAddress = ton_1.Address.parse(tvmTokenAddress).toString({ bounceable: true });
650
761
  const { code: givenMinterCodeBOC } = await this.TONParams.contractOpener.getContractState((0, ton_1.address)(tvmTokenAddress));
651
762
  await (0, Utils_1.sleep)(this.delay * 1000);
652
763
  if (givenMinterCodeBOC && this.TONParams.jettonMinterCode.equals(ton_1.Cell.fromBoc(givenMinterCodeBOC)[0])) {
764
+ this.debugLog(`Computing EVM token address using jetton minter`);
653
765
  const givenMinter = this.TONParams.contractOpener.open(new JettonMaster_1.JettonMaster((0, ton_1.address)(tvmTokenAddress)));
654
766
  const evmAddress = await givenMinter.getEVMAddress();
655
767
  await (0, Utils_1.sleep)(this.delay * 1000);
656
768
  return evmAddress;
657
769
  }
658
770
  }
771
+ this.debugLog(`Computing EVM token address using token utils`);
659
772
  return this.TACParams.tokenUtils.computeAddress(tvmTokenAddress);
660
773
  }
661
774
  async getTVMTokenAddress(evmTokenAddress) {
775
+ this.debugLog(`Getting TVM token address for ${evmTokenAddress}`);
662
776
  (0, Utils_1.validateEVMAddress)(evmTokenAddress);
663
777
  const exists = await this.TACParams.tokenUtils['exists(address)'](evmTokenAddress);
664
778
  if (exists) {
779
+ this.debugLog(`Getting TVM token address using cross chain layer ERC20 factory`);
665
780
  const erc721Token = this.artifacts.tac.wrappers.CrossChainLayerERC20FactoryTAC.connect(evmTokenAddress, this.TACParams.provider);
666
781
  const info = await erc721Token.getInfo();
667
782
  return info.tvmAddress;
668
783
  }
784
+ this.debugLog(`Getting TVM token address using jetton minter`);
669
785
  const jettonMaster = JettonMaster_1.JettonMaster.createFromConfig({
670
786
  evmTokenAddress,
671
787
  crossChainLayerAddress: (0, ton_1.address)(this.TONParams.crossChainLayerAddress),
@@ -675,10 +791,12 @@ class TacSdk {
675
791
  return jettonMaster.address.toString();
676
792
  }
677
793
  async getTVMNFTAddress(evmNFTAddress, tokenId) {
794
+ this.debugLog(`Getting TVM NFT ${tokenId ? `item ${tokenId}` : 'collection'} address for ${evmNFTAddress}`);
678
795
  (0, Utils_1.validateEVMAddress)(evmNFTAddress);
679
796
  let nftCollection;
680
797
  const exists = await this.TACParams.tokenUtils['exists(address)'](evmNFTAddress);
681
798
  if (exists) {
799
+ this.debugLog(`Getting TVM NFT address using cross chain layer ERC721 factory`);
682
800
  const erc721Token = this.artifacts.tac.wrappers.CrossChainLayerERC721FactoryTAC.connect(evmNFTAddress, this.TACParams.provider);
683
801
  const info = await erc721Token.getInfo();
684
802
  nftCollection = this.TONParams.contractOpener.open(wrappers_1.NFTCollection.createFromAddress((0, ton_1.address)(info.tvmAddress)));
@@ -687,9 +805,12 @@ class TacSdk {
687
805
  : (await nftCollection.getNFTAddressByIndex(tokenId)).toString();
688
806
  }
689
807
  else {
808
+ this.debugLog(`Getting TVM NFT address using TON NFT collection contract`);
690
809
  nftCollection = this.TONParams.contractOpener.open(wrappers_1.NFTCollection.createFromConfig({
691
- ownerAddress: (0, ton_1.address)(this.TONParams.crossChainLayerAddress),
692
- content: (0, ton_1.beginCell)().endCell(),
810
+ adminAddress: (0, ton_1.address)(this.TONParams.crossChainLayerAddress),
811
+ newAdminAddress: null,
812
+ commonContent: (0, ton_1.beginCell)().endCell(),
813
+ collectionContent: (0, ton_1.beginCell)().endCell(),
693
814
  nftItemCode: this.TONParams.nftItemCode,
694
815
  originalAddress: evmNFTAddress,
695
816
  }, this.TONParams.nftCollectionCode));
@@ -698,43 +819,50 @@ class TacSdk {
698
819
  : wrappers_1.NFTItem.createFromConfig({
699
820
  collectionAddress: nftCollection.address,
700
821
  cclAddress: (0, ton_1.address)(this.TONParams.crossChainLayerAddress),
701
- // @ts-ignore // bigint can be used, wrapper is not typed properly
822
+ // @ts-expect-error // bigint can be used, wrapper is not typed properly
702
823
  index: tokenId,
703
824
  }, this.TONParams.nftItemCode).address.toString();
704
825
  }
705
826
  }
706
827
  async getEVMNFTAddress(tvmNFTAddress, addressType) {
828
+ this.debugLog(`Getting EVM NFT address for ${tvmNFTAddress}`);
707
829
  (0, Utils_1.validateTVMAddress)(tvmNFTAddress);
708
830
  tvmNFTAddress = ton_1.Address.parse(tvmNFTAddress).toString({ bounceable: true });
709
831
  if (addressType == Struct_1.NFTAddressType.ITEM) {
832
+ this.debugLog(`Retrieving collection address for item ${tvmNFTAddress}`);
710
833
  tvmNFTAddress = (await this.getNFTItemData(tvmNFTAddress)).collectionAddress.toString();
834
+ this.debugLog(`Collection address: ${tvmNFTAddress}`);
711
835
  addressType = Struct_1.NFTAddressType.COLLECTION;
712
836
  await (0, Utils_1.sleep)(this.delay * 1000);
713
837
  }
714
838
  const { code: givenNFTCollection } = await this.TONParams.contractOpener.getContractState((0, ton_1.address)(tvmNFTAddress));
715
839
  await (0, Utils_1.sleep)(this.delay * 1000);
716
840
  if (givenNFTCollection && this.TONParams.nftCollectionCode.equals(ton_1.Cell.fromBoc(givenNFTCollection)[0])) {
841
+ this.debugLog(`Getting EVM NFT address using TON NFT collection contract`);
717
842
  const nftCollection = this.TONParams.contractOpener.open(wrappers_1.NFTCollection.createFromAddress((0, ton_1.address)(tvmNFTAddress)));
718
843
  const evmAddress = await nftCollection.getOriginalAddress();
719
844
  await (0, Utils_1.sleep)(this.delay * 1000);
720
845
  return evmAddress.toString();
721
846
  }
847
+ this.debugLog(`Computing EVM NFT address using token utils`);
722
848
  return this.TACParams.tokenUtils.computeAddressERC721(tvmNFTAddress);
723
849
  }
724
850
  async isContractDeployedOnTVM(address) {
725
851
  return (await this.TONParams.contractOpener.getContractState(ton_1.Address.parse(address))).state === 'active';
726
852
  }
727
853
  async simulateTACMessage(req) {
854
+ this.debugLog('Simulating TAC message');
728
855
  let lastError;
729
856
  for (const endpoint of this.liteSequencerEndpoints) {
730
857
  try {
731
858
  const response = await axios_1.default.post(new URL('tac/simulator/simulate-message', endpoint).toString(), req, {
732
859
  transformResponse: [Utils_1.toCamelCaseTransformer],
733
860
  });
861
+ this.debugLog('TAC message simulation success');
734
862
  return response.data.response;
735
863
  }
736
864
  catch (error) {
737
- console.error(`Error while simulating with ${endpoint}:`, error);
865
+ this.debugLog(`Error while simulating with ${endpoint}: ${error}`);
738
866
  lastError = error;
739
867
  }
740
868
  }
@@ -1,7 +1,7 @@
1
1
  import { Address, Cell } from '@ton/ton';
2
2
  import { AbiCoder } from 'ethers';
3
- import { EvmProxyMsg, FeeParams, TransactionLinker, ValidExecutors } from '../structs/Struct';
4
3
  import { RandomNumberByTimestamp } from '../structs/InternalStruct';
4
+ import { EvmProxyMsg, FeeParams, TransactionLinker, ValidExecutors, WaitOptions } from '../structs/Struct';
5
5
  export declare const sleep: (ms: number) => Promise<unknown>;
6
6
  export declare function generateRandomNumber(interval: number): number;
7
7
  export declare function generateRandomNumberByTimestamp(): RandomNumberByTimestamp;
@@ -15,5 +15,7 @@ export declare function calculateEVMTokenAddress(abiCoder: AbiCoder, tokenUtilsA
15
15
  export declare const convertKeysToCamelCase: <T>(data: T) => T;
16
16
  export declare const calculateRawAmount: (amount: number, decimals: number) => bigint;
17
17
  export declare const calculateAmount: (rawAmount: bigint, decimals: number) => number;
18
- export declare const toCamelCaseTransformer: (data: any) => any;
18
+ export declare const toCamelCaseTransformer: (data: string) => any;
19
19
  export declare const generateFeeData: (feeParams?: FeeParams) => Cell | undefined;
20
+ export declare function waitUntilSuccess<T, A extends unknown[]>(options: WaitOptions<T> | undefined, operation: (...args: A) => Promise<T>, ...args: A): Promise<T>;
21
+ export declare function formatObjectForLogging(obj: unknown): string;