@tonappchain/sdk 0.6.4 → 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,53 +4,53 @@ 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;
36
40
  const delay = sdkParams.delay ?? Consts_1.DEFAULT_DELAY;
37
41
  const artifacts = network === Struct_1.Network.TESTNET ? artifacts_1.testnet : artifacts_1.mainnet;
38
- const TONParams = await this.prepareTONParams(network, delay, artifacts, sdkParams.TONParams);
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);
45
- }
46
- static async prepareTONParams(network, delay, artifacts, TONParams) {
47
- const contractOpener = TONParams?.contractOpener ??
48
- new ton_1.TonClient({
49
- endpoint: network == Struct_1.Network.TESTNET
50
- ? new URL('api/v2/jsonRPC', artifacts_1.testnet.TON_RPC_ENDPOINT_BY_TAC).toString()
51
- : artifacts_1.mainnet.TON_PUBLIC_RPC_ENDPOINT,
52
- });
53
- const settingsAddress = TONParams?.settingsAddress ?? artifacts.ton.addresses.TON_SETTINGS_ADDRESS;
49
+ return new TacSdk(network, delay, artifacts, TONParams, TACParams, liteSequencerEndpoints, debug);
50
+ }
51
+ static async prepareTONParams(delay, artifacts, TONParams) {
52
+ const contractOpener = TONParams?.contractOpener ?? (await (0, retryableContractOpener_1.createDefaultRetryableOpener)(artifacts));
53
+ const settingsAddress = TONParams?.settingsAddress ?? artifacts.TON_SETTINGS_ADDRESS;
54
54
  const settings = contractOpener.open(new Settings_1.Settings(ton_1.Address.parse(settingsAddress)));
55
55
  const jettonProxyAddress = await settings.getAddressSetting('JettonProxyAddress');
56
56
  await (0, Utils_1.sleep)(delay * 1000);
@@ -79,7 +79,7 @@ class TacSdk {
79
79
  }
80
80
  static async prepareTACParams(artifacts, delay, TACParams) {
81
81
  const provider = TACParams?.provider ?? ethers_1.ethers.getDefaultProvider(artifacts.TAC_RPC_ENDPOINT);
82
- const settingsAddress = TACParams?.settingsAddress?.toString() ?? artifacts.tac.addresses.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, evmValidExecutors, forceSend = false, isRoundTrip) {
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,28 +487,27 @@ class TacSdk {
440
487
  })),
441
488
  tonCaller: transactionLinker.caller,
442
489
  };
490
+ isRoundTrip = isRoundTrip ?? rawAssets.length != 0;
491
+ this.debugLog(`Is round trip: ${isRoundTrip}`);
443
492
  const tacSimulationResult = await this.simulateTACMessage(tacSimulationBody);
493
+ this.debugLog(`TAC simulation ${tacSimulationResult.simulationStatus ? 'success' : 'failed'}`);
444
494
  if (!tacSimulationResult.simulationStatus) {
445
495
  if (forceSend) {
496
+ this.debugLog('Force send is true, returning fee params');
446
497
  return {
447
498
  feeParams: {
448
- isRoundTrip: isRoundTrip ?? false,
499
+ isRoundTrip,
449
500
  gasLimit: 0n,
450
501
  protocolFee: BigInt((0, ton_1.toNano)(fullStateCCL.tacProtocolFee)) +
451
- BigInt(isRoundTrip ?? false) * BigInt((0, ton_1.toNano)(fullStateCCL.tonProtocolFee)),
452
- evmExecutorFee: 0n,
453
- tvmExecutorFee: 0n,
502
+ BigInt(isRoundTrip) * BigInt((0, ton_1.toNano)(fullStateCCL.tonProtocolFee)),
503
+ evmExecutorFee: BigInt(tacSimulationResult.suggestedTacExecutionFee),
504
+ tvmExecutorFee: BigInt(tacSimulationResult.suggestedTonExecutionFee) * BigInt(isRoundTrip),
454
505
  },
455
506
  simulation: tacSimulationResult,
456
507
  };
457
508
  }
458
509
  throw tacSimulationResult;
459
510
  }
