@tonappchain/sdk 0.7.2 → 0.7.3-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +203 -199
  3. package/dist/src/adapters/BaseContractOpener.js +8 -5
  4. package/dist/src/assets/AssetFactory.d.ts +4 -1
  5. package/dist/src/assets/AssetFactory.js +4 -0
  6. package/dist/src/assets/FT.d.ts +3 -3
  7. package/dist/src/assets/FT.js +28 -15
  8. package/dist/src/assets/NFT.d.ts +3 -3
  9. package/dist/src/assets/NFT.js +10 -4
  10. package/dist/src/assets/TAC.d.ts +24 -0
  11. package/dist/src/assets/TAC.js +74 -0
  12. package/dist/src/assets/TON.d.ts +3 -3
  13. package/dist/src/assets/TON.js +12 -5
  14. package/dist/src/assets/index.d.ts +1 -0
  15. package/dist/src/assets/index.js +3 -1
  16. package/dist/src/errors/index.d.ts +1 -1
  17. package/dist/src/errors/index.js +6 -1
  18. package/dist/src/errors/instances.d.ts +4 -0
  19. package/dist/src/errors/instances.js +7 -1
  20. package/dist/src/interfaces/Asset.d.ts +11 -6
  21. package/dist/src/interfaces/IConfiguration.d.ts +1 -3
  22. package/dist/src/interfaces/ILiteSequencerClient.d.ts +9 -1
  23. package/dist/src/interfaces/IOperationTracker.d.ts +20 -1
  24. package/dist/src/interfaces/ITACTransactionManager.d.ts +19 -1
  25. package/dist/src/interfaces/ITacSDK.d.ts +29 -8
  26. package/dist/src/sdk/Consts.d.ts +4 -0
  27. package/dist/src/sdk/Consts.js +5 -1
  28. package/dist/src/sdk/LiteSequencerClient.d.ts +3 -1
  29. package/dist/src/sdk/LiteSequencerClient.js +37 -0
  30. package/dist/src/sdk/OperationTracker.d.ts +4 -1
  31. package/dist/src/sdk/OperationTracker.js +58 -0
  32. package/dist/src/sdk/TACTransactionManager.d.ts +3 -0
  33. package/dist/src/sdk/TACTransactionManager.js +170 -34
  34. package/dist/src/sdk/TONTransactionManager.js +28 -6
  35. package/dist/src/sdk/TacSdk.d.ts +4 -3
  36. package/dist/src/sdk/TacSdk.js +4 -0
  37. package/dist/src/sdk/Utils.d.ts +2 -1
  38. package/dist/src/sdk/Utils.js +4 -0
  39. package/dist/src/structs/InternalStruct.d.ts +35 -1
  40. package/dist/src/structs/Struct.d.ts +155 -5
  41. package/dist/src/structs/Struct.js +12 -1
  42. package/dist/src/wrappers/ContentUtils.d.ts +36 -13
  43. package/dist/src/wrappers/ContentUtils.js +197 -98
  44. package/package.json +121 -121
@@ -55,6 +55,22 @@ class LiteSequencerClient {
55
55
  throw (0, errors_1.operationFetchError)(`request ${requestLabel} failed to complete request`, error);
56
56
  }
57
57
  }
58
+ async getOperationTypeV2(operationId) {
59
+ const path = 'v2/operation-type';
60
+ const requestLabel = this.getRequestLabel('GET', path);
61
+ try {
62
+ const response = await this.httpClient.get(new URL(path, this.endpoint).toString(), {
63
+ params: {
64
+ operationId,
65
+ },
66
+ transformResponse: [Utils_1.toCamelCaseTransformer],
67
+ });
68
+ return response.data.response;
69
+ }
70
+ catch (error) {
71
+ throw (0, errors_1.operationFetchError)(`request ${requestLabel} failed to complete request`, error);
72
+ }
73
+ }
58
74
  async getOperationId(transactionLinker) {
59
75
  const path = 'ton/operation-id';
60
76
  const requestLabel = this.getRequestLabel('POST', path);
@@ -117,6 +133,27 @@ class LiteSequencerClient {
117
133
  throw (0, errors_1.profilingFetchError)(`request ${requestLabel} failed to complete request`, error);
118
134
  }
119
135
  }
