@tonappchain/sdk 0.6.1-v3.0.4 → 0.6.1-v3.0.5

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.
@@ -20,7 +20,6 @@ const Consts_1 = require("./Consts");
20
20
  const Utils_1 = require("./Utils");
21
21
  const artifacts_1 = require("@tonappchain/artifacts");
22
22
  const errors_1 = require("../errors");
23
- const contractOpener_1 = require("../adapters/contractOpener");
24
23
  const wrappers_1 = require("@tonappchain/artifacts/dist/src/ton/wrappers");
25
24
  const instances_1 = require("../errors/instances");
26
25
  class TacSdk {
@@ -45,7 +44,12 @@ class TacSdk {
45
44
  return new TacSdk(network, delay, artifacts, TONParams, TACParams, liteSequencerEndpoints);
46
45
  }
47
46
  static async prepareTONParams(network, delay, artifacts, TONParams) {
48
- const contractOpener = TONParams?.contractOpener ?? (await (0, contractOpener_1.orbsOpener4)(network));
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
+ });
49
53
  const settingsAddress = TONParams?.settingsAddress ?? artifacts.ton.addresses.TON_SETTINGS_ADDRESS;
50
54
  const settings = contractOpener.open(new Settings_1.Settings(ton_1.Address.parse(settingsAddress)));
51
55
  const jettonProxyAddress = await settings.getAddressSetting('JettonProxyAddress');
@@ -169,24 +173,9 @@ class TacSdk {
169
173
  .endCell();
170
174
  return wrappers_1.NFTItem.transferMessage(queryId, (0, ton_1.address)(transferData.to ?? this.TONParams.nftProxyAddress), (0, ton_1.address)(transferData.responseAddress), Number((0, ton_1.fromNano)(Consts_1.NFT_TRANSFER_FORWARD_TON_AMOUNT + forwardFeeAmount + crossChainTonAmount)), forwardPayload);
171
175
  }