460
- isRoundTrip = isRoundTrip ?? tacSimulationResult.outMessages != null;
461
- let tonExecutorFeeInTON = 0n;
462
- if (isRoundTrip) {
463
- tonExecutorFeeInTON = BigInt(tacSimulationResult.suggestedTonExecutionFee);
464
- }
465
511
  const protocolFee = BigInt((0, ton_1.toNano)(fullStateCCL.tacProtocolFee)) +
466
512
  BigInt(isRoundTrip) * BigInt((0, ton_1.toNano)(fullStateCCL.tonProtocolFee));
467
513
  const feeParams = {
@@ -469,19 +515,23 @@ class TacSdk {
469
515
  gasLimit: tacSimulationResult.estimatedGas,
470
516
  protocolFee: protocolFee,
471
517
  evmExecutorFee: BigInt(tacSimulationResult.suggestedTacExecutionFee),
472
- tvmExecutorFee: tonExecutorFeeInTON,
518
+ tvmExecutorFee: BigInt(tacSimulationResult.suggestedTonExecutionFee) * BigInt(isRoundTrip),
473
519
  };
520
+ this.debugLog(`Collected fee params: ${(0, Utils_1.formatObjectForLogging)(feeParams)}`);
474
521
  return { feeParams: feeParams, simulation: tacSimulationResult };
475
522
  }
476
523
  async getTransactionSimulationInfo(evmProxyMsg, sender, assets) {
524
+ this.debugLog('Getting transaction simulation info');
477
525
  const rawAssets = await this.convertAssetsToRawFormat(assets);
478
526
  const aggregatedData = await this.aggregateTokens(rawAssets);
479
527
  const transactionLinkerShardCount = aggregatedData.jettons.length == 0 ? 1 : aggregatedData.jettons.length;
528
+ this.debugLog(`Transaction linker shard count: ${transactionLinkerShardCount}`);
480
529
  const transactionLinker = (0, Utils_1.generateTransactionLinker)(sender.getSenderAddress(), transactionLinkerShardCount);
481
- const evmValidExecutors = this.TACParams.trustedTACExecutors;
482
- return await this.getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, evmValidExecutors, false, undefined);
530
+ this.debugLog(`Transaction linker: ${(0, Utils_1.formatObjectForLogging)(transactionLinker)}`);
531
+ return await this.getFeeInfo(evmProxyMsg, transactionLinker, rawAssets);
483
532
  }
