@tonappchain/sdk 0.7.2 → 0.7.3-rc2

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 (67) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +203 -199
  3. package/dist/artifacts/dev/index.d.ts +2 -2
  4. package/dist/artifacts/dev/index.js +2 -1
  5. package/dist/artifacts/dev/ton/endpoints.d.ts +1 -0
  6. package/dist/artifacts/dev/ton/endpoints.js +2 -1
  7. package/dist/artifacts/mainnet/index.d.ts +2 -2
  8. package/dist/artifacts/mainnet/index.js +2 -1
  9. package/dist/artifacts/mainnet/ton/endpoints.d.ts +1 -0
  10. package/dist/artifacts/mainnet/ton/endpoints.js +2 -1
  11. package/dist/artifacts/testnet/index.d.ts +2 -2
  12. package/dist/artifacts/testnet/index.js +2 -1
  13. package/dist/artifacts/testnet/ton/endpoints.d.ts +1 -0
  14. package/dist/artifacts/testnet/ton/endpoints.js +2 -1
  15. package/dist/src/adapters/BaseContractOpener.js +8 -5
  16. package/dist/src/adapters/RetryableContractOpener.d.ts +6 -1
  17. package/dist/src/adapters/RetryableContractOpener.js +35 -8
  18. package/dist/src/adapters/ToncenterV3Indexer.d.ts +34 -0
  19. package/dist/src/adapters/ToncenterV3Indexer.js +123 -0
  20. package/dist/src/adapters/index.d.ts +1 -0
  21. package/dist/src/adapters/index.js +1 -0
  22. package/dist/src/assets/AssetFactory.d.ts +4 -1
  23. package/dist/src/assets/AssetFactory.js +4 -0
  24. package/dist/src/assets/FT.d.ts +3 -3
  25. package/dist/src/assets/FT.js +28 -15
  26. package/dist/src/assets/NFT.d.ts +3 -3
  27. package/dist/src/assets/NFT.js +10 -4
  28. package/dist/src/assets/TAC.d.ts +24 -0
  29. package/dist/src/assets/TAC.js +74 -0
  30. package/dist/src/assets/TON.d.ts +3 -3
  31. package/dist/src/assets/TON.js +12 -5
  32. package/dist/src/assets/index.d.ts +1 -0
  33. package/dist/src/assets/index.js +3 -1
  34. package/dist/src/errors/index.d.ts +1 -1
  35. package/dist/src/errors/index.js +8 -1
  36. package/dist/src/errors/instances.d.ts +6 -0
  37. package/dist/src/errors/instances.js +11 -1
  38. package/dist/src/interfaces/Asset.d.ts +11 -6
  39. package/dist/src/interfaces/ContractOpener.d.ts +1 -1
  40. package/dist/src/interfaces/IConfiguration.d.ts +1 -3
  41. package/dist/src/interfaces/ILiteSequencerClient.d.ts +14 -2
  42. package/dist/src/interfaces/IOperationTracker.d.ts +26 -1
  43. package/dist/src/interfaces/ITACTransactionManager.d.ts +20 -1
  44. package/dist/src/interfaces/ITacSDK.d.ts +52 -10
  45. package/dist/src/interfaces/IToncenterV3Indexer.d.ts +35 -0
  46. package/dist/src/interfaces/IToncenterV3Indexer.js +2 -0
  47. package/dist/src/interfaces/index.d.ts +1 -0
  48. package/dist/src/interfaces/index.js +1 -0
  49. package/dist/src/sdk/Consts.d.ts +6 -0
  50. package/dist/src/sdk/Consts.js +7 -1
  51. package/dist/src/sdk/LiteSequencerClient.d.ts +5 -2
  52. package/dist/src/sdk/LiteSequencerClient.js +59 -1
  53. package/dist/src/sdk/OperationTracker.d.ts +5 -1
  54. package/dist/src/sdk/OperationTracker.js +76 -0
  55. package/dist/src/sdk/TACTransactionManager.d.ts +4 -0
  56. package/dist/src/sdk/TACTransactionManager.js +181 -35
  57. package/dist/src/sdk/TONTransactionManager.js +28 -6
  58. package/dist/src/sdk/TacSdk.d.ts +8 -3
  59. package/dist/src/sdk/TacSdk.js +40 -2
  60. package/dist/src/sdk/Utils.d.ts +2 -1
  61. package/dist/src/sdk/Utils.js +5 -1
  62. package/dist/src/structs/InternalStruct.d.ts +41 -2
  63. package/dist/src/structs/Struct.d.ts +209 -6
  64. package/dist/src/structs/Struct.js +12 -1
  65. package/dist/src/wrappers/ContentUtils.d.ts +36 -13
  66. package/dist/src/wrappers/ContentUtils.js +197 -98
  67. package/package.json +121 -121
@@ -5,6 +5,7 @@ const ton_1 = require("@ton/ton");
5
5
  const errors_1 = require("../errors");
6
6
  const Consts_1 = require("../sdk/Consts");
7
7
  const Utils_1 = require("../sdk/Utils");
8
+ const Struct_1 = require("../structs/Struct");
8
9
  /**
9
10
  * Base class for ContractOpener implementations with common functionality
10
11
  */