172
- generateFeeData(feeParams) {
173
- if (feeParams) {
174
- let feeDataBuilder = (0, ton_1.beginCell)()
175
- .storeBit(feeParams.isRoundTrip)
176
- .storeCoins(feeParams.protocolFee)
177
- .storeCoins(feeParams.evmExecutorFee);
178
- if (feeParams.isRoundTrip) {
179
- feeDataBuilder.storeCoins(feeParams.tvmExecutorFee);
180
- }
181
- return feeDataBuilder.endCell();
182
- }
183
- else {
184
- return undefined;
185
- }
186
- }
187
176
  getTonTransferPayload(responseAddress, evmData, crossChainTonAmount, feeParams) {
188
177
  const queryId = (0, Utils_1.generateRandomNumberByTimestamp)().randomNumber;
189
- const feeData = this.generateFeeData(feeParams);
178
+ const feeData = (0, Utils_1.generateFeeData)(feeParams);
190
179
  return (0, ton_1.beginCell)()
191
180
  .storeUint(this.artifacts.ton.wrappers.CrossChainLayerOpCodes.anyone_tvmMsgToEVM, 32)
192
181
  .storeUint(queryId, 64)
@@ -288,7 +277,7 @@ class TacSdk {
288
277
  const opType = await this.getJettonOpType(jetton);
289
278
  await (0, Utils_1.sleep)(this.delay * 1000);
290
279
  console.log(`***** Jetton ${jetton.address} requires ${opType} operation`);
291
- const feeData = this.generateFeeData(feeParams);
280
+ const feeData = (0, Utils_1.generateFeeData)(feeParams);
292
281
  let payload;
293
282
  switch (opType) {
294
283
  case InternalStruct_1.AssetOpType.JETTON_BURN:
@@ -307,7 +296,7 @@ class TacSdk {
307
296
  const opType = await this.getNFTOpType(nft);
308
297
  await (0, Utils_1.sleep)(this.delay * 1000);
309
298
  console.log(`***** NFT ${nft.address} requires ${opType} operation`);
310
- const feeData = this.generateFeeData(feeParams);
299
+ const feeData = (0, Utils_1.generateFeeData)(feeParams);
311
300
  let payload;
312
301
  switch (opType) {
313
302
  case InternalStruct_1.AssetOpType.NFT_BURN:
@@ -391,6 +380,7 @@ class TacSdk {
391
380
  (0, Utils_1.validateTVMAddress)(precalculatedAddress);
392
381
  const contract = this.TONParams.contractOpener.open(new JettonMaster_1.JettonMaster((0, ton_1.address)(precalculatedAddress)));
393
382
  const { content } = await contract.getJettonData();
383
+ await (0, Utils_1.sleep)(this.delay * 1000);
394
384
  if (!content.metadata.decimals) {
395
385
  // if decimals not specified use default value 9
396
386
  return (0, ton_1.toNano)(asset.amount);
@@ -414,6 +404,7 @@ class TacSdk {
414
404
  const address = (0, ethers_1.isAddress)(asset.collectionAddress)
415
405
  ? await this.getTVMNFTAddress(asset.collectionAddress, asset.itemIndex)
416
406
  : await this.getNFTItemAddressTON(asset.collectionAddress, asset.itemIndex);
407
+ await (0, Utils_1.sleep)(this.delay * 1000);
417
408
  return {
418
409
  address,
419
410
  rawAmount: 1n,
@@ -491,6 +482,27 @@ class TacSdk {
491
482
  const evmValidExecutors = this.TACParams.trustedTACExecutors;
492
483
  return await this.getFeeInfo(evmProxyMsg, transactionLinker, rawAssets, evmValidExecutors, false, undefined);
493
484
  }
485
+ async getTVMExecutorFeeInfo(assets, feeSymbol) {
486
+ const rawAssets = await this.convertAssetsToRawFormat(assets);
487
+ const requestBody = {
488
+ tonAssets: rawAssets.map((asset) => ({
489
+ amount: asset.rawAmount.toString(),
490
+ tokenAddress: asset.address || '',
491
+ assetType: asset.type,
492
+ })),
493
+ feeSymbol: feeSymbol,
494
+ };
495
+ for (const endpoint of this.liteSequencerEndpoints) {
496
+ try {
497
+ const response = await axios_1.default.post(`${endpoint}/ton/calculator/ton-executor-fee`, requestBody);
498
+ return response.data.response;
499
+ }
500
+ catch (error) {
501
+ console.error(`Error while calulating tvm executor fee ${endpoint}:`, error);
502
+ }
503
+ }
504
+ throw errors_1.simulationError;
505
+ }
494
506
  async prepareCrossChainTransaction(evmProxyMsg, caller, assets, options) {
495
507
  let { forceSend = false, isRoundTrip = undefined, protocolFee = undefined, evmValidExecutors = [], evmExecutorFee = undefined, tvmValidExecutors = [], tvmExecutorFee = undefined, } = options || {};
496
508
  const rawAssets = await this.convertAssetsToRawFormat(assets);
@@ -556,6 +568,34 @@ class TacSdk {
556
568
  if (assets == undefined) {
557
569
  assets = [];
558
570
  }
571
+ let tonAssets = [];
572
+ for (const asset of assets) {
573
+ if (asset.type == Struct_1.AssetType.FT) {
574
+ const tvmAddress = await this.getTVMTokenAddress(asset.address);
575
+ tonAssets.push({
576
+ address: tvmAddress,
577
+ rawAmount: asset.rawAmount,
578
+ type: Struct_1.AssetType.FT,
579
+ });
580
+ }
581
+ else {
582
+ const nftItemAddress = await this.getTVMNFTAddress(asset.collectionAddress, asset.itemIndex);
583
+ tonAssets.push({
584
+ address: nftItemAddress,
585
+ amount: 1,
586
+ type: Struct_1.AssetType.NFT,
587
+ });
588
+ }
589
+ }
590
+ if (value > 0) {
591
+ const tvmAddress = await this.getTVMTokenAddress(await this.nativeTACAddress());
592
+ tonAssets.push({
593
+ address: tvmAddress,
594
+ rawAmount: value,
595
+ type: Struct_1.AssetType.FT,
596
+ });
597
+ }
598
+ const suggestedTONExecutorFee = await this.getTVMExecutorFeeInfo(tonAssets, Consts_1.TAC_SYMBOL);
559
599
  const crossChainLayerAddress = await this.TACParams.crossChainLayer.getAddress();
560
600
  for (const asset of assets) {
561
601
  if (asset.type == Struct_1.AssetType.FT) {
@@ -571,27 +611,12 @@ class TacSdk {
571
611
  }
572
612
  const shardsKey = BigInt(Math.round(Math.random() * 1e18));
573
613
  const protocolFee = await this.TACParams.crossChainLayer.getProtocolFee();
574
- let tvmExecutorFeeInTON = 0n;
575
- if (tvmExecutorFee != undefined) {
576
- tvmExecutorFeeInTON = tvmExecutorFee;
577
- }
578
- else {
579
- tvmExecutorFeeInTON =
580
- ((((0, ton_1.toNano)('0.065') + (0, ton_1.toNano)('0.05')) * BigInt(assets.length + 1 + Number(value != 0n)) +
581
- (0, ton_1.toNano)('0.2')) *
582
- 120n) /
583
- 100n; // TODO calc that
584
- }
585
- const tonToTacRate = 100n;
586
- const scale = 10n ** 9n;
587
- const tonToTacRateScaled = tonToTacRate * scale;
588
- const tvmExecutorFeeInTAC = tonToTacRateScaled * tvmExecutorFeeInTON;
589
614
  const outMessage = {
590
615
  shardsKey: shardsKey,
591
616
  tvmTarget: tonTarget,
592
617
  tvmPayload: '',
593
618
  tvmProtocolFee: protocolFee,
594
- tvmExecutorFee: tvmExecutorFeeInTAC,
619
+ tvmExecutorFee: tvmExecutorFee ?? BigInt(suggestedTONExecutorFee.inTAC),
595
620
  tvmValidExecutors: this.TACParams.trustedTONExecutors,
596
621
  toBridge: assets
597
622
  .filter((asset) => asset.type === Struct_1.AssetType.FT)
@@ -690,7 +715,7 @@ class TacSdk {
690
715
  await (0, Utils_1.sleep)(this.delay * 1000);
691
716
  return evmAddress.toString();
692
717
  }
693
- return this.TACParams.tokenUtils.computeAddress(tvmNFTAddress);
718
+ return this.TACParams.tokenUtils.computeAddressERC721(tvmNFTAddress);
694
719
  }
695
720
  async isContractDeployedOnTVM(address) {
696
721
  return (await this.TONParams.contractOpener.getContractState(ton_1.Address.parse(address))).state === 'active';
@@ -698,7 +723,7 @@ class TacSdk {
698
723
  async simulateTACMessage(req) {
699
724
  for (const endpoint of this.liteSequencerEndpoints) {
700
725
  try {
701
- const response = await axios_1.default.post(`${endpoint}/tac/simulator/simulate-message`, req, {
726
+ const response = await axios_1.default.post(new URL('tac/simulator/simulate-message', endpoint).toString(), req, {
702
727
  transformResponse: [Utils_1.toCamelCaseTransformer],
703
728
  });
704
729
  return response.data.response;
@@ -1,6 +1,6 @@
1
1
  import { Address, Cell } from '@ton/ton';
2
2
  import { AbiCoder } from 'ethers';
3
- import { EvmProxyMsg, TransactionLinker, ValidExecutors } from '../structs/Struct';
3
+ import { EvmProxyMsg, FeeParams, TransactionLinker, ValidExecutors } from '../structs/Struct';
4
4
  import { RandomNumberByTimestamp } from '../structs/InternalStruct';
5
5
  export declare const sleep: (ms: number) => Promise<unknown>;
6
6
  export declare function generateRandomNumber(interval: number): number;
@@ -16,3 +16,4 @@ 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
18
  export declare const toCamelCaseTransformer: (data: any) => any;
19
+ export declare const generateFeeData: (feeParams?: FeeParams) => Cell | undefined;
package/dist/sdk/Utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toCamelCaseTransformer = exports.calculateAmount = exports.calculateRawAmount = exports.convertKeysToCamelCase = exports.sleep = void 0;
3
+ exports.generateFeeData = exports.toCamelCaseTransformer = exports.calculateAmount = exports.calculateRawAmount = exports.convertKeysToCamelCase = exports.sleep = void 0;
4
4
  exports.generateRandomNumber = generateRandomNumber;
5
5
  exports.generateRandomNumberByTimestamp = generateRandomNumberByTimestamp;
6
6
  exports.calculateContractAddress = calculateContractAddress;
@@ -126,3 +126,19 @@ const toCamelCaseTransformer = (data) => {
126
126
  }
127
127
  };
128
128
  exports.toCamelCaseTransformer = toCamelCaseTransformer;
129
+ const generateFeeData = (feeParams) => {
130
+ if (feeParams) {
131
+ let feeDataBuilder = (0, ton_1.beginCell)()
132
+ .storeBit(feeParams.isRoundTrip)
133
+ .storeCoins(feeParams.protocolFee)
134
+ .storeCoins(feeParams.evmExecutorFee);
135
+ if (feeParams.isRoundTrip) {
136
+ feeDataBuilder.storeCoins(feeParams.tvmExecutorFee);
137
+ }
138
+ return feeDataBuilder.endCell();
139
+ }
140
+ else {
141
+ return undefined;
142
+ }
143
+ };
144
+ exports.generateFeeData = generateFeeData;
@@ -0,0 +1,15 @@
1
+ import type { ContractOpener } from '../structs/Struct';
2
+ import type { SendResult, ShardTransaction } from '../structs/InternalStruct';
3
+ import { Network } from '../structs/Struct';
4
+ import { SenderAbstraction } from './SenderAbstraction';
5
+ import { HighloadWalletV3 } from '../wrappers/HighloadWalletV3';
6
+ export declare class BatchSender implements SenderAbstraction {
7
+ private wallet;
8
+ private secretKey;
9
+ constructor(wallet: HighloadWalletV3, secretKey: Buffer);
10
+ sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, _chain: Network, contractOpener: ContractOpener): Promise<SendResult[]>;
11
+ private prepareGroups;
12
+ private sendGroup;
13
+ getSenderAddress(): string;
14
+ sendShardTransaction(shardTransaction: ShardTransaction, delay: number, _chain: Network, contractOpener: ContractOpener): Promise<SendResult>;
15
+ }
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BatchSender = void 0;
4
+ const ton_1 = require("@ton/ton");
5
+ const SenderAbstraction_1 = require("./SenderAbstraction");
6
+ const Consts_1 = require("../sdk/Consts");
7
+ const instances_1 = require("../errors/instances");
8
+ class BatchSender {
9
+ constructor(wallet, secretKey) {
10
+ this.wallet = wallet;
11
+ this.secretKey = secretKey;
12
+ }
13
+ async sendShardTransactions(shardTransactions, delay, _chain, contractOpener) {
14
+ const allMessages = [];
15
+ let minValidUntil = Number.MAX_SAFE_INTEGER;
16
+ for (const transaction of shardTransactions) {
17
+ for (const message of transaction.messages) {
18
+ allMessages.push((0, ton_1.internal)({
19
+ to: message.address,
20
+ value: (0, ton_1.fromNano)(message.value),
21
+ bounce: true,
22
+ body: message.payload,
23
+ }));
24
+ }
25
+ minValidUntil = Math.min(minValidUntil, transaction.validUntil);
26
+ }
27
+ const groups = await this.prepareGroups(allMessages);
28
+ const results = [];
29
+ let currentMessageIndex = 0;
30
+ for (const group of groups) {
31
+ await (0, SenderAbstraction_1.sleep)(delay * 1000);
32
+ try {
33
+ const result = await this.sendGroup(group, contractOpener);
34
+ results.push({
35
+ success: true,
36
+ result,
37
+ lastMessageIndex: currentMessageIndex + group.length - 1,
38
+ });
39
+ }
40
+ catch (error) {
41
+ results.push({
42
+ success: false,
43
+ error: error,
44
+ lastMessageIndex: currentMessageIndex - 1,
45
+ });
46
+ break; // Stop sending after first error
47
+ }
48
+ currentMessageIndex += group.length;
49
+ }
50
+ return results;
51
+ }
52
+ async prepareGroups(messages) {
53
+ const total = messages.length;
54
+ let left = 0;
55
+ const groups = [];
56
+ while (left < total) {
57
+ let groupSize = total - left;
58
+ if (groupSize > Consts_1.MAX_HIGHLOAD_GROUP_MSG_NUM) {
59
+ groupSize = Consts_1.MAX_HIGHLOAD_GROUP_MSG_NUM;
60
+ }
61
+ let validGroupFound = false;
62
+ while (groupSize > 0) {
63
+ const group = messages.slice(left, left + groupSize);
64
+ const createdAt = Math.floor(Date.now() / 1000) - 40;
65
+ const queryId = this.wallet.getQueryIdFromCreatedAt(createdAt);
66
+ const externalMsg = this.wallet.getExternalMessage(group, ton_1.SendMode.PAY_GAS_SEPARATELY, 0n, queryId);
67
+ const isBocSizeValid = externalMsg.body.toBoc().length <= Consts_1.MAX_EXT_MSG_SIZE;
68
+ const isDepthValid = externalMsg.body.depth() <= Consts_1.MAX_MSG_DEPTH;
69
+ if (isBocSizeValid && isDepthValid) {
70
+ groups.push(group);
71
+ left += groupSize;
72
+ validGroupFound = true;
73
+ break;
74
+ }
75
+ if (groupSize <= 1) {
76
+ throw (0, instances_1.prepareMessageGroupError)(isBocSizeValid, isDepthValid);
77
+ }
78
+ groupSize = Math.floor(groupSize / 2);
79
+ }
80
+ if (!validGroupFound) {
81
+ throw instances_1.noValidGroupFoundError;
82
+ }
83
+ }
84
+ return groups;
85
+ }
86
+ async sendGroup(messages, contractOpener) {
87
+ const walletContract = contractOpener.open(this.wallet);
88
+ return walletContract.sendTransfer({
89
+ secretKey: this.secretKey,
90
+ messages,
91
+ sendMode: ton_1.SendMode.PAY_GAS_SEPARATELY,
92
+ });
93
+ }
94
+ getSenderAddress() {
95
+ return this.wallet.address.toString();
96
+ }
97
+ async sendShardTransaction(shardTransaction, delay, _chain, contractOpener) {
98
+ const messages = [];
99
+ for (const message of shardTransaction.messages) {
100
+ messages.push((0, ton_1.internal)({
101
+ to: message.address,
102
+ value: (0, ton_1.fromNano)(message.value),
103
+ bounce: true,
104
+ body: message.payload,
105
+ }));
106
+ }
107
+ await (0, SenderAbstraction_1.sleep)(delay * 1000);
108
+ const result = await this.sendGroup(messages, contractOpener);
109
+ return {
110
+ success: true,
111
+ result,
112
+ lastMessageIndex: shardTransaction.messages.length - 1,
113
+ };
114
+ }
115
+ }
116
+ exports.BatchSender = BatchSender;
@@ -1,14 +1,12 @@
1
1
  import type { ContractOpener } from '../structs/Struct';
2
- import type { ShardTransaction } from '../structs/InternalStruct';
2
+ import type { SendResult, ShardTransaction } from '../structs/InternalStruct';
3
3
  import { Network } from '../structs/Struct';
4
4
  import { SenderAbstraction, WalletInstance } from './SenderAbstraction';
5
5
  export declare class RawSender implements SenderAbstraction {
6
6
  private wallet;
7
7
  private secretKey;
8
8
  constructor(wallet: WalletInstance, secretKey: Buffer);
9
- sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, chain: Network, contractOpener: ContractOpener): Promise<unknown>;
9
+ sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, chain: Network, contractOpener: ContractOpener): Promise<SendResult[]>;
10
10
  getSenderAddress(): string;
11
- sendShardTransaction(shardTransaction: ShardTransaction, delay: number, _chain: Network, contractOpener: ContractOpener): Promise<void | (import("@ton/sandbox").SendMessageResult & {
12
- result: void;
13
- })>;
11
+ sendShardTransaction(shardTransaction: ShardTransaction, delay: number, _chain: Network, contractOpener: ContractOpener): Promise<SendResult>;
14
12
  }
@@ -4,43 +4,34 @@ exports.RawSender = void 0;
4
4
  const ton_1 = require("@ton/ton");
5
5
  const ton_2 = require("@ton/ton");
6
6
  const SenderAbstraction_1 = require("./SenderAbstraction");
7
- const HighloadWalletV3_1 = require("../wrappers/HighloadWalletV3");
8
7
  class RawSender {
9
8
  constructor(wallet, secretKey) {
10
9
  this.wallet = wallet;
11
10
  this.secretKey = secretKey;
12
11
  }
13
12
  async sendShardTransactions(shardTransactions, delay, chain, contractOpener) {
14
- const walletContract = contractOpener.open(this.wallet);
15
- const isBatchSendSupported = walletContract instanceof HighloadWalletV3_1.HighloadWalletV3 || walletContract instanceof ton_1.WalletContractV5R1;
16
- if (isBatchSendSupported) {
17
- const messages = [];
18
- for (const shardTx of shardTransactions) {
19
- for (const message of shardTx.messages) {
20
- messages.push((0, ton_1.internal)({
21
- to: message.address,
22
- value: (0, ton_1.fromNano)(message.value),
23
- bounce: true,
24
- body: message.payload,
25
- }));
26
- }
13
+ const results = [];
14
+ let currentMessageIndex = 0;
15
+ for (const shardTx of shardTransactions) {
16
+ try {
17
+ const result = await this.sendShardTransaction(shardTx, delay, chain, contractOpener);
18
+ results.push({
19
+ success: true,
20
+ result,
21
+ lastMessageIndex: currentMessageIndex + shardTx.messages.length - 1,
22
+ });
23
+ currentMessageIndex += shardTx.messages.length;
27
24
  }
28
- const seqno = await walletContract.getSeqno();
29
- await (0, SenderAbstraction_1.sleep)(delay * 1000);
30
- return walletContract.sendTransfer({
31
- seqno,
32
- secretKey: this.secretKey,
33
- messages,
34
- sendMode: ton_2.SendMode.PAY_GAS_SEPARATELY,
35
- });
36
- }
37
- else {
38
- const results = [];
39
- for (const shardTx of shardTransactions) {
40
- results.push(await this.sendShardTransaction(shardTx, delay, chain, contractOpener));
25
+ catch (error) {
26
+ results.push({
27
+ success: false,
28
+ error: error,
29
+ lastMessageIndex: currentMessageIndex - 1,
30
+ });
31
+ break; // Stop sending after first error
41
32
  }
42
- return results;
43
33
  }
34
+ return results;
44
35
  }
45
36
  getSenderAddress() {
46
37
  return this.wallet.address.toString();
@@ -59,12 +50,17 @@ class RawSender {
59
50
  }));
60
51
  }
61
52
  await (0, SenderAbstraction_1.sleep)(delay * 1000);
62
- return walletContract.sendTransfer({
53
+ const result = await walletContract.sendTransfer({
63
54
  seqno,
64
55
  secretKey: this.secretKey,
65
56
  messages,
66
57
  sendMode: ton_2.SendMode.PAY_GAS_SEPARATELY,
67
58
  });
59
+ return {
60
+ success: true,
61
+ result,
62
+ lastMessageIndex: shardTransaction.messages.length - 1,
63
+ };
68
64
  }
69
65
  }
70
66
  exports.RawSender = RawSender;
@@ -1,6 +1,6 @@
1
1
  import type { Contract, ContractProvider, MessageRelaxed, SendMode } from '@ton/ton';
2
2
  import type { ContractOpener } from '../structs/Struct';
3
- import type { ShardTransaction } from '../structs/InternalStruct';
3
+ import type { SendResult, ShardTransaction } from '../structs/InternalStruct';
4
4
  import { Network } from '../structs/Struct';
5
5
  export declare const sleep: (ms: number) => Promise<unknown>;
6
6
  export interface WalletInstance extends Contract {
@@ -14,7 +14,7 @@ export interface WalletInstance extends Contract {
14
14
  }): Promise<void>;
15
15
  }
16
16
  export interface SenderAbstraction {
17
- sendShardTransaction(shardTransaction: ShardTransaction, delay: number, chain?: Network, contractOpener?: ContractOpener): Promise<unknown>;
18
- sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, chain?: Network, contractOpener?: ContractOpener): Promise<unknown>;
17
+ sendShardTransaction(shardTransaction: ShardTransaction, delay: number, chain?: Network, contractOpener?: ContractOpener): Promise<SendResult>;
18
+ sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, chain?: Network, contractOpener?: ContractOpener): Promise<SendResult[]>;
19
19
  getSenderAddress(): string;
20
20
  }
@@ -5,6 +5,7 @@ const ton_1 = require("@ton/ton");
5
5
  const ton_crypto_1 = require("ton-crypto");
6
6
  const RawSender_1 = require("./RawSender");
7
7
  const TonConnectSender_1 = require("./TonConnectSender");
8
+ const BatchSender_1 = require("./BatchSender");
8
9
  const errors_1 = require("../errors");
9
10
  const Struct_1 = require("../structs/Struct");
10
11
  const HighloadWalletV3_1 = require("../wrappers/HighloadWalletV3");
@@ -49,6 +50,9 @@ class SenderFactory {
49
50
  config.timeout = params.options?.highloadV3?.timeout ?? HighloadWalletV3_1.DEFAULT_TIMEOUT;
50
51
  }
51
52
  const wallet = exports.wallets[params.version].create(config);
53
+ if (params.version === 'HIGHLOAD_V3') {
54
+ return new BatchSender_1.BatchSender(wallet, keypair.secretKey);
55
+ }
52
56
  return new RawSender_1.RawSender(wallet, keypair.secretKey);
53
57
  }
54
58
  }
@@ -1,12 +1,12 @@
1
1
  import { TonConnectUI } from '@tonconnect/ui';
2
- import type { ShardTransaction } from '../structs/InternalStruct';
2
+ import type { SendResult, ShardTransaction } from '../structs/InternalStruct';
3
3
  import { ContractOpener, Network } from '../structs/Struct';
4
4
  import { SenderAbstraction } from './SenderAbstraction';
5
- import { SendTransactionResponse } from '@tonconnect/sdk';
6
5
  export declare class TonConnectSender implements SenderAbstraction {
7
6
  readonly tonConnect: TonConnectUI;
8
7
  constructor(tonConnect: TonConnectUI);
9
- sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, chain?: Network, contractOpener?: ContractOpener): Promise<SendTransactionResponse[]>;
8
+ private sendChunkedMessages;
9
+ sendShardTransactions(shardTransactions: ShardTransaction[], delay: number, chain: Network, _contractOpener?: ContractOpener): Promise<SendResult[]>;
10
10
  getSenderAddress(): string;
11
- sendShardTransaction(shardTransaction: ShardTransaction, delay: number, chain: Network): Promise<SendTransactionResponse>;
11
+ sendShardTransaction(shardTransaction: ShardTransaction, delay: number, chain: Network): Promise<SendResult>;
12
12
  }
@@ -5,13 +5,51 @@ const protocol_1 = require("@tonconnect/protocol");
5
5
  const ui_1 = require("@tonconnect/ui");
6
6
  const Struct_1 = require("../structs/Struct");
7
7
  const SenderAbstraction_1 = require("./SenderAbstraction");
8
+ const CHUNK_SIZE = 4;
8
9
  class TonConnectSender {
9
10
  constructor(tonConnect) {
10
11
  this.tonConnect = tonConnect;
11
12
  }
12
- async sendShardTransactions(shardTransactions, delay, chain, contractOpener) {
13
+ async sendChunkedMessages(messages, validUntil, chain) {
14
+ const responses = [];
15
+ let currentMessageIndex = 0;
16
+ const chunkSize =
17
+ //@ts-ignore // 'find' checks that maxMessages is a property of the feature
18
+ this.tonConnect.wallet?.device.features.find((feat) => feat.hasOwnProperty('maxMessages'))?.maxMessages ||
19
+ CHUNK_SIZE;
20
+ for (let i = 0; i < messages.length; i += chunkSize) {
21
+ const chunk = messages.slice(i, i + chunkSize);
22
+ const transaction = {
23
+ validUntil,
24
+ messages: chunk,
25
+ network: chain == Struct_1.Network.TESTNET ? ui_1.CHAIN.TESTNET : ui_1.CHAIN.MAINNET,
26
+ };
27
+ try {
28
+ const response = await this.tonConnect.sendTransaction(transaction);
29
+ responses.push({
30
+ success: true,
31
+ result: response,
32
+ lastMessageIndex: currentMessageIndex + chunk.length - 1,
33
+ });
34
+ currentMessageIndex += chunk.length;
35
+ }
36
+ catch (error) {
37
+ responses.push({
38
+ success: false,
39
+ error: error,
40
+ lastMessageIndex: currentMessageIndex - 1,
41
+ });
42
+ break; // Stop sending after first error
43
+ }
44
+ if (i + chunkSize < messages.length) {
45
+ await (0, SenderAbstraction_1.sleep)(1000);
46
+ }
47
+ }
48
+ return responses;
49
+ }
50
+ async sendShardTransactions(shardTransactions, delay, chain, _contractOpener) {
13
51
  const allMessages = [];
14
- let minValidUntil = 0;
52
+ let minValidUntil = Number.MAX_SAFE_INTEGER;
15
53
  for (const transaction of shardTransactions) {
16
54
  for (const message of transaction.messages) {
17
55
  allMessages.push({
@@ -22,14 +60,8 @@ class TonConnectSender {
22
60
  }
23
61
  minValidUntil = Math.min(minValidUntil, transaction.validUntil);
24
62
  }
25
- const transaction = {
26
- validUntil: minValidUntil,
27
- messages: allMessages,
28
- network: chain == Struct_1.Network.TESTNET ? ui_1.CHAIN.TESTNET : ui_1.CHAIN.MAINNET,
29
- };
30
63
  await (0, SenderAbstraction_1.sleep)(delay * 1000);
31
- const response = await this.tonConnect.sendTransaction(transaction);
32
- return [response];
64
+ return this.sendChunkedMessages(allMessages, minValidUntil, chain);
33
65
  }
34
66
  getSenderAddress() {
35
67
  return this.tonConnect.account?.address?.toString() || '';
@@ -43,13 +75,9 @@ class TonConnectSender {
43
75
  payload: protocol_1.Base64.encode(message.payload.toBoc()).toString(),
44
76
  });
45
77
  }
46
- const transaction = {
47
- validUntil: shardTransaction.validUntil,
48
- messages,
49
- network: chain == Struct_1.Network.TESTNET ? ui_1.CHAIN.TESTNET : ui_1.CHAIN.MAINNET,
50
- };
51
78
  await (0, SenderAbstraction_1.sleep)(delay * 1000);
52
- return this.tonConnect.sendTransaction(transaction);
79
+ const responses = await this.sendChunkedMessages(messages, shardTransaction.validUntil, chain);
80
+ return responses[0];
53
81
  }
54
82
  }
55
83
  exports.TonConnectSender = TonConnectSender;
@@ -1,2 +1,3 @@
1
1
  export * from './SenderAbstraction';
2
2
  export * from './SenderFactory';
3
+ export * from './BatchSender';
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./SenderAbstraction"), exports);
18
18
  __exportStar(require("./SenderFactory"), exports);
19
+ __exportStar(require("./BatchSender"), exports);
@@ -1,5 +1,5 @@
1
1
  import { Cell } from '@ton/ton';
2
- import { ContractOpener, TACSimulationResult, ExecutionStagesByOperationId, Network, OperationIdsByShardsKey, RawAssetBridgingData, StatusInfosByOperationId, OperationType, AssetType } from './Struct';
2
+ import { ContractOpener, TACSimulationResult, ExecutionStagesByOperationId, Network, OperationIdsByShardsKey, RawAssetBridgingData, StatusInfosByOperationId, OperationType, AssetType, SuggestedTONExecutorFee } from './Struct';
3
3
  import { AbstractProvider, ethers, Interface, InterfaceAbi } from 'ethers';
4
4
  import { mainnet, testnet } from '@tonappchain/artifacts';
5
5
  export type ShardMessage = {
@@ -80,3 +80,10 @@ export type StatusesResponse = ResponseBase<StatusInfosByOperationId>;
80
80
  export type OperationIdsByShardsKeyResponse = ResponseBase<OperationIdsByShardsKey>;
81
81
  export type StageProfilingResponse = ResponseBase<ExecutionStagesByOperationId>;
82
82
  export type TACSimulationResponse = ResponseBase<TACSimulationResult>;
83
+ export type SuggestedTONExecutorFeeResponse = ResponseBase<SuggestedTONExecutorFee>;
84
+ export interface SendResult {
85
+ success: boolean;
86
+ result?: unknown;
87
+ error?: Error;
88
+ lastMessageIndex?: number;
89
+ }