484
533
  async getTVMExecutorFeeInfo(assets, feeSymbol) {
534
+ this.debugLog('Getting TVM executor fee info');
485
535
  const rawAssets = await this.convertAssetsToRawFormat(assets);
486
536
  const requestBody = {
487
537
  tonAssets: rawAssets.map((asset) => ({
@@ -498,26 +548,32 @@ class TacSdk {
498
548
  return response.data.response;
499
549
  }
500
550
  catch (error) {
501
- console.error(`Error while calculating tvm executor fee ${endpoint}:`, error);
551
+ this.debugLog(`Error while calculating tvm executor fee ${endpoint}: ${error}`);
502
552
  lastError = error;
503
553
  }
504
554
  }
555
+ this.debugLog('Error while calculating tvm executor fee on all endpoints');
505
556
  throw (0, errors_1.simulationError)(lastError);
506
557
  }
507
558
  async prepareCrossChainTransaction(evmProxyMsg, caller, assets, options) {
508
- 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 || {};
509
562
  const rawAssets = await this.convertAssetsToRawFormat(assets);
510
563
  const aggregatedData = await this.aggregateTokens(rawAssets);
511
564
  const tokensLength = aggregatedData.jettons.length + aggregatedData.nfts.length;
512
- 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}`);
513
568
  const transactionLinker = (0, Utils_1.generateTransactionLinker)(caller, transactionLinkerShardCount);
569
+ this.debugLog(`Generated transaction linker: ${(0, Utils_1.formatObjectForLogging)(transactionLinker)}`);
514
570
  if (evmValidExecutors.length == 0) {
515
571
  evmValidExecutors = this.TACParams.trustedTACExecutors;
516
572
  }
517
573
  if (tvmValidExecutors.length == 0) {
518
574
  tvmValidExecutors = this.TACParams.trustedTONExecutors;
519
575
  }
520
- const { feeParams } = await this.getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, evmValidExecutors, forceSend, isRoundTrip);
576
+ const { feeParams } = await this.getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, forceSend, isRoundTrip, evmValidExecutors, tvmValidExecutors);
521
577
  if (evmProxyMsg.gasLimit == undefined) {
522
578
  evmProxyMsg.gasLimit = feeParams.gasLimit;
523
579
  }
@@ -530,10 +586,12 @@ class TacSdk {
530
586
  if (protocolFee != undefined) {
531
587
  feeParams.protocolFee = protocolFee;
532
588
  }
589
+ this.debugLog(`Resulting fee params: ${(0, Utils_1.formatObjectForLogging)(feeParams)}`);
533
590
  const validExecutors = {
534
591
  tac: evmValidExecutors,
535
592
  ton: tvmValidExecutors,
536
593
  };
594
+ this.debugLog(`Valid executors: ${(0, Utils_1.formatObjectForLogging)(validExecutors)}`);
537
595
  const evmData = (0, Utils_1.buildEvmDataCell)(transactionLinker, evmProxyMsg, validExecutors);
538
596
  const messages = await this.generateCrossChainMessages(caller, evmData, aggregatedData, feeParams);
539
597
  await (0, Utils_1.sleep)(this.delay * 1000);
@@ -542,34 +600,70 @@ class TacSdk {
542
600
  messages,
543
601
  network: this.network,
544
602
  };
603
+ this.debugLog('Transaction prepared');
545
604
  return { transaction, transactionLinker };
546
605
  }
547
- async sendCrossChainTransaction(evmProxyMsg, sender, assets, options) {
606
+ async sendCrossChainTransaction(evmProxyMsg, sender, assets, options, waitOptions) {
548
607
  const caller = sender.getSenderAddress();
608
+ this.debugLog(`Caller: ${caller}`);
549
609
  const { transaction, transactionLinker } = await this.prepareCrossChainTransaction(evmProxyMsg, caller, assets, options);
550
- console.log('*****Sending transaction: ', transaction);
610
+ this.debugLog(`*****Sending transaction: ${(0, Utils_1.formatObjectForLogging)(transaction)}`);
551
611
  const sendTransactionResult = await sender.sendShardTransaction(transaction, this.delay, this.network, this.TONParams.contractOpener);
552
- 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 };
553
623
  }
554
- async sendCrossChainTransactions(sender, txs) {
624
+ async sendCrossChainTransactions(sender, txs, waitOptions) {
555
625
  const transactions = [];
556
626
  const transactionLinkers = [];
557
627
  const caller = sender.getSenderAddress();
628
+ this.debugLog(`Caller: ${caller}`);
629
+ this.debugLog('Preparing multiple cross-chain transactions');
558
630
  for (const { options, assets, evmProxyMsg } of txs) {
559
631
  const { transaction, transactionLinker } = await this.prepareCrossChainTransaction(evmProxyMsg, caller, assets, options);
560
632
  transactions.push(transaction);
561
633
  transactionLinkers.push(transactionLinker);
562
634
  }
563
- console.log('*****Sending transactions: ', transactions);
635
+ this.debugLog(`*****Sending transactions: ${(0, Utils_1.formatObjectForLogging)(transactions)}`);
564
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
+ }
565
658
  return transactionLinkers;
566
659
  }
567
660
  // TODO move to sdk.TAC, sdk.TON
568
661
  async bridgeTokensToTON(signer, value, tonTarget, assets, tvmExecutorFee) {
662
+ this.debugLog('Bridging tokens to TON');
569
663
  if (assets == undefined) {
570
664
  assets = [];
571
665
  }
572
- let tonAssets = [];
666
+ const tonAssets = [];
573
667
  for (const asset of assets) {
574
668
  if (asset.type == Struct_1.AssetType.FT) {
575
669
  const tvmAddress = await this.getTVMTokenAddress(asset.address);
@@ -588,7 +682,9 @@ class TacSdk {
588
682
  });
589
683
  }
590
684
  }
685
+ this.debugLog(`TON assets: ${(0, Utils_1.formatObjectForLogging)(tonAssets)}`);
591
686
  if (value > 0) {
687
+ this.debugLog('Adding native TAC to TON assets');
592
688
  const tvmAddress = await this.getTVMTokenAddress(await this.nativeTACAddress());
593
689
  tonAssets.push({
594
690
  address: tvmAddress,
@@ -597,21 +693,28 @@ class TacSdk {
597
693
  });
598
694
  }
599
695
  const suggestedTONExecutorFee = await this.getTVMExecutorFeeInfo(tonAssets, Consts_1.TAC_SYMBOL);
696
+ this.debugLog(`Suggested TON executor fee: ${(0, Utils_1.formatObjectForLogging)(suggestedTONExecutorFee)}`);
600
697
  const crossChainLayerAddress = await this.TACParams.crossChainLayer.getAddress();
601
698
  for (const asset of assets) {
602
699
  if (asset.type == Struct_1.AssetType.FT) {
700
+ this.debugLog(`Approving token ${asset.address} for ${crossChainLayerAddress}`);
603
701
  const tokenContract = this.artifacts.tac.wrappers.ERC20FactoryTAC.connect(asset.address, this.TACParams.provider);
604
702
  const tx = await tokenContract.connect(signer).approve(crossChainLayerAddress, asset.rawAmount);
605
703
  await tx.wait();
704
+ this.debugLog(`Approved ${asset.address} for ${crossChainLayerAddress}`);
606
705
  }
607
706
  if (asset.type == Struct_1.AssetType.NFT) {
707
+ this.debugLog(`Approving collection ${asset.collectionAddress} for ${crossChainLayerAddress}`);
608
708
  const tokenContract = this.artifacts.tac.wrappers.ERC721FactoryTAC.connect(asset.collectionAddress, this.TACParams.provider);
609
709
  const tx = await tokenContract.connect(signer).approve(crossChainLayerAddress, asset.itemIndex);
610
710
  await tx.wait();
711
+ this.debugLog(`Approved ${asset.collectionAddress} for ${crossChainLayerAddress}`);
611
712
  }
612
713
  }
613
714
  const shardsKey = BigInt(Math.round(Math.random() * 1e18));
715
+ this.debugLog(`Shards key: ${shardsKey}`);
614
716
  const protocolFee = await this.TACParams.crossChainLayer.getProtocolFee();
717
+ this.debugLog(`Protocol fee: ${protocolFee}`);
615
718
  const outMessage = {
616
719
  shardsKey: shardsKey,
617
720
  tvmTarget: tonTarget,
@@ -636,10 +739,12 @@ class TacSdk {
636
739
  const encodedOutMessage = this.artifacts.tac.utils.encodeOutMessageV1(outMessage);
637
740
  const outMsgVersion = 1n;
638
741
  const totalValue = value + BigInt(outMessage.tvmProtocolFee) + BigInt(outMessage.tvmExecutorFee);
742
+ this.debugLog(`Total value: ${totalValue}`);
639
743
  const tx = await this.TACParams.crossChainLayer
640
744
  .connect(signer)
641
745
  .sendMessage(outMsgVersion, encodedOutMessage, { value: totalValue });
642
746
  await tx.wait();
747
+ this.debugLog(`Transaction hash: ${tx.hash}`);
643
748
  return tx.hash;
644
749
  }
645
750
  get getTrustedTACExecutors() {
@@ -649,28 +754,34 @@ class TacSdk {
649
754
  return this.TACParams.trustedTONExecutors;
650
755
  }
651
756
  async getEVMTokenAddress(tvmTokenAddress) {
757
+ this.debugLog(`Getting EVM token address for ${tvmTokenAddress}`);
652
758
  if (tvmTokenAddress !== this.nativeTONAddress) {
653
759
  (0, Utils_1.validateTVMAddress)(tvmTokenAddress);
654
760
  tvmTokenAddress = ton_1.Address.parse(tvmTokenAddress).toString({ bounceable: true });
655
761
  const { code: givenMinterCodeBOC } = await this.TONParams.contractOpener.getContractState((0, ton_1.address)(tvmTokenAddress));
656
762
  await (0, Utils_1.sleep)(this.delay * 1000);
657
763
  if (givenMinterCodeBOC && this.TONParams.jettonMinterCode.equals(ton_1.Cell.fromBoc(givenMinterCodeBOC)[0])) {
764
+ this.debugLog(`Computing EVM token address using jetton minter`);
658
765
  const givenMinter = this.TONParams.contractOpener.open(new JettonMaster_1.JettonMaster((0, ton_1.address)(tvmTokenAddress)));
659
766
  const evmAddress = await givenMinter.getEVMAddress();
660
767
  await (0, Utils_1.sleep)(this.delay * 1000);
661
768
  return evmAddress;
662
769
  }
663
770
  }
771
+ this.debugLog(`Computing EVM token address using token utils`);
664
772
  return this.TACParams.tokenUtils.computeAddress(tvmTokenAddress);
665
773
  }
666
774
  async getTVMTokenAddress(evmTokenAddress) {
775
+ this.debugLog(`Getting TVM token address for ${evmTokenAddress}`);
667
776
  (0, Utils_1.validateEVMAddress)(evmTokenAddress);
668
777
  const exists = await this.TACParams.tokenUtils['exists(address)'](evmTokenAddress);
669
778
  if (exists) {
779
+ this.debugLog(`Getting TVM token address using cross chain layer ERC20 factory`);
670
780
  const erc721Token = this.artifacts.tac.wrappers.CrossChainLayerERC20FactoryTAC.connect(evmTokenAddress, this.TACParams.provider);
671
781
  const info = await erc721Token.getInfo();
672
782
  return info.tvmAddress;
673
783
  }
784
+ this.debugLog(`Getting TVM token address using jetton minter`);
674
785
  const jettonMaster = JettonMaster_1.JettonMaster.createFromConfig({
675
786
  evmTokenAddress,
676
787
  crossChainLayerAddress: (0, ton_1.address)(this.TONParams.crossChainLayerAddress),
@@ -680,10 +791,12 @@ class TacSdk {
680
791
  return jettonMaster.address.toString();
681
792
  }
682
793
  async getTVMNFTAddress(evmNFTAddress, tokenId) {
794
+ this.debugLog(`Getting TVM NFT ${tokenId ? `item ${tokenId}` : 'collection'} address for ${evmNFTAddress}`);
683
795
  (0, Utils_1.validateEVMAddress)(evmNFTAddress);
684
796
  let nftCollection;
685
797
  const exists = await this.TACParams.tokenUtils['exists(address)'](evmNFTAddress);
686
798
  if (exists) {
799
+ this.debugLog(`Getting TVM NFT address using cross chain layer ERC721 factory`);
687
800
  const erc721Token = this.artifacts.tac.wrappers.CrossChainLayerERC721FactoryTAC.connect(evmNFTAddress, this.TACParams.provider);
688
801
  const info = await erc721Token.getInfo();
689
802
  nftCollection = this.TONParams.contractOpener.open(wrappers_1.NFTCollection.createFromAddress((0, ton_1.address)(info.tvmAddress)));
@@ -692,9 +805,12 @@ class TacSdk {
692
805
  : (await nftCollection.getNFTAddressByIndex(tokenId)).toString();
693
806
  }
694
807
  else {
808
+ this.debugLog(`Getting TVM NFT address using TON NFT collection contract`);
695
809
  nftCollection = this.TONParams.contractOpener.open(wrappers_1.NFTCollection.createFromConfig({
696
- ownerAddress: (0, ton_1.address)(this.TONParams.crossChainLayerAddress),
697
- 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(),
698
814
  nftItemCode: this.TONParams.nftItemCode,
699
815
  originalAddress: evmNFTAddress,
700
816
  }, this.TONParams.nftCollectionCode));
@@ -703,43 +819,50 @@ class TacSdk {
703
819
  : wrappers_1.NFTItem.createFromConfig({
704
820
  collectionAddress: nftCollection.address,
705
821
  cclAddress: (0, ton_1.address)(this.TONParams.crossChainLayerAddress),
706
- // @ts-ignore // bigint can be used, wrapper is not typed properly
822
+ // @ts-expect-error // bigint can be used, wrapper is not typed properly
707
823
  index: tokenId,
708
824
  }, this.TONParams.nftItemCode).address.toString();
709
825
  }
710
826
  }
711
827
  async getEVMNFTAddress(tvmNFTAddress, addressType) {
828
+ this.debugLog(`Getting EVM NFT address for ${tvmNFTAddress}`);
712
829
  (0, Utils_1.validateTVMAddress)(tvmNFTAddress);
713
830
  tvmNFTAddress = ton_1.Address.parse(tvmNFTAddress).toString({ bounceable: true });
714
831
  if (addressType == Struct_1.NFTAddressType.ITEM) {
832
+ this.debugLog(`Retrieving collection address for item ${tvmNFTAddress}`);
715
833
  tvmNFTAddress = (await this.getNFTItemData(tvmNFTAddress)).collectionAddress.toString();
834
+ this.debugLog(`Collection address: ${tvmNFTAddress}`);
716
835
  addressType = Struct_1.NFTAddressType.COLLECTION;
717
836
  await (0, Utils_1.sleep)(this.delay * 1000);
718
837
  }
719
838
  const { code: givenNFTCollection } = await this.TONParams.contractOpener.getContractState((0, ton_1.address)(tvmNFTAddress));
720
839
  await (0, Utils_1.sleep)(this.delay * 1000);
721
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`);
722
842
  const nftCollection = this.TONParams.contractOpener.open(wrappers_1.NFTCollection.createFromAddress((0, ton_1.address)(tvmNFTAddress)));
723
843
  const evmAddress = await nftCollection.getOriginalAddress();
724
844
  await (0, Utils_1.sleep)(this.delay * 1000);
725
845
  return evmAddress.toString();
726
846
  }
847
+ this.debugLog(`Computing EVM NFT address using token utils`);
727
848
  return this.TACParams.tokenUtils.computeAddressERC721(tvmNFTAddress);
728
849
  }
729
850
  async isContractDeployedOnTVM(address) {
730
851
  return (await this.TONParams.contractOpener.getContractState(ton_1.Address.parse(address))).state === 'active';
731
852
  }
732
853
  async simulateTACMessage(req) {
854
+ this.debugLog('Simulating TAC message');
733
855
  let lastError;
734
856
  for (const endpoint of this.liteSequencerEndpoints) {
735
857
  try {
736
858
  const response = await axios_1.default.post(new URL('tac/simulator/simulate-message', endpoint).toString(), req, {
737
859
  transformResponse: [Utils_1.toCamelCaseTransformer],
738
860
  });
861
+ this.debugLog('TAC message simulation success');
739
862
  return response.data.response;
740
863
  }
741
864
  catch (error) {
742
- console.error(`Error while simulating with ${endpoint}:`, error);
865
+ this.debugLog(`Error while simulating with ${endpoint}: ${error}`);
743
866
  lastError = error;
744
867
  }
745
868
  }