136
+ async getStageProfilingsV2(operationIds, chunkSize = this.maxChunkSize) {
137
+ const path = 'v2/stage-profiling';
138
+ const requestLabel = this.getRequestLabel('POST', path);
139
+ if (!operationIds || operationIds.length === 0) {
140
+ throw (0, errors_1.emptyArrayError)('operationIds');
141
+ }
142
+ try {
143
+ const response = await this.processChunkedRequest(operationIds, async (chunk) => {
144
+ const response = await this.httpClient.post(new URL(path, this.endpoint).toString(), {
145
+ operationIds: chunk,
146
+ }, {
147
+ transformResponse: [Utils_1.toCamelCaseTransformer],
148
+ });
149
+ return response.data;
150
+ }, chunkSize);
151
+ return response.response;
152
+ }
153
+ catch (error) {
154
+ throw (0, errors_1.profilingFetchError)(`request ${requestLabel} failed to complete request`, error);
155
+ }
156
+ }
120
157
  async getOperationStatuses(operationIds, chunkSize = this.maxChunkSize) {
121
158
  const path = 'status';
122
159
  const requestLabel = this.getRequestLabel('POST', path);
@@ -1,5 +1,5 @@
1
1
  import { ILiteSequencerClient, ILiteSequencerClientFactory, ILogger, IOperationTracker } from '../interfaces';
2
- import { ConvertCurrencyParams, ConvertedCurrencyResult, ExecutionStages, ExecutionStagesByOperationId, GetTVMExecutorFeeParams, Network, OperationIdsByShardsKey, OperationType, SimplifiedStatuses, StatusInfo, StatusInfosByOperationId, SuggestedTVMExecutorFee, TACSimulationParams, TACSimulationResult, TransactionLinker, WaitOptions } from '../structs/Struct';
2
+ import { ConvertCurrencyParams, ConvertedCurrencyResult, ExecutionStages, ExecutionStagesByOperationId, ExecutionStagesV2, ExecutionStagesV2ByOperationId, GetTVMExecutorFeeParams, Network, OperationIdsByShardsKey, OperationType, OperationTypeV2Info, SimplifiedStatuses, StatusInfo, StatusInfosByOperationId, SuggestedTVMExecutorFee, TACSimulationParams, TACSimulationResult, TransactionLinker, WaitOptions } from '../structs/Struct';
3
3
  export declare class DefaultLiteSequencerClientFactory implements ILiteSequencerClientFactory {
4
4
  createClients(endpoints: string[]): ILiteSequencerClient[];
5
5
  }
@@ -9,10 +9,13 @@ export declare class OperationTracker implements IOperationTracker {
9
9
  constructor(network: Network, customLiteSequencerEndpoints?: string[], logger?: ILogger, clientFactory?: ILiteSequencerClientFactory);
10
10
  getOperationIdByTransactionHash(transactionHash: string, waitOptions?: WaitOptions<string> | null): Promise<string>;
11
11
  getOperationType(operationId: string, waitOptions?: WaitOptions<OperationType> | null): Promise<OperationType>;
12
+ getOperationTypeV2(operationId: string, waitOptions?: WaitOptions<OperationTypeV2Info> | null): Promise<OperationTypeV2Info>;
12
13
  getOperationId(transactionLinker: TransactionLinker, waitOptions?: WaitOptions<string> | null): Promise<string>;
13
14
  getOperationIdsByShardsKeys(shardsKeys: string[], caller: string, waitOptions?: WaitOptions<OperationIdsByShardsKey> | null, chunkSize?: number): Promise<OperationIdsByShardsKey>;
14
15
  getStageProfiling(operationId: string, waitOptions?: WaitOptions<ExecutionStages> | null): Promise<ExecutionStages>;
15
16
  getStageProfilings(operationIds: string[], waitOptions?: WaitOptions<ExecutionStagesByOperationId> | null, chunkSize?: number): Promise<ExecutionStagesByOperationId>;
17
+ getStageProfilingV2(operationId: string, waitOptions?: WaitOptions<ExecutionStagesV2> | null): Promise<ExecutionStagesV2>;
18
+ getStageProfilingsV2(operationIds: string[], waitOptions?: WaitOptions<ExecutionStagesV2ByOperationId> | null, chunkSize?: number): Promise<ExecutionStagesV2ByOperationId>;
16
19
  getOperationStatuses(operationIds: string[], waitOptions?: WaitOptions<StatusInfosByOperationId> | null, chunkSize?: number): Promise<StatusInfosByOperationId>;
17
20
  getOperationStatus(operationId: string, waitOptions?: WaitOptions<StatusInfo> | null): Promise<StatusInfo>;
18
21
  getSimplifiedOperationStatus(transactionLinker: TransactionLinker): Promise<SimplifiedStatuses>;
@@ -70,6 +70,24 @@ class OperationTracker {
70
70
  ? await requestFn()
71
71
  : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting operation type for ${(0, Utils_1.formatObjectForLogging)(operationId)}`);
72
72
  }
73
+ async getOperationTypeV2(operationId, waitOptions) {
74
+ const requestFn = async () => {
75
+ let lastError;
76
+ for (const client of this.clients) {
77
+ try {
78
+ const type = await client.getOperationTypeV2(operationId);
79
+ return type;
80
+ }
81
+ catch (error) {
82
+ lastError = error;
83
+ }
84
+ }
85
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
86
+ };
87
+ return waitOptions === null
88
+ ? await requestFn()
89
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting operation type v2 for ${(0, Utils_1.formatObjectForLogging)(operationId)}`);
90
+ }
73
91
  async getOperationId(transactionLinker, waitOptions) {
74
92
  const requestFn = async () => {
75
93
  let lastError;
@@ -146,6 +164,46 @@ class OperationTracker {
146
164
  ? await requestFn()
147
165
  : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting stage profilings for operations: ${operationIds.join(', ')} chunkSize=${chunkSize}`);
148
166
  }
167
+ async getStageProfilingV2(operationId, waitOptions) {
168
+ const requestFn = async () => {
169
+ let lastError;
170
+ for (const client of this.clients) {
171
+ try {
172
+ const map = await client.getStageProfilingsV2([operationId]);
173
+ const result = map[operationId];
174
+ if (!result) {
175
+ throw new Error(`No stageProfiling v2 data for operationId=${operationId}`);
176
+ }
177
+ return result;
178
+ }
179
+ catch (error) {
180
+ lastError = error;
181
+ }
182
+ }
183
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
184
+ };
185
+ return waitOptions === null
186
+ ? await requestFn()
187
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting stage profiling v2 for operation ${operationId}`);
188
+ }
189
+ async getStageProfilingsV2(operationIds, waitOptions, chunkSize = 100) {
190
+ const requestFn = async () => {
191
+ let lastError;
192
+ for (const client of this.clients) {
193
+ try {
194
+ const result = await client.getStageProfilingsV2(operationIds, chunkSize);
195
+ return result;
196
+ }
197
+ catch (error) {
198
+ lastError = error;
199
+ }
200
+ }
201
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
202
+ };
203
+ return waitOptions === null
204
+ ? await requestFn()
205
+ : await (0, Utils_1.waitUntilSuccess)({ logger: this.logger, ...waitOptions }, requestFn, `OperationTracker: Getting stage profilings v2 for operations: ${operationIds.join(', ')} chunkSize=${chunkSize}`);
206
+ }
149
207
  async getOperationStatuses(operationIds, waitOptions, chunkSize = 100) {
150
208
  const requestFn = async () => {
151
209
  let lastError;
@@ -1,10 +1,13 @@
1
1
  import { Wallet } from 'ethers';
2
2
  import { Asset, IConfiguration, ILogger, IOperationTracker, ITACTransactionManager } from '../interfaces';
3
+ import { BridgeTokensToTONOptions, TACCrossChainTransactionResult } from '../structs/Struct';
3
4
  export declare class TACTransactionManager implements ITACTransactionManager {
4
5
  private readonly config;
5
6
  private readonly operationTracker;
6
7
  private readonly logger;
7
8
  constructor(config: IConfiguration, operationTracker: IOperationTracker, logger?: ILogger);
9
+ private prepareBridgeTokensToTON;
8
10
  private approveAsset;
11
+ sendCrossChainTransactionToTON(signer: Wallet, tonTarget: string, assets?: Asset[], options?: BridgeTokensToTONOptions): Promise<TACCrossChainTransactionResult>;
9
12
  bridgeTokensToTON(signer: Wallet, value: bigint, tonTarget: string, assets?: Asset[], tvmExecutorFee?: bigint, tvmValidExecutors?: string[]): Promise<string>;
10
13
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TACTransactionManager = void 0;
4
4
  const ethers_1 = require("ethers");
5
5
  const assets_1 = require("../assets");
6
+ const errors_1 = require("../errors");
6
7
  const Struct_1 = require("../structs/Struct");
7
8
  const Consts_1 = require("./Consts");
8
9
  const Logger_1 = require("./Logger");
@@ -14,28 +15,10 @@ class TACTransactionManager {
14
15
  this.operationTracker = operationTracker;
15
16
  this.logger = logger;
16
17
  }
17
- async approveAsset(asset, signer, spenderAddress) {
18
- const evmAddress = await asset.getEVMAddress();
19
- if (asset.type === Struct_1.AssetType.FT) {
20
- this.logger.debug(`Approving FT ${evmAddress} for ${spenderAddress}`);
21
- const erc20Abi = this.config.artifacts.tac.compilationArtifacts.IERC20WithDecimals.abi;
22
- const contract = new ethers_1.ethers.Contract(evmAddress, erc20Abi, this.config.TACParams.provider);
23
- const tx = await contract.connect(signer).approve(spenderAddress, asset.rawAmount);
24
- await tx.wait();
25
- }
26
- else if (asset.type === Struct_1.AssetType.NFT) {
27
- this.logger.debug(`Approving NFT ${evmAddress} for ${spenderAddress}`);
28
- const erc721Abi = this.config.artifacts.tac.compilationArtifacts.IERC721.abi;
29
- const contract = new ethers_1.ethers.Contract(evmAddress, erc721Abi, this.config.TACParams.provider);
30
- const tx = await contract.connect(signer).approve(spenderAddress, asset.addresses.index);
31
- await tx.wait();
32
- }
33
- this.logger.debug(`Approved ${evmAddress} for ${spenderAddress}`);
34
- }
35
- async bridgeTokensToTON(signer, value, tonTarget, assets = [], tvmExecutorFee, tvmValidExecutors) {
36
- this.logger.debug('Bridging tokens to TON');
18
+ async prepareBridgeTokensToTON(value, tonTarget, assets = [], tvmExecutorFee, tvmValidExecutors) {
37
19
  Validator_1.Validator.validateTVMAddress(tonTarget);
38
- // Add native TAC asset if value > 0
20
+ Validator_1.Validator.validateTVMAddresses(tvmValidExecutors);
21
+ const validExecutors = tvmValidExecutors?.length ? tvmValidExecutors : this.config.getTrustedTONExecutors;
39
22
  const tonAssets = [...assets];
40
23
  if (value > 0n) {
41
24
  tonAssets.push((await assets_1.AssetFactory.from(this.config, {
@@ -43,26 +26,20 @@ class TACTransactionManager {
43
26
  tokenType: Struct_1.AssetType.FT,
44
27
  })).withRawAmount(value));
45
28
  }
46
- // Calculate executor fee if not provided
47
29
  if (!tvmExecutorFee) {
48
30
  const feeParams = {
49
31
  tonAssets: (0, Utils_1.mapAssetsToTonAssets)(tonAssets),
50
32
  feeSymbol: Consts_1.TAC_SYMBOL,
51
- tvmValidExecutors: tvmValidExecutors ?? [],
33
+ tvmValidExecutors: validExecutors,
52
34
  };
53
- const suggestedFee = await this.operationTracker.getTVMExecutorFee(feeParams);
35
+ const suggestedFee = await this.operationTracker.getTVMExecutorFee(feeParams, null);
54
36
  this.logger.debug(`Suggested TON executor fee: ${(0, Utils_1.formatObjectForLogging)(suggestedFee)}`);
55
37
  tvmExecutorFee = BigInt(suggestedFee.inTAC);
56
38
  }
57
- // Approve all assets
58
39
  const crossChainLayerAddress = await this.config.TACParams.crossChainLayer.getAddress();
59
- for (const asset of assets) {
60
- await this.approveAsset(asset, signer, crossChainLayerAddress);
61
- }
62
40
  const protocolFee = await this.config.TACParams.crossChainLayer.getProtocolFee();
63
- const shardsKey = BigInt(Math.round(Math.random() * 1e18));
41
+ const shardsKey = BigInt(Math.round(Math.random() * Consts_1.SHARDS_KEY_RANDOM_RANGE));
64
42
  this.logger.debug(`Shards key: ${shardsKey}, Protocol fee: ${protocolFee}`);
65
- // Prepare bridge data
66
43
  const [toBridge, toBridgeNFT] = await Promise.all([
67
44
  Promise.all(assets
68
45
  .filter((a) => a.type === Struct_1.AssetType.FT)
@@ -74,7 +51,7 @@ class TACTransactionManager {
74
51
  .filter((a) => a.type === Struct_1.AssetType.NFT)
75
52
  .map(async (a) => ({
76
53
  evmAddress: await a.getEVMAddress(),
77
- amount: 1n,
54
+ amount: Consts_1.NFT_BRIDGE_AMOUNT,
78
55
  tokenId: a.addresses.index,
79
56
  }))),
80
57
  ]);
@@ -84,15 +61,174 @@ class TACTransactionManager {
84
61
  tvmPayload: '',
85
62
  tvmProtocolFee: protocolFee,
86
63
  tvmExecutorFee,
87
- tvmValidExecutors: this.config.getTrustedTONExecutors,
64
+ tvmValidExecutors: validExecutors,
88
65
  toBridge,
89
66
  toBridgeNFT,
90
67
  };
91
- const totalValue = value + BigInt(outMessage.tvmProtocolFee) + BigInt(outMessage.tvmExecutorFee);
68
+ return {
69
+ crossChainLayerAddress,
70
+ outMessagePayload: this.config.artifacts.tac.utils.encodeOutMessageV1(outMessage),
71
+ totalValue: value + BigInt(outMessage.tvmProtocolFee) + BigInt(outMessage.tvmExecutorFee),
72
+ };
73
+ }
74
+ async approveAsset(asset, signer, spenderAddress, transactionParams = {}) {
75
+ const evmAddress = await asset.getEVMAddress();
76
+ if (asset.type === Struct_1.AssetType.FT) {
77
+ this.logger.debug(`Approving FT ${evmAddress} for ${spenderAddress}`);
78
+ const contract = new ethers_1.ethers.Contract(evmAddress, this.config.artifacts.tac.compilationArtifacts.IERC20WithDecimals.abi, this.config.TACParams.provider);
79
+ const tx = await contract.connect(signer).approve(spenderAddress, asset.rawAmount, transactionParams);
80
+ await tx.wait();
81
+ }
82
+ else {
83
+ this.logger.debug(`Approving NFT ${evmAddress} for ${spenderAddress}`);
84
+ const contract = new ethers_1.ethers.Contract(evmAddress, this.config.artifacts.tac.compilationArtifacts.IERC721.abi, this.config.TACParams.provider);
85
+ const tx = await contract
86
+ .connect(signer)
87
+ .approve(spenderAddress, asset.addresses.index, transactionParams);
88
+ await tx.wait();
89
+ }
90
+ this.logger.debug(`Approved ${evmAddress} for ${spenderAddress}`);
91
+ }
92
+ async sendCrossChainTransactionToTON(signer, tonTarget, assets = [], options) {
93
+ const signerAddress = signer.address;
94
+ const nativeTACAsset = await assets_1.AssetFactory.from(this.config, {
95
+ address: await this.config.nativeTACAddress(),
96
+ tokenType: Struct_1.AssetType.FT,
97
+ });
98
+ let value = 0n;
99
+ const bridgeAssets = [];
100
+ for (const asset of assets) {
101
+ if (asset.origin === Struct_1.Origin.TAC && asset.type === Struct_1.AssetType.FT && asset.address === nativeTACAsset.address) {
102
+ value += asset.rawAmount;
103
+ continue;
104
+ }
105
+ bridgeAssets.push(asset);
106
+ }
107
+ const preparedBridge = await this.prepareBridgeTokensToTON(value, tonTarget, bridgeAssets, options?.tvmExecutorFee, options?.tvmValidExecutors);
108
+ const feeData = await this.config.TACParams.provider.getFeeData();
109
+ const maxFeePerGas = feeData.maxFeePerGas;
110
+ if (maxFeePerGas === null) {
111
+ throw (0, errors_1.gasPriceFetchError)('TAC provider did not return maxFeePerGas');
112
+ }
113
+ const latestBlock = await this.config.TACParams.provider
114
+ .getBlock('latest')
115
+ .catch((error) => {
116
+ throw (0, errors_1.blockGasLimitFetchError)('provider failed to return latest block', error);
117
+ });
118
+ const blockGasLimit = latestBlock?.gasLimit;
119
+ if (blockGasLimit === null || blockGasLimit === undefined) {
120
+ throw (0, errors_1.blockGasLimitFetchError)('provider did not return latest block gas limit');
121
+ }
122
+ const transactionParams = {
123
+ maxFeePerGas,
124
+ maxPriorityFeePerGas: feeData.maxPriorityFeePerGas ?? Consts_1.DEFAULT_EIP1559_PRIORITY_FEE,
125
+ };
126
+ const shouldValidateAssetsBalance = options?.validateAssetsBalance ?? true;
127
+ if (shouldValidateAssetsBalance) {
128
+ await Promise.all(bridgeAssets.map((asset) => asset.checkCanBeTransferredBy(signerAddress, Struct_1.BlockchainType.TAC)));
129
+ }
130
+ let requiredBalance = preparedBridge.totalValue;
131
+ const approvalPlans = [];
132
+ for (const asset of bridgeAssets) {
133
+ let estimatedGas;
134
+ if (asset.type === Struct_1.AssetType.FT) {
135
+ const contract = new ethers_1.ethers.Contract(await asset.getEVMAddress(), this.config.artifacts.tac.compilationArtifacts.IERC20WithDecimals.abi, this.config.TACParams.provider);
136
+ estimatedGas = await contract
137
+ .connect(signer)
138
+ .approve.estimateGas(preparedBridge.crossChainLayerAddress, asset.rawAmount, transactionParams);
139
+ }
140
+ else {
141
+ const contract = new ethers_1.ethers.Contract(await asset.getEVMAddress(), this.config.artifacts.tac.compilationArtifacts.IERC721.abi, this.config.TACParams.provider);
142
+ estimatedGas = await contract
143
+ .connect(signer)
144
+ .approve.estimateGas(preparedBridge.crossChainLayerAddress, asset.addresses.index, transactionParams);
145
+ }
146
+ if (estimatedGas > blockGasLimit) {
147
+ throw (0, errors_1.estimatedGasExceedsBlockGasLimitError)('approve', estimatedGas, blockGasLimit);
148
+ }
149
+ requiredBalance += estimatedGas * maxFeePerGas;
150
+ approvalPlans.push({ asset, gasLimit: estimatedGas });
151
+ }
152
+ const sendMessageGas = await this.config.TACParams.crossChainLayer
153
+ .connect(signer)
154
+ .sendMessage.estimateGas(Consts_1.CROSS_CHAIN_MESSAGE_VERSION_V1, preparedBridge.outMessagePayload, {
155
+ ...transactionParams,
156
+ value: preparedBridge.totalValue,
157
+ });
158
+ if (sendMessageGas > blockGasLimit) {
159
+ throw (0, errors_1.estimatedGasExceedsBlockGasLimitError)('sendMessage', sendMessageGas, blockGasLimit);
160
+ }
161
+ requiredBalance += sendMessageGas * maxFeePerGas;
162
+ const balance = await this.config.TACParams.provider.getBalance(signer.address);
163
+ if (balance < requiredBalance) {
164
+ throw (0, errors_1.insufficientBalanceError)(Consts_1.TAC_SYMBOL);
165
+ }
166
+ for (const approval of approvalPlans) {
167
+ await this.approveAsset(approval.asset, signer, preparedBridge.crossChainLayerAddress, {
168
+ ...transactionParams,
169
+ gasLimit: approval.gasLimit,
170
+ });
171
+ }
172
+ const tx = await this.config.TACParams.crossChainLayer
173
+ .connect(signer)
174
+ .sendMessage(Consts_1.CROSS_CHAIN_MESSAGE_VERSION_V1, preparedBridge.outMessagePayload, {
175
+ ...transactionParams,
176
+ gasLimit: sendMessageGas,
177
+ value: preparedBridge.totalValue,
178
+ });
179
+ await tx.wait();
180
+ this.logger.debug(`Transaction hash: ${tx.hash}`);
181
+ const shouldWaitForOperationId = options?.waitOperationId ?? true;
182
+ if (!shouldWaitForOperationId) {
183
+ return { txHash: tx.hash };
184
+ }
185
+ const waitOptions = options?.waitOptions ?? {};
186
+ waitOptions.successCheck = waitOptions.successCheck ?? ((id) => !!id);
187
+ waitOptions.logger = waitOptions.logger ?? this.logger;
188
+ const operationId = await this.operationTracker
189
+ .getOperationIdByTransactionHash(tx.hash, waitOptions)
190
+ .catch((error) => {
191
+ this.logger.error(`Error while waiting for operation ID by transaction hash: ${error}`);
192
+ return undefined;
193
+ });
194
+ const shouldWaitForFinalization = options?.waitFinalization ?? true;
195
+ if (!shouldWaitForFinalization) {
196
+ return { txHash: tx.hash, operationId };
197
+ }
198
+ if (!operationId) {
199
+ throw errors_1.operationIdRequiredForFinalizationError;
200
+ }
201
+ const finalizationWaitOptions = options?.finalizationWaitOptions ?? {};
202
+ finalizationWaitOptions.successCheck = finalizationWaitOptions.successCheck ?? Utils_1.isFinalProfiling;
203
+ finalizationWaitOptions.logger = finalizationWaitOptions.logger ?? this.logger;
204
+ finalizationWaitOptions.onSuccess =
205
+ finalizationWaitOptions.onSuccess ??
206
+ (async (profilingData) => {
207
+ if (!profilingData.executedInTON.exists) {
208
+ return;
209
+ }
210
+ if (!profilingData.executedInTON.stageData?.success) {
211
+ throw errors_1.executedInTONStageFailedError;
212
+ }
213
+ for (const transaction of profilingData.executedInTON.stageData?.transactions ?? []) {
214
+ await this.config.TONParams.contractOpener.trackTransactionTree(this.config.TONParams.crossChainLayerAddress, transaction.hash);
215
+ }
216
+ });
217
+ await this.operationTracker.getStageProfiling(operationId, finalizationWaitOptions);
218
+ return { txHash: tx.hash, operationId };
219
+ }
220
+ async bridgeTokensToTON(signer, value, tonTarget, assets = [], tvmExecutorFee, tvmValidExecutors) {
221
+ this.logger.debug('Bridging tokens to TON');
222
+ const { crossChainLayerAddress, outMessagePayload, totalValue } = await this.prepareBridgeTokensToTON(value, tonTarget, assets, tvmExecutorFee, tvmValidExecutors);
92
223
  this.logger.debug(`Total value: ${totalValue}`);
224
+ for (const asset of assets) {
225
+ await this.approveAsset(asset, signer, crossChainLayerAddress);
226
+ }
93
227
  const tx = await this.config.TACParams.crossChainLayer
94
228
  .connect(signer)
95
- .sendMessage(1n, this.config.artifacts.tac.utils.encodeOutMessageV1(outMessage), { value: totalValue });
229
+ .sendMessage(Consts_1.CROSS_CHAIN_MESSAGE_VERSION_V1, outMessagePayload, {
230
+ value: totalValue,
231
+ });
96
232
  await tx.wait();
97
233
  this.logger.debug(`Transaction hash: ${tx.hash}`);
98
234
  return tx.hash;
@@ -68,8 +68,7 @@ class TONTransactionManager {
68
68
  async prepareCrossChainTransaction(evmProxyMsg, sender, assets, options, skipAssetsBalanceValidation = false) {
69
69
  this.logger.debug('Preparing cross-chain transaction');
70
70
  const caller = sender.getSenderAddress();
71
- const { allowSimulationError = false, isRoundTrip = undefined, calculateRollbackFee = true, validateAssetsBalance = true, evmDataBuilder = Utils_1.buildEvmDataCell, } = options || {};
72
- const { evmValidExecutors = [], tvmValidExecutors = [] } = options || {};
71
+ const { allowSimulationError = false, isRoundTrip = undefined, calculateRollbackFee = true, validateAssetsBalance = true, evmValidExecutors = [], tvmValidExecutors = [], evmDataBuilder = Utils_1.buildEvmDataCell, } = options || {};
73
72
  Validator_1.Validator.validateEVMAddress(evmProxyMsg.evmTargetAddress);
74
73
  const aggregatedData = (0, Utils_1.aggregateTokens)(assets);
75
74
  Validator_1.Validator.validateEVMAddresses(evmValidExecutors);
@@ -182,16 +181,14 @@ class TONTransactionManager {
182
181
  if (!shouldWaitForOperationId) {
183
182
  return { sendTransactionResult, ...transactionLinker };
184
183
  }
185
- const waitOptions = tx.options?.waitOptions ?? {};
186
184
  const ensureTxExecuted = tx.options?.ensureTxExecuted ?? true;
187
185
  if (ensureTxExecuted && sendTransactionResult.boc) {
188
186
  const hash = (0, Utils_1.getNormalizedExtMessageHash)((0, ton_1.loadMessage)(ton_1.Cell.fromBase64(sendTransactionResult.boc).beginParse()));
189
187
  this.logger.info(`Tracking transaction tree for hash: ${hash}`);
190
- await this.config.TONParams.contractOpener.trackTransactionTree(sender.getSenderAddress(), hash, {
191
- maxDepth: Consts_1.DEFAULT_FIND_TX_MAX_DEPTH,
192
- });
188
+ await this.config.TONParams.contractOpener.trackTransactionTree(sender.getSenderAddress(), hash);
193
189
  this.logger.info(`Transaction tree successful`);
194
190
  }
191
+ const waitOptions = tx.options?.waitOptions ?? {};
195
192
  waitOptions.successCheck = waitOptions.successCheck ?? ((id) => !!id);
196
193
  waitOptions.logger = waitOptions.logger ?? this.logger;
197
194
  const operationId = await this.operationTracker
@@ -200,6 +197,31 @@ class TONTransactionManager {
200
197
  this.logger.error(`Error while waiting for operation ID: ${error}`);
201
198
  return undefined;
202
199
  });
200
+ const shouldWaitForFinalization = tx.options?.waitFinalization ?? true;
201
+ if (!shouldWaitForFinalization) {
202
+ return { sendTransactionResult, ...transactionLinker };
203
+ }
204
+ if (!operationId) {
205
+ throw errors_1.operationIdRequiredForFinalizationError;
206
+ }
207
+ const finalizationWaitOptions = tx.options?.finalizationWaitOptions ?? {};
208
+ finalizationWaitOptions.successCheck = finalizationWaitOptions.successCheck ?? Utils_1.isFinalProfiling;
209
+ finalizationWaitOptions.logger = finalizationWaitOptions.logger ?? this.logger;
210
+ finalizationWaitOptions.onSuccess =
211
+ finalizationWaitOptions.onSuccess ??
212
+ (async (profilingData) => {
213
+ const stage = profilingData.executedInTON;
214
+ if (!stage.exists) {
215
+ return;
216
+ }
217
+ if (!stage.stageData?.success) {
218
+ throw errors_1.executedInTONStageFailedError;
219
+ }
220
+ for (const transaction of stage.stageData?.transactions ?? []) {
221
+ await this.config.TONParams.contractOpener.trackTransactionTree(this.config.TONParams.crossChainLayerAddress, transaction.hash);
222
+ }
223
+ });
224
+ await this.operationTracker.getStageProfiling(operationId, finalizationWaitOptions);
203
225
  return { sendTransactionResult, operationId, ...transactionLinker };
204
226
  }
205
227
  async sendCrossChainTransactions(sender, txs, options) {
@@ -1,9 +1,9 @@
1
1
  import { Wallet } from 'ethers';
2
2
  import { JettonMinterData, NFTItemData } from '../../artifacts/tonTypes';
3
- import { FT, NFT } from '../assets';
3
+ import { FT, NFT, TAC, TON } from '../assets';
4
4
  import { ContractOpener, IConfiguration, ILogger, IOperationTracker, ITacExplorerClient, ITacSDK } from '../interfaces';
5
5
  import type { SenderAbstraction } from '../sender';
6
- import { AssetFromFTArg, AssetFromNFTCollectionArg, AssetFromNFTItemArg, AssetLike, BatchCrossChainTxWithAssetLike, CrossChainPayloadResult, CrossChainTransactionOptions, CrossChainTransactionsOptions, CrosschainTx, EVMAddress, EvmProxyMsg, ExecutionFeeEstimationResult, NFTAddressType, SDKParams, SuggestedTVMExecutorFee, TacGasPrice, TACSimulationParams, TACSimulationResult, TransactionLinkerWithOperationId, TVMAddress, UserWalletBalanceExtended } from '../structs/Struct';
6
+ import { AssetFromFTArg, AssetFromNFTCollectionArg, AssetFromNFTItemArg, AssetLike, BatchCrossChainTxWithAssetLike, BridgeTokensToTONOptions, CrossChainPayloadResult, CrossChainTransactionOptions, CrossChainTransactionsOptions, CrosschainTx, EVMAddress, EvmProxyMsg, ExecutionFeeEstimationResult, NFTAddressType, SDKParams, SuggestedTVMExecutorFee, TACCrossChainTransactionResult, TacGasPrice, TACSimulationParams, TACSimulationResult, TransactionLinkerWithOperationId, TVMAddress, UserWalletBalanceExtended } from '../structs/Struct';
7
7
  export declare class TacSdk implements ITacSDK {
8
8
  readonly config: IConfiguration;
9
9
  readonly contactOpener: ContractOpener;
@@ -23,12 +23,13 @@ export declare class TacSdk implements ITacSDK {
23
23
  getSimulationInfo(evmProxyMsg: EvmProxyMsg, sender: SenderAbstraction, assets?: AssetLike[], options?: CrossChainTransactionOptions): Promise<ExecutionFeeEstimationResult>;
24
24
  getTVMExecutorFeeInfo(assets: AssetLike[], feeSymbol: string, tvmValidExecutors?: string[]): Promise<SuggestedTVMExecutorFee>;
25
25
  sendCrossChainTransaction(evmProxyMsg: EvmProxyMsg, sender: SenderAbstraction, assets?: AssetLike[], options?: CrossChainTransactionOptions): Promise<TransactionLinkerWithOperationId>;
26
+ sendCrossChainTransactionToTON(signer: Wallet, tonTarget: string, assets?: AssetLike[], options?: BridgeTokensToTONOptions): Promise<TACCrossChainTransactionResult>;
26
27
  sendCrossChainTransactions(sender: SenderAbstraction, txs: BatchCrossChainTxWithAssetLike[], options?: CrossChainTransactionsOptions): Promise<TransactionLinkerWithOperationId[]>;
27
28
  bridgeTokensToTON(signer: Wallet, value: bigint, tonTarget: string, assets?: AssetLike[], tvmExecutorFee?: bigint, tvmValidExecutors?: string[]): Promise<string>;
28
29
  isContractDeployedOnTVM(address: string): Promise<boolean>;
29
30
  simulateTACMessage(req: TACSimulationParams): Promise<TACSimulationResult>;
30
31
  simulateTransactions(sender: SenderAbstraction, txs: CrosschainTx[]): Promise<ExecutionFeeEstimationResult[]>;
31
- getAsset(args: AssetFromFTArg): Promise<FT>;
32
+ getAsset(args: AssetFromFTArg): Promise<FT | TAC | TON>;
32
33
  getAsset(args: AssetFromNFTCollectionArg): Promise<NFT>;
33
34
  getAsset(args: AssetFromNFTItemArg): Promise<NFT>;
34
35
  getUserJettonWalletAddress(userAddress: string, tokenAddress: string): Promise<string>;
@@ -87,6 +87,10 @@ class TacSdk {
87
87
  const tx = { evmProxyMsg, assets: normalizedAssets, options };
88
88
  return this.tonTransactionManager.sendCrossChainTransaction(evmProxyMsg, sender, tx);
89
89
  }
90
+ async sendCrossChainTransactionToTON(signer, tonTarget, assets, options) {
91
+ const normalizedAssets = await (0, Utils_1.normalizeAssets)(this.config, assets);
92
+ return this.tacTransactionManager.sendCrossChainTransactionToTON(signer, tonTarget, normalizedAssets, options);
93
+ }
90
94
  async sendCrossChainTransactions(sender, txs, options) {
91
95
  const normalizedTxs = await Promise.all(txs.map(async (tx) => ({
92
96
  evmProxyMsg: tx.evmProxyMsg,
@@ -3,7 +3,7 @@ import { AbiCoder } from 'ethers';
3
3
  import type { FT, NFT, TON } from '../assets';
4
4
  import { Asset, IConfiguration } from '../interfaces';
5
5
  import { RandomNumberByTimestamp } from '../structs/InternalStruct';
6
- import { AssetLike, EvmProxyMsg, FeeParams, TONAsset, TransactionLinker, ValidExecutors, WaitOptions } from '../structs/Struct';
6
+ import { AssetLike, EvmProxyMsg, ExecutionStages, FeeParams, TONAsset, TransactionLinker, ValidExecutors, WaitOptions } from '../structs/Struct';
7
7
  export declare const sleep: (ms: number) => Promise<unknown>;
8
8
  export declare function generateRandomNumber(interval: number): number;
9
9
  export declare function generateRandomNumberByTimestamp(): RandomNumberByTimestamp;
@@ -56,3 +56,4 @@ export declare function recurisivelyCollectCellStats(cell: Cell): {
56
56
  bits: number;
57
57
  cells: number;
58
58
  };
59
+ export declare function isFinalProfiling(profilingData: ExecutionStages): boolean;
@@ -25,6 +25,7 @@ exports.normalizeHashToHex = normalizeHashToHex;
25
25
  exports.getNormalizedExtMessageHash = getNormalizedExtMessageHash;
26
26
  exports.retry = retry;
27
27
  exports.recurisivelyCollectCellStats = recurisivelyCollectCellStats;
28
+ exports.isFinalProfiling = isFinalProfiling;
28
29
  const ton_1 = require("@ton/ton");
29
30
  const ethers_1 = require("ethers");
30
31
  const ton_crypto_1 = require("ton-crypto");
@@ -458,3 +459,6 @@ function recurisivelyCollectCellStats(cell) {
458
459
  }
459
460
  return { bits, cells };
460
461
  }
462
+ function isFinalProfiling(profilingData) {
463
+ return profilingData.operationType !== Struct_1.OperationType.PENDING && profilingData.operationType !== Struct_1.OperationType.UNKNOWN;
464
+ }
@@ -2,7 +2,7 @@ import { Address, Cell } from '@ton/ton';
2
2
  import { AbstractProvider, ethers } from 'ethers';
3
3
  import { ICrossChainLayer, ISAFactory, ISettings, ITokenUtils } from '../../artifacts/tacTypes';
4
4
  import { ContractOpener } from '../interfaces';
5
- import { CurrencyType, ExecutionStagesByOperationId, Network, OperationIdsByShardsKey, OperationType, StatusInfosByOperationId, SuggestedTVMExecutorFee, TACSimulationResult } from './Struct';
5
+ import { CurrencyType, ExecutionStagesByOperationId, ExecutionStagesV2ByOperationId, Network, OperationIdsByShardsKey, OperationType, OperationTypeV2Info, StatusInfosByOperationId, SuggestedTVMExecutorFee, TACSimulationResult, TransactionLinker } from './Struct';
6
6
  export type ShardMessage = {
7
7
  address: string;
8
8
  value: bigint;
@@ -17,6 +17,15 @@ export type ShardTransaction = {
17
17
  messages: ShardMessage[];
18
18
  network: Network;
19
19
  };
20
+ export type PreparedCrossChainTransaction = {
21
+ transaction: ShardTransaction;
22
+ transactionLinker: TransactionLinker;
23
+ };
24
+ export type PreparedBridgeTokensToTON = {
25
+ crossChainLayerAddress: string;
26
+ outMessagePayload: ethers.BytesLike;
27
+ totalValue: bigint;
28
+ };
20
29
  export declare enum AssetOpType {
21
30
  JETTON_BURN = "JETTON_BURN",
22
31
  JETTON_TRANSFER = "JETTON_TRANSFER",
@@ -54,9 +63,11 @@ export type ResponseBase<T> = {
54
63
  };
55
64
  export type StringResponse = ResponseBase<string>;
56
65
  export type OperationTypeResponse = ResponseBase<OperationType>;
66
+ export type OperationTypeV2Response = ResponseBase<OperationTypeV2Info>;
57
67
  export type StatusesResponse = ResponseBase<StatusInfosByOperationId>;
58
68
  export type OperationIdsByShardsKeyResponse = ResponseBase<OperationIdsByShardsKey>;
59
69
  export type StageProfilingResponse = ResponseBase<ExecutionStagesByOperationId>;
70
+ export type StageProfilingV2Response = ResponseBase<ExecutionStagesV2ByOperationId>;
60
71
  export type TACSimulationResponse = ResponseBase<TACSimulationResult>;
61
72
  export type SuggestedTVMExecutorFeeResponse = ResponseBase<SuggestedTVMExecutorFee>;
62
73
  export type ConvertCurrencyResponse = ResponseBase<ConvertedCurrencyRawResult>;
@@ -72,6 +83,29 @@ export interface SendResult {
72
83
  error?: Error;
73
84
  lastMessageIndex?: number;
74
85
  }
86
+ export type SendGroupTransferResult = string | {
87
+ result: string;
88
+ };
89
+ export type SendBatchTransferResult = string | void | {
90
+ result: string | void;
91
+ };
92
+ export type RetryableOperationResult<T> = {
93
+ success: boolean;
94
+ data?: T;
95
+ lastError?: Error;
96
+ };
97
+ export type MetadataPersistenceType = 'none' | 'onchain' | 'offchain_private_domain' | 'offchain_ipfs' | 'semichain_private_domain' | 'semichain_ipfs';
98
+ export type OffchainMetadataResult<TMetadata = unknown> = {
99
+ metadata: TMetadata | null;
100
+ isIpfs: boolean;
101
+ contentUri: string;
102
+ };
103
+ export type ReadMetadataResult<TMetadata = unknown> = {
104
+ persistenceType: MetadataPersistenceType;
105
+ metadata: TMetadata | null;
106
+ contentUri?: string;
107
+ isJettonDeployerFaultyOnChainData?: boolean;
108
+ };
75
109
  export type ToncenterTransaction = {
76
110
  description: {
77
111
  aborted: boolean;