@@ -327,7 +328,7 @@ class BaseContractOpener {
327
328
  maxDepth: Consts_1.DEFAULT_FIND_TX_MAX_DEPTH,
328
329
  ignoreOpcodeList: Consts_1.IGNORE_OPCODE,
329
330
  limit: Consts_1.DEFAULT_FIND_TX_LIMIT,
330
- direction: 'both',
331
+ direction: Struct_1.TransactionTreeDirection.FORWARD,
331
332
  retryOnNotFound: Consts_1.DEFAULT_RETRY_ON_NOT_FOUND,
332
333
  }) {
333
334
  const result = await this.trackTransactionTreeWithResult(address, hash, params);
@@ -353,10 +354,10 @@ class BaseContractOpener {
353
354
  maxDepth: Consts_1.DEFAULT_FIND_TX_MAX_DEPTH,
354
355
  ignoreOpcodeList: Consts_1.IGNORE_OPCODE,
355
356
  limit: Consts_1.DEFAULT_FIND_TX_LIMIT,
356
- direction: 'both',
357
+ direction: Struct_1.TransactionTreeDirection.FORWARD,
357
358
  retryOnNotFound: Consts_1.DEFAULT_RETRY_ON_NOT_FOUND,
358
359
  }) {
359
- const { maxDepth = Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, ignoreOpcodeList = Consts_1.IGNORE_OPCODE, limit = Consts_1.DEFAULT_FIND_TX_LIMIT, maxScannedTransactions = Consts_1.DEFAULT_MAX_SCANNED_TRANSACTIONS, direction = 'both', retryOnNotFound = Consts_1.DEFAULT_RETRY_ON_NOT_FOUND, retryDelayMs, retries, } = params;
360
+ const { maxDepth = Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, ignoreOpcodeList = Consts_1.IGNORE_OPCODE, limit = Consts_1.DEFAULT_FIND_TX_LIMIT, maxScannedTransactions = Consts_1.DEFAULT_MAX_SCANNED_TRANSACTIONS, direction = Struct_1.TransactionTreeDirection.FORWARD, retryOnNotFound = Consts_1.DEFAULT_RETRY_ON_NOT_FOUND, retryDelayMs, retries, } = params;
360
361
  const parsedAddress = ton_1.Address.parse(address);
361
362
  const normalizedRootHash = (0, Utils_1.normalizeHashToBase64)(hash);
362
363
  const visitedSearchKeys = new Set();
@@ -410,7 +411,8 @@ class BaseContractOpener {
410
411
  }
411
412
  // Add adjacent transactions to queue
412
413
  if (currentDepth < maxDepth) {
413
- if ((direction === 'forward' || direction === 'both') && tx.outMessages.size > 0) {
414
+ if ((direction === Struct_1.TransactionTreeDirection.FORWARD || direction === Struct_1.TransactionTreeDirection.BOTH) &&
415
+ tx.outMessages.size > 0) {
414
416
  for (const msg of tx.outMessages.values()) {
415
417
  const dst = msg.info.dest;
416
418
  if (!dst || dst instanceof ton_1.ExternalAddress)
@@ -424,7 +426,8 @@ class BaseContractOpener {
424
426
  }
425
427
  }
426
428
  // Backward: add parent (incoming message source)
427
- if ((direction === 'backward' || direction === 'both') && tx.inMessage?.info.type === 'internal') {
429
+ if ((direction === Struct_1.TransactionTreeDirection.BACKWARD || direction === Struct_1.TransactionTreeDirection.BOTH) &&
430
+ tx.inMessage?.info.type === 'internal') {
428
431
  queue.push({
429
432
  hash: (0, ton_1.beginCell)().store((0, ton_1.storeMessage)(tx.inMessage)).endCell().hash().toString('base64'),
430
433
  address: tx.inMessage.info.src,
@@ -7,8 +7,12 @@ export interface OpenerConfig {
7
7
  opener: ContractOpener;
8
8
  /** Number of retry attempts before falling back to the next opener. */
9
9
  retries: number;
10
- /** Delay in milliseconds between retries for this opener. */
10
+ /** Base delay in milliseconds between retries for this opener. */
11
11
  retryDelay: number;
12
+ /** Upper bound for exponential backoff delay in milliseconds. */
13
+ maxRetryDelay?: number;
14
+ /** Exponential backoff multiplier applied after each failed retry. */
15
+ retryBackoffMultiplier?: number;
12
16
  }
13
17
  export declare class RetryableContractOpener implements ContractOpener {
14
18
  private readonly openerConfigs;
@@ -32,6 +36,7 @@ export declare class RetryableContractOpener implements ContractOpener {
32
36
  private executeWithFallback;
33
37
  private trySingleAttempt;
34
38
  private tryWithRetries;
39
+ private getRetryDelay;
35
40
  private isContractExecutionError;
36
41
  private isTransportError;
37
42
  private createRetryableContract;
@@ -22,9 +22,7 @@ class RetryableContractOpener {
22
22
  }
23
23
  }
24
24
  setLogger(logger) {
25
- if (!this.logger) {
26
- this.logger = logger;
27
- }
25
+ this.logger = logger;
28
26
  this.applyLoggerToOpeners(logger);
29
27
  }
30
28
  applyLoggerToOpeners(logger) {
@@ -199,13 +197,24 @@ class RetryableContractOpener {
199
197
  return { success: false, lastError };
200
198
  }
201
199
  if (attempt < config.retries) {
202
- this.logger?.debug(`[RetryableContractOpener] ${operationContext}: attempt ${attempt + 1}/${config.retries + 1} failed (${lastError.message}), retrying in ${config.retryDelay}ms`);
203
- await sleep(config.retryDelay);
200
+ const retryDelay = this.getRetryDelay(config, attempt);
201
+ this.logger?.debug(`[RetryableContractOpener] ${operationContext}: attempt ${attempt + 1}/${config.retries + 1} failed (${lastError.message}), retrying in ${retryDelay}ms`);
202
+ await sleep(retryDelay);
204
203
  }
205
204
  }
206
205
  }
207
206
  return { success: false, lastError };
208
207
  }
208
+ getRetryDelay(config, attempt) {
209
+ const baseDelay = config.retryDelay ?? Consts_1.DEFAULT_RETRY_DELAY_MS;
210
+ const maxRetryDelay = config.maxRetryDelay ?? Consts_1.DEFAULT_RETRY_MAX_DELAY_MS;
211
+ const backoffMultiplier = config.retryBackoffMultiplier ?? Consts_1.DEFAULT_RETRY_BACKOFF_MULTIPLIER;
212
+ if (baseDelay === 0 || maxRetryDelay === 0) {
213
+ return 0;
214
+ }
215
+ const calculatedDelay = baseDelay * backoffMultiplier ** attempt;
216
+ return Math.min(Math.round(calculatedDelay), maxRetryDelay);
217
+ }
209
218
  isContractExecutionError(error) {
210
219
  const errorWithExit = error;
211
220
  if (typeof errorWithExit.exitCode === 'number' ||
@@ -269,18 +278,36 @@ async function createDefaultRetryableOpener(tonRpcEndpoint, networkType, maxRetr
269
278
  timeout: Consts_1.DEFAULT_HTTP_CLIENT_TIMEOUT_MS,
270
279
  });
271
280
  const opener = (0, TonClientOpener_1.tonClientOpener)(tonClient, logger);
272
- openers.push({ opener, retries: maxRetries, retryDelay });
281
+ openers.push({
282
+ opener,
283
+ retries: maxRetries,
284
+ retryDelay,
285
+ maxRetryDelay: Consts_1.DEFAULT_RETRY_MAX_DELAY_MS,
286
+ retryBackoffMultiplier: Consts_1.DEFAULT_RETRY_BACKOFF_MULTIPLIER,
287
+ });
273
288
  if (networkType !== Struct_1.Network.DEV) {
274
289
  try {
275
290
  const opener = await (0, TonClientOpener_1.orbsOpener)(networkType, logger);
276
- openers.push({ opener: opener, retries: maxRetries, retryDelay });
291
+ openers.push({
292
+ opener: opener,
293
+ retries: maxRetries,
294
+ retryDelay,
295
+ maxRetryDelay: Consts_1.DEFAULT_RETRY_MAX_DELAY_MS,
296
+ retryBackoffMultiplier: Consts_1.DEFAULT_RETRY_BACKOFF_MULTIPLIER,
297
+ });
277
298
  }
278
299
  catch {
279
300
  // skip opener in case of failure
280
301
  }
281
302
  try {
282
303
  const opener4 = await (0, TonClient4Opener_1.orbsOpener4)(networkType, Consts_1.DEFAULT_HTTP_CLIENT_TIMEOUT_MS, logger);
283
- openers.push({ opener: opener4, retries: maxRetries, retryDelay });
304
+ openers.push({
305
+ opener: opener4,
306
+ retries: maxRetries,
307
+ retryDelay,
308
+ maxRetryDelay: Consts_1.DEFAULT_RETRY_MAX_DELAY_MS,
309
+ retryBackoffMultiplier: Consts_1.DEFAULT_RETRY_BACKOFF_MULTIPLIER,
310
+ });
284
311
  }
285
312
  catch {
286
313
  // skip opener in case of failure
@@ -0,0 +1,34 @@
1
+ import { IHttpClient, IToncenterV3Indexer } from '../interfaces';
2
+ import { ToncenterV3IndexedTransaction, ToncenterV3TraversalParams } from '../structs/Struct';
3
+ /**
4
+ * Thin Toncenter v3 indexer client for resolving indexed TON transaction context by hash and
5
+ * traversing a linked chain of TON transactions until it finds the sequencer-collected event transaction on CCL.
6
+ */
7
+ export declare class ToncenterV3Indexer implements IToncenterV3Indexer {
8
+ readonly endpoint: string;
9
+ private readonly httpClient;
10
+ constructor(endpoint: string, httpClient?: IHttpClient);
11
+ /**
12
+ * Queries Toncenter v3 indexed `/transactions` endpoint by hash and returns the first match.
13
+ * @param transactionHash TON transaction hash accepted by the indexer.
14
+ * @returns Indexed transaction with owning account context, or null on 404 / empty result.
15
+ */
16
+ getTransactionByHash(transactionHash: string): Promise<ToncenterV3IndexedTransaction | null>;
17
+ /**
18
+ * Queries Toncenter v3 indexed `/adjacentTransactions` endpoint by hash.
19
+ * @param transactionHash TON transaction hash accepted by the indexer.
20
+ * @returns Adjacent indexed transactions, or an empty array on 404 / empty result.
21
+ */
22
+ getAdjacentTransactions(transactionHash: string): Promise<ToncenterV3IndexedTransaction[]>;
23
+ /**
24
+ * Traverses the linked chain of TON transactions in both directions starting from any TON transaction hash
25
+ * from that linked transaction chain, and returns the transaction on crossChainLayer that the sequencer would collect
26
+ * as a TVM event.
27
+ * @param transactionHash Any TON transaction hash from the target linked chain of TON transactions.
28
+ * @param crossChainLayerAddress crossChainLayer address whose sequencer-collected event transaction should be found in that linked chain of TON transactions.
29
+ * @param params Optional traversal settings. Defaults match the SDK traversal defaults.
30
+ * @returns Indexed crossChainLayer transaction that matches the sequencer collector rules, or null if not found.
31
+ */
32
+ findCollectibleCrossChainLayerTransaction(transactionHash: string, crossChainLayerAddress: string, params?: ToncenterV3TraversalParams): Promise<ToncenterV3IndexedTransaction | null>;
33
+ private isCollectibleEventTransactionOnAccount;
34
+ }
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToncenterV3Indexer = void 0;
4
+ const ton_1 = require("@ton/ton");
5
+ const errors_1 = require("../errors");
6
+ const AxiosHttpClient_1 = require("../sdk/AxiosHttpClient");
7
+ const Consts_1 = require("../sdk/Consts");
8
+ const Utils_1 = require("../sdk/Utils");
9
+ /**
10
+ * Thin Toncenter v3 indexer client for resolving indexed TON transaction context by hash and
11
+ * traversing a linked chain of TON transactions until it finds the sequencer-collected event transaction on CCL.
12
+ */
13
+ class ToncenterV3Indexer {
14
+ constructor(endpoint, httpClient = new AxiosHttpClient_1.AxiosHttpClient()) {
15
+ this.endpoint = endpoint;
16
+ this.httpClient = httpClient;
17
+ }
18
+ /**
19
+ * Queries Toncenter v3 indexed `/transactions` endpoint by hash and returns the first match.
20
+ * @param transactionHash TON transaction hash accepted by the indexer.
21
+ * @returns Indexed transaction with owning account context, or null on 404 / empty result.
22
+ */
23
+ async getTransactionByHash(transactionHash) {
24
+ const endpoint = this.endpoint.endsWith('/') ? `${this.endpoint}transactions` : `${this.endpoint}/transactions`;
25
+ const requestLabel = `GET ${endpoint}`;
26
+ try {
27
+ const response = await this.httpClient.get(endpoint, {
28
+ params: {
29
+ hash: transactionHash,
30
+ limit: 1,
31
+ },
32
+ transformResponse: [Utils_1.toCamelCaseTransformer],
33
+ });
34
+ return response.data.transactions?.[0] ?? null;
35
+ }
36
+ catch (error) {
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ if (error?.response?.status === 404) {
39
+ return null;
40
+ }
41
+ throw (0, errors_1.operationFetchError)(`request ${requestLabel} failed to resolve TON indexed transaction`, error);
42
+ }
43
+ }
44
+ /**
45
+ * Queries Toncenter v3 indexed `/adjacentTransactions` endpoint by hash.
46
+ * @param transactionHash TON transaction hash accepted by the indexer.
47
+ * @returns Adjacent indexed transactions, or an empty array on 404 / empty result.
48
+ */
49
+ async getAdjacentTransactions(transactionHash) {
50
+ const endpoint = this.endpoint.endsWith('/') ? `${this.endpoint}adjacentTransactions` : `${this.endpoint}/adjacentTransactions`;
51
+ const requestLabel = `GET ${endpoint}`;
52
+ try {
53
+ const response = await this.httpClient.get(endpoint, {
54
+ params: {
55
+ hash: transactionHash,
56
+ },
57
+ transformResponse: [Utils_1.toCamelCaseTransformer],
58
+ });
59
+ return response.data.transactions ?? [];
60
+ }
61
+ catch (error) {
62
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
+ if (error?.response?.status === 404) {
64
+ return [];
65
+ }
66
+ throw (0, errors_1.operationFetchError)(`request ${requestLabel} failed to resolve adjacent TON indexed transactions`, error);
67
+ }
68
+ }
69
+ /**
70
+ * Traverses the linked chain of TON transactions in both directions starting from any TON transaction hash
71
+ * from that linked transaction chain, and returns the transaction on crossChainLayer that the sequencer would collect
72
+ * as a TVM event.
73
+ * @param transactionHash Any TON transaction hash from the target linked chain of TON transactions.
74
+ * @param crossChainLayerAddress crossChainLayer address whose sequencer-collected event transaction should be found in that linked chain of TON transactions.
75
+ * @param params Optional traversal settings. Defaults match the SDK traversal defaults.
76
+ * @returns Indexed crossChainLayer transaction that matches the sequencer collector rules, or null if not found.
77
+ */
78
+ async findCollectibleCrossChainLayerTransaction(transactionHash, crossChainLayerAddress, params) {
79
+ const { maxDepth = Consts_1.DEFAULT_FIND_TX_MAX_DEPTH, maxScannedTransactions = Consts_1.DEFAULT_MAX_SCANNED_TRANSACTIONS, } = params ?? {};
80
+ const crossChainLayer = ton_1.Address.parse(crossChainLayerAddress);
81
+ const rootTransaction = await this.getTransactionByHash(transactionHash);
82
+ if (!rootTransaction) {
83
+ return null;
84
+ }
85
+ if (this.isCollectibleEventTransactionOnAccount(rootTransaction, crossChainLayer)) {
86
+ return rootTransaction;
87
+ }
88
+ const queue = [{ hash: rootTransaction.hash, depth: 0 }];
89
+ const visitedHashes = new Set([(0, Utils_1.normalizeHashToHex)(rootTransaction.hash)]);
90
+ let scannedTransactions = 0;
91
+ while (queue.length > 0) {
92
+ const { hash: currentHash, depth } = queue.shift();
93
+ if (depth >= maxDepth || scannedTransactions >= maxScannedTransactions) {
94
+ continue;
95
+ }
96
+ const adjacentTransactions = await this.getAdjacentTransactions(currentHash);
97
+ for (const transaction of adjacentTransactions) {
98
+ const normalizedHash = (0, Utils_1.normalizeHashToHex)(transaction.hash);
99
+ if (visitedHashes.has(normalizedHash)) {
100
+ continue;
101
+ }
102
+ visitedHashes.add(normalizedHash);
103
+ scannedTransactions += 1;
104
+ if (this.isCollectibleEventTransactionOnAccount(transaction, crossChainLayer)) {
105
+ return transaction;
106
+ }
107
+ if (scannedTransactions < maxScannedTransactions) {
108
+ queue.push({ hash: transaction.hash, depth: depth + 1 });
109
+ }
110
+ }
111
+ }
112
+ return null;
113
+ }
114
+ isCollectibleEventTransactionOnAccount(transaction, account) {
115
+ if (!ton_1.Address.parse(transaction.account).equals(account)) {
116
+ return false;
117
+ }
118
+ return transaction.outMsgs.some((message) => {
119
+ return message.destination == null;
120
+ });
121
+ }
122
+ }
123
+ exports.ToncenterV3Indexer = ToncenterV3Indexer;
@@ -3,5 +3,6 @@ export * from './LiteClientOpener';
3
3
  export * from './OpenerUtils';
4
4
  export * from './RetryableContractOpener';
5
5
  export * from './SandboxOpener';
6
+ export * from './ToncenterV3Indexer';
6
7
  export * from './TonClient4Opener';
7
8
  export * from './TonClientOpener';
@@ -19,5 +19,6 @@ __exportStar(require("./LiteClientOpener"), exports);
19
19
  __exportStar(require("./OpenerUtils"), exports);
20
20
  __exportStar(require("./RetryableContractOpener"), exports);
21
21
  __exportStar(require("./SandboxOpener"), exports);
22
+ __exportStar(require("./ToncenterV3Indexer"), exports);
22
23
  __exportStar(require("./TonClient4Opener"), exports);
23
24
  __exportStar(require("./TonClientOpener"), exports);
@@ -1,7 +1,10 @@
1
1
  import { Asset, IConfiguration } from '../interfaces';
2
2
  import { AssetFromFTArg, AssetFromNFTCollectionArg, AssetFromNFTItemArg, EVMAddress, NFTAddressType, TVMAddress } from '../structs/Struct';
3
+ import { FT } from './FT';
4
+ import { TAC } from './TAC';
5
+ import { TON } from './TON';
3
6
  export declare class AssetFactory {
4
7
  static from(configuration: IConfiguration, token: AssetFromFTArg | AssetFromNFTCollectionArg | AssetFromNFTItemArg): Promise<Asset>;
5
- static createFTAsset(configuration: IConfiguration, address: TVMAddress | EVMAddress): Promise<Asset>;
8
+ static createFTAsset(configuration: IConfiguration, address: TVMAddress | EVMAddress): Promise<FT | TAC | TON>;
6
9
  static createNFTAsset(configuration: IConfiguration, address: TVMAddress | EVMAddress, addressType: NFTAddressType, index?: bigint): Promise<Asset>;
7
10
  }
@@ -7,6 +7,7 @@ const Struct_1 = require("../structs/Struct");
7
7
  const AssetCache_1 = require("./AssetCache");
8
8
  const FT_1 = require("./FT");
9
9
  const NFT_1 = require("./NFT");
10
+ const TAC_1 = require("./TAC");
10
11
  const TON_1 = require("./TON");
11
12
  class AssetFactory {
12
13
  static async from(configuration, token) {
@@ -35,6 +36,9 @@ class AssetFactory {
35
36
  address === Consts_1.TON_BURN_ADDRESS) {
36
37
  return ton;
37
38
  }
39
+ if (address === (await configuration.nativeTACAddress())) {
40
+ return TAC_1.TAC.create(configuration);
41
+ }
38
42
  return FT_1.FT.fromAddress(configuration, address);
39
43
  }
40
44
  static async createNFTAsset(configuration, address, addressType, index) {
@@ -3,7 +3,7 @@ import { Cell, OpenedContract } from '@ton/ton';
3
3
  import { JettonMinterData, JettonWallet } from '../../artifacts/tonTypes';
4
4
  import { Asset, IConfiguration } from '../interfaces';
5
5
  import { AssetOpType } from '../structs/InternalStruct';
6
- import { AssetType, EVMAddress, FeeParams, FTOriginAndData, TVMAddress, UserWalletBalanceExtended } from '../structs/Struct';
6
+ import { AssetType, BlockchainType, EVMAddress, FeeParams, FTOriginAndData, TVMAddress, UserWalletBalanceExtended } from '../structs/Struct';
7
7
  import { Origin } from '../structs/Struct';
8
8
  export declare class FT implements Asset {
9
9
  private _tvmAddress;
@@ -55,8 +55,8 @@ export declare class FT implements Asset {
55
55
  getUserBalance(userAddress: string): Promise<bigint>;
56
56
  getUserBalanceExtended(userAddress: string): Promise<UserWalletBalanceExtended>;
57
57
  checkBalance(userAddress: string): Promise<void>;
58
- checkCanBeTransferredBy(userAddress: string): Promise<void>;
59
- getBalanceOf(userAddress: string): Promise<bigint>;
58
+ checkCanBeTransferredBy(userAddress: string, blockchainType?: BlockchainType): Promise<void>;
59
+ getBalanceOf(userAddress: string, blockchainType?: BlockchainType): Promise<bigint>;
60
60
  private getTransferPayload;
61
61
  private getBurnPayload;
62
62
  }
@@ -122,20 +122,18 @@ class FT {
122
122
  throw errors_1.missingJettonDataError;
123
123
  }
124
124
  const metadata = await (0, ContentUtils_1.readJettonMetadata)(jettonData.content);
125
- const decimalsRaw = metadata.metadata.decimals ?? Consts_1.TON_DECIMALS;
125
+ const decimalsRaw = metadata.metadata?.decimals ?? Consts_1.TON_DECIMALS;
126
126
  if (decimalsRaw === undefined) {
127
127
  throw errors_1.missingDecimals;
128
128
  }
129
129
  decimals = Number(decimalsRaw);
130
130
  }
131
131
  else {
132
- if ((0, ethers_1.isAddress)(address)) {
133
- finalEvmAddress = address;
134
- }
135
- else {
136
- finalEvmAddress = cachedEvmAddress || (await jettonMinter.getEVMTokenAddress());
137
- }
138
- decimals = await this.getTACDecimals(configuration, finalEvmAddress);
132
+ const resolvedEvmAddress = (0, ethers_1.isAddress)(address)
133
+ ? address
134
+ : (cachedEvmAddress ?? (await jettonMinter.getEVMTokenAddress()));
135
+ finalEvmAddress = resolvedEvmAddress;
136
+ decimals = await this.getTACDecimals(configuration, resolvedEvmAddress);
139
137
  }
140
138
  const token = new FT(tvmAddress, origin, configuration, decimals);
141
139
  if (finalEvmAddress || (0, ethers_1.isAddress)(address)) {
@@ -224,17 +222,19 @@ class FT {
224
222
  return this._evmAddress;
225
223
  }
226
224
  const tokenAddressString = this._tvmAddress.toString({ bounceable: true });
225
+ let evmAddress;
227
226
  if (this.origin === Struct_2.Origin.TON) {
228
- this._evmAddress = await this._configuration.TACParams.tokenUtils.computeAddress(tokenAddressString);
227
+ evmAddress = await this._configuration.TACParams.tokenUtils.computeAddress(tokenAddressString);
229
228
  }
230
229
  else if (this.origin === Struct_2.Origin.TAC) {
231
230
  const givenMinter = this._configuration.TONParams.contractOpener.open(this._configuration.artifacts.ton.wrappers.JettonMinter.createFromAddress(ton_1.Address.parse(tokenAddressString)));
232
- this._evmAddress = await givenMinter.getEVMTokenAddress();
231
+ evmAddress = await givenMinter.getEVMTokenAddress();
233
232
  }
234
233
  else {
235
234
  throw (0, errors_1.unknownTokenTypeError)(tokenAddressString, 'Token origin is neither TON nor TAC');
236
235
  }
237
- return this._evmAddress;
236
+ this._evmAddress = evmAddress;
237
+ return evmAddress;
238
238
  }
239
239
  async getTVMAddress() {
240
240
  return this._tvmAddress.toString({ bounceable: true });
@@ -290,11 +290,24 @@ class FT {
290
290
  throw (0, errors_1.insufficientBalanceError)(this._tvmAddress.toString());
291
291
  }
292
292
  }
293
- async checkCanBeTransferredBy(userAddress) {
294
- await this.checkBalance(userAddress);
293
+ async checkCanBeTransferredBy(userAddress, blockchainType = Struct_1.BlockchainType.TON) {
294
+ if ((await this.getBalanceOf(userAddress, blockchainType)) < this._transferAmount) {
295
+ throw (0, errors_1.insufficientBalanceError)(this._tvmAddress.toString());
296
+ }
295
297
  }
296
- async getBalanceOf(userAddress) {
297
- return this.getUserBalance(userAddress);
298
+ async getBalanceOf(userAddress, blockchainType = Struct_1.BlockchainType.TON) {
299
+ if (blockchainType === Struct_1.BlockchainType.TON) {
300
+ Validator_1.Validator.validateTVMAddress(userAddress);
301
+ return this.getUserBalance(userAddress);
302
+ }
303
+ Validator_1.Validator.validateEVMAddress(userAddress);
304
+ const evmAddress = await this.getEVMAddress();
305
+ const nativeTACAddress = await this._configuration.nativeTACAddress();
306
+ if (evmAddress === nativeTACAddress) {
307
+ return this._configuration.TACParams.provider.getBalance(userAddress);
308
+ }
309
+ const erc20Token = new ethers_1.ethers.Contract(evmAddress, this._configuration.artifacts.tac.compilationArtifacts.IERC20WithDecimals.abi, this._configuration.TACParams.provider);
310
+ return erc20Token.balanceOf(userAddress);
298
311
  }
299
312
  getTransferPayload(rawAmount, notificationReceiverAddress, responseAddress, evmData, crossChainTonAmount, forwardFeeAmount, feeData) {
300
313
  const queryId = (0, Utils_1.generateRandomNumberByTimestamp)().randomNumber;
@@ -1,7 +1,7 @@
1
1
  import { Cell } from '@ton/ton';
2
2
  import { NFTCollectionData, NFTItemData } from '../../artifacts/tonTypes';
3
3
  import { Asset, IConfiguration } from '../interfaces';
4
- import { AssetType, EVMAddress, FeeParams, Origin, TVMAddress } from '../structs/Struct';
4
+ import { AssetType, BlockchainType, EVMAddress, FeeParams, Origin, TVMAddress } from '../structs/Struct';
5
5
  export declare class NFT implements Asset {
6
6
  private readonly _addresses;
7
7
  readonly origin: Origin;
@@ -61,8 +61,8 @@ export declare class NFT implements Asset {
61
61
  feeParams?: FeeParams;
62
62
  }): Cell;
63
63
  isOwnedBy(userAddress: string): Promise<boolean>;
64
- checkCanBeTransferredBy(userAddress: string): Promise<void>;
65
- getBalanceOf(userAddress: string): Promise<bigint>;
64
+ checkCanBeTransferredBy(userAddress: string, blockchainType?: BlockchainType): Promise<void>;
65
+ getBalanceOf(userAddress: string, blockchainType?: BlockchainType): Promise<bigint>;
66
66
  private getBurnPayload;
67
67
  private getTransferPayload;
68
68
  }
@@ -207,13 +207,19 @@ class NFT {
207
207
  const nftData = await NFT.getItemData(this._configuration, this.address.toString());
208
208
  return !!nftData.ownerAddress?.equals(ton_1.Address.parse(userAddress));
209
209
  }
210
- async checkCanBeTransferredBy(userAddress) {
211
- if (!(await this.isOwnedBy(userAddress))) {
210
+ async checkCanBeTransferredBy(userAddress, blockchainType = Struct_1.BlockchainType.TON) {
211
+ if ((await this.getBalanceOf(userAddress, blockchainType)) < 1n) {
212
212
  throw (0, errors_1.insufficientBalanceError)(this.address.toString());
213
213
  }
214
214
  }
215
- async getBalanceOf(userAddress) {
216
- return (await this.isOwnedBy(userAddress)) ? 1n : 0n;
215
+ async getBalanceOf(userAddress, blockchainType = Struct_1.BlockchainType.TON) {
216
+ if (blockchainType === Struct_1.BlockchainType.TON) {
217
+ Validator_1.Validator.validateTVMAddress(userAddress);
218
+ return (await this.isOwnedBy(userAddress)) ? 1n : 0n;
219
+ }
220
+ Validator_1.Validator.validateEVMAddress(userAddress);
221
+ const nft = new ethers_1.ethers.Contract(await this.getEVMAddress(), this._configuration.artifacts.tac.compilationArtifacts.IERC721.abi, this._configuration.TACParams.provider);
222
+ return (await nft.ownerOf(this._addresses.index)).toLowerCase() === userAddress.toLowerCase() ? 1n : 0n;
217
223
  }
218
224
  getBurnPayload(crossChainLayerAddress, evmData, crossChainTonAmount, feeData) {
219
225
  const queryId = (0, Utils_1.generateRandomNumberByTimestamp)().randomNumber;
@@ -0,0 +1,24 @@
1
+ import type { Cell } from '@ton/ton';
2
+ import { Asset, IConfiguration } from '../interfaces';
3
+ import { AssetType, BlockchainType, GeneratePayloadParams, Origin } from '../structs/Struct';
4
+ export declare class TAC implements Asset {
5
+ private readonly _configuration;
6
+ private readonly _evmAddress;
7
+ private _wrappedAsset;
8
+ readonly type: AssetType;
9
+ readonly origin: Origin;
10
+ private constructor();
11
+ static create(configuration: IConfiguration): Promise<TAC>;
12
+ get address(): string;
13
+ get rawAmount(): bigint;
14
+ get clone(): TAC;
15
+ withAmount(amount: number): TAC;
16
+ withRawAmount(rawAmount: bigint): TAC;
17
+ addAmount(amount: number): TAC;
18
+ addRawAmount(rawAmount: bigint): TAC;
19
+ getEVMAddress(): Promise<string>;
20
+ getTVMAddress(): Promise<string>;
21
+ generatePayload(params: GeneratePayloadParams): Cell;
22
+ checkCanBeTransferredBy(userAddress: string, blockchainType?: BlockchainType): Promise<void>;
23
+ getBalanceOf(userAddress: string, blockchainType?: BlockchainType): Promise<bigint>;
24
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TAC = void 0;
4
+ const errors_1 = require("../errors");
5
+ const Validator_1 = require("../sdk/Validator");
6
+ const Struct_1 = require("../structs/Struct");
7
+ const FT_1 = require("./FT");
8
+ class TAC {
9
+ constructor(_configuration, _evmAddress, _wrappedAsset) {
10
+ this._configuration = _configuration;
11
+ this._evmAddress = _evmAddress;
12
+ this._wrappedAsset = _wrappedAsset;
13
+ this.type = Struct_1.AssetType.FT;
14
+ this.origin = Struct_1.Origin.TAC;
15
+ }
16
+ static async create(configuration) {
17
+ const evmAddress = await configuration.nativeTACAddress();
18
+ const wrappedAsset = await FT_1.FT.fromAddress(configuration, evmAddress);
19
+ return new TAC(configuration, evmAddress, wrappedAsset);
20
+ }
21
+ get address() {
22
+ return this._wrappedAsset.address;
23
+ }
24
+ get rawAmount() {
25
+ return this._wrappedAsset.rawAmount;
26
+ }
27
+ get clone() {
28
+ return new TAC(this._configuration, this._evmAddress, this._wrappedAsset.clone);
29
+ }
30
+ withAmount(amount) {
31
+ const nextWrappedAsset = this._wrappedAsset.withAmount(amount);
32
+ if (nextWrappedAsset === this._wrappedAsset) {
33
+ return this;
34
+ }
35
+ return new TAC(this._configuration, this._evmAddress, nextWrappedAsset);
36
+ }
37
+ withRawAmount(rawAmount) {
38
+ const nextWrappedAsset = this._wrappedAsset.withRawAmount(rawAmount);
39
+ if (nextWrappedAsset === this._wrappedAsset) {
40
+ return this;
41
+ }
42
+ return new TAC(this._configuration, this._evmAddress, nextWrappedAsset);
43
+ }
44
+ addAmount(amount) {
45
+ this._wrappedAsset = this._wrappedAsset.addAmount(amount);
46
+ return this;
47
+ }
48
+ addRawAmount(rawAmount) {
49
+ this._wrappedAsset = this._wrappedAsset.addRawAmount(rawAmount);
50
+ return this;
51
+ }
52
+ async getEVMAddress() {
53
+ return this._evmAddress;
54
+ }
55
+ async getTVMAddress() {
56
+ return this.address;
57
+ }
58
+ generatePayload(params) {
59
+ return this._wrappedAsset.generatePayload(params);
60
+ }
61
+ async checkCanBeTransferredBy(userAddress, blockchainType = Struct_1.BlockchainType.TON) {
62
+ if ((await this.getBalanceOf(userAddress, blockchainType)) < this.rawAmount) {
63
+ throw (0, errors_1.insufficientBalanceError)(this.address);
64
+ }
65
+ }
66
+ async getBalanceOf(userAddress, blockchainType = Struct_1.BlockchainType.TON) {
67
+ if (blockchainType === Struct_1.BlockchainType.TAC) {
68
+ Validator_1.Validator.validateEVMAddress(userAddress);
69
+ return this._configuration.TACParams.provider.getBalance(userAddress);
70
+ }
71
+ return this._wrappedAsset.getBalanceOf(userAddress, blockchainType);
72
+ }
73
+ }
74
+ exports.TAC = TAC;
@@ -2,7 +2,7 @@ import { Cell } from '@ton/ton';
2
2
  import { Asset, IConfiguration } from '../interfaces';
3
3
  import type { SenderAbstraction } from '../sender';
4
4
  import type { ShardTransaction } from '../structs/InternalStruct';
5
- import { AssetType, FeeParams, Origin } from '../structs/Struct';
5
+ import { AssetType, BlockchainType, FeeParams, Origin } from '../structs/Struct';
6
6
  export declare class TON implements Asset {
7
7
  readonly address: string;
8
8
  readonly type: AssetType;
@@ -29,6 +29,6 @@ export declare class TON implements Asset {
29
29
  }): Cell;
30
30
  getUserBalance(userAddress: string): Promise<bigint>;
31
31
  static checkBalance(sender: SenderAbstraction, config: IConfiguration, transactions: ShardTransaction[]): Promise<void>;
32
- checkCanBeTransferredBy(userAddress: string): Promise<void>;
33
- getBalanceOf(userAddress: string): Promise<bigint>;
32
+ checkCanBeTransferredBy(userAddress: string, blockchainType?: BlockchainType): Promise<void>;
33
+ getBalanceOf(userAddress: string, blockchainType?: BlockchainType): Promise<bigint>;
34
34
  }