@tonappchain/sdk 0.7.2-alpha-15 → 0.7.2-alpha-16

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.
@@ -1,23 +1,23 @@
1
1
  import { Asset } from '../interfaces';
2
+ type AssetCacheToken = {
3
+ address: string;
4
+ index?: bigint;
5
+ tokenType?: string;
6
+ };
2
7
  export declare class AssetCache {
3
8
  private static readonly cache;
4
9
  /**
5
10
  * Get asset from cache
6
11
  */
7
- static get(token: {
8
- address: string;
9
- index?: bigint;
10
- }): Asset | undefined;
12
+ static get(token: AssetCacheToken): Asset | undefined;
11
13
  /**
12
14
  * Set asset in cache
13
15
  */
14
- static set(token: {
15
- address: string;
16
- index?: bigint;
17
- }, asset: Asset): void;
16
+ static set(token: AssetCacheToken, asset: Asset): void;
18
17
  /**
19
18
  * Clear the cache
20
19
  */
21
20
  static clear(): void;
22
21
  private static generateKey;
23
22
  }
23
+ export {};
@@ -26,6 +26,9 @@ class AssetCache {
26
26
  // Normalize address to lowercase for consistency
27
27
  const normalizedAddress = token.address.toLowerCase();
28
28
  const parts = [normalizedAddress];
29
+ if (token.tokenType !== undefined) {
30
+ parts.push(token.tokenType);
31
+ }
29
32
  if (token.index !== undefined) {
30
33
  parts.push(token.index.toString());
31
34
  }
@@ -7,7 +7,15 @@ export declare class ContractError extends ErrorWithStatusCode {
7
7
  }
8
8
  export declare class FetchError extends ErrorWithStatusCode {
9
9
  readonly inner?: unknown;
10
- constructor(message: string, errorCode: number, inner?: unknown);
10
+ readonly httpStatus?: number;
11
+ readonly innerErrorCode?: number;
12
+ readonly innerErrorName?: string;
13
+ readonly innerMessage?: string;
14
+ readonly innerStack?: string;
15
+ constructor(message: string, errorCode: number, inner?: unknown, options?: {
16
+ includeInnerStack?: boolean;
17
+ });
18
+ toDebugString(includeTrace?: boolean): string;
11
19
  }
12
20
  export declare class AddressError extends ErrorWithStatusCode {
13
21
  constructor(message: string, errorCode: number);
@@ -16,10 +16,50 @@ class ContractError extends ErrorWithStatusCode {
16
16
  }
17
17
  exports.ContractError = ContractError;
18
18
  class FetchError extends ErrorWithStatusCode {
19
- constructor(message, errorCode, inner) {
19
+ constructor(message, errorCode, inner, options) {
20
20
  super(message, errorCode);
21
21
  this.name = 'FetchError';
22
22
  this.inner = inner;
23
+ if (inner && typeof inner === 'object') {
24
+ const err = inner;
25
+ if (typeof err.status === 'number') {
26
+ this.httpStatus = err.status;
27
+ }
28
+ else if (typeof err.response?.status === 'number') {
29
+ this.httpStatus = err.response.status;
30
+ }
31
+ if (typeof err.errorCode === 'number') {
32
+ this.innerErrorCode = err.errorCode;
33
+ }
34
+ if (typeof err.name === 'string') {
35
+ this.innerErrorName = err.name;
36
+ }
37
+ if (typeof err.message === 'string') {
38
+ this.innerMessage = err.message;
39
+ }
40
+ if (options?.includeInnerStack && typeof err.stack === 'string') {
41
+ this.innerStack = err.stack;
42
+ }
43
+ }
44
+ }
45
+ toDebugString(includeTrace = false) {
46
+ const parts = [`${this.name} (${this.errorCode}): ${this.message}`];
47
+ if (this.httpStatus !== undefined) {
48
+ parts.push(`httpStatus: ${this.httpStatus}`);
49
+ }
50
+ if (this.innerErrorCode !== undefined) {
51
+ parts.push(`innerErrorCode: ${this.innerErrorCode}`);
52
+ }
53
+ if (this.innerErrorName) {
54
+ parts.push(`innerErrorName: ${this.innerErrorName}`);
55
+ }
56
+ if (this.innerMessage) {
57
+ parts.push(`innerMessage: ${this.innerMessage}`);
58
+ }
59
+ if (includeTrace && this.innerStack) {
60
+ parts.push(`innerStack:\n${this.innerStack}`);
61
+ }
62
+ return parts.join('\n');
23
63
  }
24
64
  }
25
65
  exports.FetchError = FetchError;
@@ -1,2 +1,2 @@
1
1
  export { AddressError, BitError, ContractError, EVMCallError, FetchError, FormatError, KeyError, MetadataError, SettingError, TokenError, TransactionError, WalletError, } from './errors';
2
- export { allEndpointsFailedError, emptyArrayError, emptyContractError, emptySettingError, evmAddressError, indexRequiredError, insufficientBalanceError, invalidMethodNameError, missingDecimals, missingFeeParamsError, missingGasLimitError, missingJettonDataError, missingTvmExecutorFeeError, notMultiplyOf8Error, operationFetchError, prefixError, profilingFetchError, simulationFetchError, statusFetchError, tvmAddressError, txFinalizationError, unknownTokenTypeError, unknownWalletError, unsupportedFormatError, unsupportedKeyError, zeroRawAmountError, } from './instances';
2
+ export { allEndpointsFailedError, emptyArrayError, emptyContractError, emptySettingError, evmAddressError, indexRequiredError, insufficientBalanceError, insufficientFeeParamsError, invalidMethodNameError, missingDecimals, missingFeeParamsError, missingGasLimitError, missingJettonDataError, missingTvmExecutorFeeError, notMultiplyOf8Error, operationFetchError, prefixError, profilingFetchError, simulationFetchError, statusFetchError, tvmAddressError, txFinalizationError, unknownTokenTypeError, unknownWalletError, unsupportedFormatError, unsupportedKeyError, zeroRawAmountError, } from './instances';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.zeroRawAmountError = exports.unsupportedKeyError = exports.unsupportedFormatError = exports.unknownWalletError = exports.unknownTokenTypeError = exports.txFinalizationError = exports.tvmAddressError = exports.statusFetchError = exports.simulationFetchError = exports.profilingFetchError = exports.prefixError = exports.operationFetchError = exports.notMultiplyOf8Error = exports.missingTvmExecutorFeeError = exports.missingJettonDataError = exports.missingGasLimitError = exports.missingFeeParamsError = exports.missingDecimals = exports.invalidMethodNameError = exports.insufficientBalanceError = exports.indexRequiredError = exports.evmAddressError = exports.emptySettingError = exports.emptyContractError = exports.emptyArrayError = exports.allEndpointsFailedError = exports.WalletError = exports.TransactionError = exports.TokenError = exports.SettingError = exports.MetadataError = exports.KeyError = exports.FormatError = exports.FetchError = exports.EVMCallError = exports.ContractError = exports.BitError = exports.AddressError = void 0;
3
+ exports.zeroRawAmountError = exports.unsupportedKeyError = exports.unsupportedFormatError = exports.unknownWalletError = exports.unknownTokenTypeError = exports.txFinalizationError = exports.tvmAddressError = exports.statusFetchError = exports.simulationFetchError = exports.profilingFetchError = exports.prefixError = exports.operationFetchError = exports.notMultiplyOf8Error = exports.missingTvmExecutorFeeError = exports.missingJettonDataError = exports.missingGasLimitError = exports.missingFeeParamsError = exports.missingDecimals = exports.invalidMethodNameError = exports.insufficientFeeParamsError = exports.insufficientBalanceError = exports.indexRequiredError = exports.evmAddressError = exports.emptySettingError = exports.emptyContractError = exports.emptyArrayError = exports.allEndpointsFailedError = exports.WalletError = exports.TransactionError = exports.TokenError = exports.SettingError = exports.MetadataError = exports.KeyError = exports.FormatError = exports.FetchError = exports.EVMCallError = exports.ContractError = exports.BitError = exports.AddressError = void 0;
4
4
  var errors_1 = require("./errors");
5
5
  Object.defineProperty(exports, "AddressError", { enumerable: true, get: function () { return errors_1.AddressError; } });
6
6
  Object.defineProperty(exports, "BitError", { enumerable: true, get: function () { return errors_1.BitError; } });
@@ -22,6 +22,7 @@ Object.defineProperty(exports, "emptySettingError", { enumerable: true, get: fun
22
22
  Object.defineProperty(exports, "evmAddressError", { enumerable: true, get: function () { return instances_1.evmAddressError; } });
23
23
  Object.defineProperty(exports, "indexRequiredError", { enumerable: true, get: function () { return instances_1.indexRequiredError; } });
24
24
  Object.defineProperty(exports, "insufficientBalanceError", { enumerable: true, get: function () { return instances_1.insufficientBalanceError; } });
25
+ Object.defineProperty(exports, "insufficientFeeParamsError", { enumerable: true, get: function () { return instances_1.insufficientFeeParamsError; } });
25
26
  Object.defineProperty(exports, "invalidMethodNameError", { enumerable: true, get: function () { return instances_1.invalidMethodNameError; } });
26
27
  Object.defineProperty(exports, "missingDecimals", { enumerable: true, get: function () { return instances_1.missingDecimals; } });
27
28
  Object.defineProperty(exports, "missingFeeParamsError", { enumerable: true, get: function () { return instances_1.missingFeeParamsError; } });
@@ -17,7 +17,7 @@ export declare const emptyArrayError: (msg: string) => FetchError;
17
17
  export declare const invalidAssetType: FormatError;
18
18
  export declare const prepareMessageGroupError: (isBocSizeValid: boolean, isDepthValid: boolean) => PrepareMessageGroupError;
19
19
  export declare const noValidGroupFoundError: NoValidGroupFoundError;
20
- export declare const allEndpointsFailedError: (inner: unknown) => FetchError;
20
+ export declare const allEndpointsFailedError: (inner: unknown, includeInnerStack?: boolean) => FetchError;
21
21
  export declare const allContractOpenerFailedError: (inner: unknown) => FetchError;
22
22
  export declare const insufficientBalanceError: (token: string) => InsufficientBalanceError;
23
23
  export declare const unknownTokenTypeError: (token: string, reason?: string) => TokenError;
@@ -36,3 +36,4 @@ export declare const convertCurrencyNegativeOrZeroValueError: FormatError;
36
36
  export declare const unknownAssetOriginError: (origin: Origin) => TokenError;
37
37
  export declare const gasPriceFetchError: (msg: string, inner?: unknown) => FetchError;
38
38
  export declare const txFinalizationError: (msg: string) => TransactionError;
39
+ export declare const insufficientFeeParamsError: (feeName: string, provided: bigint, required: bigint) => FormatError;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.txFinalizationError = exports.gasPriceFetchError = exports.unknownAssetOriginError = exports.convertCurrencyNegativeOrZeroValueError = exports.sendCrossChainTransactionFailedError = exports.zeroRawAmountError = exports.missingJettonDataError = exports.missingDecimals = exports.missingGasLimitError = exports.missingTvmExecutorFeeError = exports.missingFeeParamsError = exports.getTONFeeInfoFetchError = exports.simulationFetchError = exports.convertCurrencyFetchError = exports.indexRequiredError = exports.unknownTokenTypeError = exports.insufficientBalanceError = exports.allContractOpenerFailedError = exports.allEndpointsFailedError = exports.noValidGroupFoundError = exports.prepareMessageGroupError = exports.invalidAssetType = exports.emptyArrayError = exports.profilingFetchError = exports.invalidMethodNameError = exports.emptySettingError = exports.prefixError = exports.notMultiplyOf8Error = exports.unsupportedFormatError = exports.unsupportedKeyError = exports.unknownWalletError = exports.evmAddressError = exports.tvmAddressError = exports.statusFetchError = exports.operationFetchError = exports.emptyContractError = void 0;
3
+ exports.insufficientFeeParamsError = exports.txFinalizationError = exports.gasPriceFetchError = exports.unknownAssetOriginError = exports.convertCurrencyNegativeOrZeroValueError = exports.sendCrossChainTransactionFailedError = exports.zeroRawAmountError = exports.missingJettonDataError = exports.missingDecimals = exports.missingGasLimitError = exports.missingTvmExecutorFeeError = exports.missingFeeParamsError = exports.getTONFeeInfoFetchError = exports.simulationFetchError = exports.convertCurrencyFetchError = exports.indexRequiredError = exports.unknownTokenTypeError = exports.insufficientBalanceError = exports.allContractOpenerFailedError = exports.allEndpointsFailedError = exports.noValidGroupFoundError = exports.prepareMessageGroupError = exports.invalidAssetType = exports.emptyArrayError = exports.profilingFetchError = exports.invalidMethodNameError = exports.emptySettingError = exports.prefixError = exports.notMultiplyOf8Error = exports.unsupportedFormatError = exports.unsupportedKeyError = exports.unknownWalletError = exports.evmAddressError = exports.tvmAddressError = exports.statusFetchError = exports.operationFetchError = exports.emptyContractError = void 0;
4
4
  const errors_1 = require("./errors");
5
5
  exports.emptyContractError = new errors_1.ContractError('unexpected empty contract code of given jetton.', 100);
6
6
  const operationFetchError = (msg, inner) => new errors_1.FetchError(`failed to fetch OperationId: ${msg}`, 101, inner);
@@ -30,7 +30,39 @@ exports.invalidAssetType = new errors_1.FormatError('Invalid asset type', 114);
30
30
  const prepareMessageGroupError = (isBocSizeValid, isDepthValid) => new errors_1.PrepareMessageGroupError(`Failed to prepare message group: BOC size valid: ${isBocSizeValid}, depth valid: ${isDepthValid}`, 115);
31
31
  exports.prepareMessageGroupError = prepareMessageGroupError;
32
32
  exports.noValidGroupFoundError = new errors_1.NoValidGroupFoundError('Failed to prepare valid message group', 116);
33
- const allEndpointsFailedError = (inner) => new errors_1.FetchError('All endpoints failed, last err: ' + inner.message, 117, inner);
33
+ function buildInnerErrorSummary(inner) {
34
+ if (inner && typeof inner === 'object') {
35
+ const err = inner;
36
+ const parts = [];
37
+ const httpStatus = typeof err.status === 'number'
38
+ ? err.status
39
+ : typeof err.response?.status === 'number'
40
+ ? err.response.status
41
+ : undefined;
42
+ if (typeof httpStatus === 'number') {
43
+ parts.push(`httpStatus=${httpStatus}`);
44
+ }
45
+ if (typeof err.errorCode === 'number') {
46
+ parts.push(`code=${err.errorCode}`);
47
+ }
48
+ if (typeof err.name === 'string' && err.name.length > 0) {
49
+ parts.push(`name=${err.name}`);
50
+ }
51
+ if (typeof err.message === 'string' && err.message.length > 0) {
52
+ parts.push(`message=${err.message}`);
53
+ }
54
+ if (parts.length > 0) {
55
+ return parts.join(', ');
56
+ }
57
+ }
58
+ if (typeof inner === 'string' && inner.length > 0) {
59
+ return `message=${inner}`;
60
+ }
61
+ return 'message=unknown error';
62
+ }
63
+ const allEndpointsFailedError = (inner, includeInnerStack = false) => new errors_1.FetchError(`All endpoints failed, last err: ${buildInnerErrorSummary(inner)}`, 117, inner, {
64
+ includeInnerStack,
65
+ });
34
66
  exports.allEndpointsFailedError = allEndpointsFailedError;
35
67
  const allContractOpenerFailedError = (inner) => new errors_1.FetchError('All contract opener failed', 118, inner);
36
68
  exports.allContractOpenerFailedError = allContractOpenerFailedError;
@@ -62,3 +94,5 @@ const gasPriceFetchError = (msg, inner) => new errors_1.FetchError(`Failed to fe
62
94
  exports.gasPriceFetchError = gasPriceFetchError;
63
95
  const txFinalizationError = (msg) => new errors_1.TransactionError(`Transaction failed: ${msg}`, 135);
64
96
  exports.txFinalizationError = txFinalizationError;
97
+ const insufficientFeeParamsError = (feeName, provided, required) => new errors_1.FormatError(`Provided ${feeName} (${provided}) is lower than required (${required}). Set shouldValidateFees: false to bypass.`, 136);
98
+ exports.insufficientFeeParamsError = insufficientFeeParamsError;
@@ -10,7 +10,7 @@ export declare class Configuration implements IConfiguration {
10
10
  readonly liteSequencerEndpoints: string[];
11
11
  readonly logger: ILogger;
12
12
  constructor(network: Network, artifacts: typeof testnet | typeof mainnet | typeof dev, TONParams: InternalTONParams, TACParams: InternalTACParams, liteSequencerEndpoints: string[], logger: ILogger);
13
- static create(network: Network, artifacts: typeof testnet | typeof mainnet | typeof dev, TONParams?: TONParams, TACParams?: TACParams, customLiteSequencerEndpoints?: string[], delay?: number, logger?: ILogger): Promise<Configuration>;
13
+ static create(network: Network, artifacts: typeof testnet | typeof mainnet | typeof dev, TONParams?: TONParams, TACParams?: TACParams, customLiteSequencerEndpoints?: string[], delay?: number, logger?: ILogger, passLoggerToOpeners?: boolean): Promise<Configuration>;
14
14
  private static prepareTONParams;
15
15
  private static prepareTACParams;
16
16
  private static loadTACSettingsViaMulticall;
@@ -10,6 +10,7 @@ const Fees_1 = require("./Fees");
10
10
  const Logger_1 = require("./Logger");
11
11
  const Utils_1 = require("./Utils");
12
12
  const Validator_1 = require("./Validator");
13
+ const Consts_1 = require("./Consts");
13
14
  class Configuration {
14
15
  constructor(network, artifacts, TONParams, TACParams, liteSequencerEndpoints, logger) {
15
16
  this.network = network;
@@ -19,9 +20,9 @@ class Configuration {
19
20
  this.liteSequencerEndpoints = liteSequencerEndpoints;
20
21
  this.logger = logger;
21
22
  }
22
- static async create(network, artifacts, TONParams, TACParams, customLiteSequencerEndpoints, delay, logger = new Logger_1.NoopLogger()) {
23
+ static async create(network, artifacts, TONParams, TACParams, customLiteSequencerEndpoints, delay, logger = new Logger_1.NoopLogger(), passLoggerToOpeners = true) {
23
24
  const [internalTONParams, internalTACParams] = await Promise.all([
24
- this.prepareTONParams(network, artifacts, TONParams, delay, logger),
25
+ this.prepareTONParams(network, artifacts, TONParams, delay, logger, passLoggerToOpeners),
25
26
  this.prepareTACParams(network, TACParams),
26
27
  ]);
27
28
  let liteSequencerEndpoints;
@@ -36,7 +37,7 @@ class Configuration {
36
37
  }
37
38
  return new Configuration(network, artifacts, internalTONParams, internalTACParams, liteSequencerEndpoints, logger);
38
39
  }
39
- static async prepareTONParams(network, artifacts, TONParams, delay, logger = new Logger_1.NoopLogger()) {
40
+ static async prepareTONParams(network, artifacts, TONParams, delay, logger = new Logger_1.NoopLogger(), passLoggerToOpeners = true) {
40
41
  let contractOpener;
41
42
  let settingsAddress;
42
43
  if (network === Struct_1.Network.DEV) {
@@ -52,10 +53,12 @@ class Configuration {
52
53
  else {
53
54
  contractOpener =
54
55
  TONParams?.contractOpener ??
55
- (await (0, adapters_1.createDefaultRetryableOpener)(artifacts.TON_RPC_ENDPOINT_BY_TAC, network, 5, delay, logger));
56
+ (await (0, adapters_1.createDefaultRetryableOpener)(artifacts.TON_RPC_ENDPOINT_BY_TAC, network, Consts_1.DEFAULT_RETRY_MAX_COUNT, delay, passLoggerToOpeners ? logger : undefined));
56
57
  settingsAddress = TONParams?.settingsAddress ?? artifacts.TON_SETTINGS_ADDRESS;
57
58
  }
58
- contractOpener.setLogger(logger);
59
+ if (passLoggerToOpeners) {
60
+ contractOpener.setLogger(logger);
61
+ }
59
62
  const settings = contractOpener.open(artifacts.ton.wrappers.Settings.createFromAddress(ton_1.Address.parse(settingsAddress)));
60
63
  const allSettingsSlice = (await settings.getAll()).beginParse();
61
64
  const allSettings = allSettingsSlice.loadDictDirect(ton_1.Dictionary.Keys.BigUint(256), ton_1.Dictionary.Values.Cell());
@@ -5,6 +5,7 @@ export declare class LiteSequencerClient implements ILiteSequencerClient {
5
5
  private readonly maxChunkSize;
6
6
  private readonly httpClient;
7
7
  constructor(endpoint: string, maxChunkSize?: number, httpClient?: IHttpClient);
8
+ private getRequestLabel;
8
9
  getOperationIdByTransactionHash(transactionHash: string): Promise<string>;
9
10
  getOperationType(operationId: string): Promise<OperationType>;
10
11
  getOperationId(transactionLinker: TransactionLinker): Promise<string>;
@@ -11,9 +11,13 @@ class LiteSequencerClient {
11
11
  this.maxChunkSize = maxChunkSize;
12
12
  this.httpClient = httpClient;
13
13
  }
14
+ getRequestLabel(method, path) {
15
+ return `${method} ${new URL(path, this.endpoint).toString()}`;
16
+ }
14
17
  async getOperationIdByTransactionHash(transactionHash) {
15
18
  const isEthHash = /^0x[a-fA-F0-9]{64}$/.test(transactionHash);
16
19
  const path = isEthHash ? 'tac/operation-id' : 'ton/operation-id';
20
+ const requestLabel = this.getRequestLabel('GET', path);
17
21
  try {
18
22
  if (isEthHash) {
19
23
  const response = await this.httpClient.get(new URL(path, this.endpoint).toString(), {
@@ -33,12 +37,14 @@ class LiteSequencerClient {
33
37
  if (error?.response?.status === 404) {
34
38
  return '';
35
39
  }
36
- throw (0, errors_1.operationFetchError)(`endpoint ${this.endpoint} failed to complete request`, error);
40
+ throw (0, errors_1.operationFetchError)(`request ${requestLabel} failed to complete request`, error);
37
41
  }
38
42
  }
39
43
  async getOperationType(operationId) {
44
+ const path = 'operation-type';
45
+ const requestLabel = this.getRequestLabel('GET', path);
40
46
  try {
41
- const response = await this.httpClient.get(new URL('operation-type', this.endpoint).toString(), {
47
+ const response = await this.httpClient.get(new URL(path, this.endpoint).toString(), {
42
48
  params: {
43
49
  operationId,
44
50
  },
@@ -46,10 +52,12 @@ class LiteSequencerClient {
46
52
  return response.data.response || '';
47
53
  }
48
54
  catch (error) {
49
- throw (0, errors_1.operationFetchError)(`endpoint ${this.endpoint} failed to complete request`, error);
55
+ throw (0, errors_1.operationFetchError)(`request ${requestLabel} failed to complete request`, error);
50
56
  }
51
57
  }
52
58
  async getOperationId(transactionLinker) {
59
+ const path = 'ton/operation-id';
60
+ const requestLabel = this.getRequestLabel('POST', path);
53
61
  const requestBody = {
54
62
  shardsKey: transactionLinker.shardsKey,
55
63
  caller: transactionLinker.caller,
@@ -57,7 +65,7 @@ class LiteSequencerClient {
57
65
  timestamp: transactionLinker.timestamp,
58
66
  };
59
67
  try {
60
- const response = await this.httpClient.post(new URL('ton/operation-id', this.endpoint).toString(), requestBody);
68
+ const response = await this.httpClient.post(new URL(path, this.endpoint).toString(), requestBody);
61
69
  return response.data.response || '';
62
70
  }
63
71
  catch (error) {
@@ -65,16 +73,18 @@ class LiteSequencerClient {
65
73
  if (error?.response?.status === 404) {
66
74
  return '';
67
75
  }
68
- throw (0, errors_1.operationFetchError)(`endpoint ${this.endpoint} failed to complete request`, error);
76
+ throw (0, errors_1.operationFetchError)(`request ${requestLabel} failed to complete request`, error);
69
77
  }
70
78
  }
71
79
  async getOperationIdsByShardsKeys(shardsKeys, caller, chunkSize = this.maxChunkSize) {
80
+ const path = 'operation-ids-by-shards-keys';
81
+ const requestLabel = this.getRequestLabel('POST', path);
72
82
  if (!shardsKeys || shardsKeys.length === 0) {
73
83
  throw (0, errors_1.emptyArrayError)('shardsKeys');
74
84
  }
75
85
  try {
76
86
  const response = await this.processChunkedRequest(shardsKeys, async (chunk) => {
77
- const response = await this.httpClient.post(new URL('operation-ids-by-shards-keys', this.endpoint).toString(), {
87
+ const response = await this.httpClient.post(new URL(path, this.endpoint).toString(), {
78
88
  shardsKeys: chunk,
79
89
  caller: caller,
80
90
  });
@@ -83,16 +93,18 @@ class LiteSequencerClient {
83
93
  return response.response;
84
94
  }
85
95
  catch (error) {
86
- throw (0, errors_1.operationFetchError)(`endpoint ${this.endpoint} failed to complete request`, error);
96
+ throw (0, errors_1.operationFetchError)(`request ${requestLabel} failed to complete request`, error);
87
97
  }
88
98
  }
89
99
  async getStageProfilings(operationIds, chunkSize = this.maxChunkSize) {
100
+ const path = 'stage-profiling';
101
+ const requestLabel = this.getRequestLabel('POST', path);
90
102
  if (!operationIds || operationIds.length === 0) {
91
103
  throw (0, errors_1.emptyArrayError)('operationIds');
92
104
  }
93
105
  try {
94
106
  const response = await this.processChunkedRequest(operationIds, async (chunk) => {
95
- const response = await this.httpClient.post(new URL('stage-profiling', this.endpoint).toString(), {
107
+ const response = await this.httpClient.post(new URL(path, this.endpoint).toString(), {
96
108
  operationIds: chunk,
97
109
  }, {
98
110
  transformResponse: [Utils_1.toCamelCaseTransformer],
@@ -102,16 +114,18 @@ class LiteSequencerClient {
102
114
  return response.response;
103
115
  }
104
116
  catch (error) {
105
- throw (0, errors_1.profilingFetchError)(`endpoint ${this.endpoint} failed to complete request`, error);
117
+ throw (0, errors_1.profilingFetchError)(`request ${requestLabel} failed to complete request`, error);
106
118
  }
107
119
  }
108
120
  async getOperationStatuses(operationIds, chunkSize = this.maxChunkSize) {
121
+ const path = 'status';
122
+ const requestLabel = this.getRequestLabel('POST', path);
109
123
  if (!operationIds || operationIds.length === 0) {
110
124
  throw (0, errors_1.emptyArrayError)('operationIds');
111
125
  }
112
126
  try {
113
127
  const response = await this.processChunkedRequest(operationIds, async (chunk) => {
114
- const response = await this.httpClient.post(new URL('status', this.endpoint).toString(), {
128
+ const response = await this.httpClient.post(new URL(path, this.endpoint).toString(), {
115
129
  operationIds: chunk,
116
130
  }, {
117
131
  transformResponse: [Utils_1.toCamelCaseTransformer],
@@ -121,16 +135,18 @@ class LiteSequencerClient {
121
135
  return response.response;
122
136
  }
123
137
  catch (error) {
124
- throw (0, errors_1.statusFetchError)(`endpoint ${this.endpoint} failed to complete request`, error);
138
+ throw (0, errors_1.statusFetchError)(`request ${requestLabel} failed to complete request`, error);
125
139
  }
126
140
  }
127
141
  async convertCurrency(params) {
142
+ const path = 'convert_currency';
143
+ const requestLabel = this.getRequestLabel('POST', path);
128
144
  try {
129
145
  const payload = {
130
146
  currency: params.currency,
131
147
  value: params.value.toString(),
132
148
  };
133
- const response = await this.httpClient.post(new URL('convert_currency', this.endpoint).toString(), payload, {
149
+ const response = await this.httpClient.post(new URL(path, this.endpoint).toString(), payload, {
134
150
  transformResponse: [Utils_1.toCamelCaseTransformer],
135
151
  });
136
152
  const raw = response.data.response;
@@ -152,29 +168,33 @@ class LiteSequencerClient {
152
168
  };
153
169
  }
154
170
  catch (error) {
155
- throw (0, instances_1.convertCurrencyFetchError)(`endpoint ${this.endpoint} failed to complete request`, error);
171
+ throw (0, instances_1.convertCurrencyFetchError)(`request ${requestLabel} failed to complete request`, error);
156
172
  }
157
173
  }
158
174
  async simulateTACMessage(params) {
175
+ const path = 'tac/simulator/simulate-message';
176
+ const requestLabel = this.getRequestLabel('POST', path);
159
177
  try {
160
- const response = await this.httpClient.post(new URL('tac/simulator/simulate-message', this.endpoint).toString(), params, {
178
+ const response = await this.httpClient.post(new URL(path, this.endpoint).toString(), params, {
161
179
  transformResponse: [Utils_1.toCamelCaseTransformer],
162
180
  });
163
181
  return response.data.response;
164
182
  }
165
183
  catch (error) {
166
- throw (0, instances_1.simulationFetchError)(`endpoint ${this.endpoint} failed to complete request`, error);
184
+ throw (0, instances_1.simulationFetchError)(`request ${requestLabel} failed to complete request`, error);
167
185
  }
168
186
  }
169
187
  async getTVMExecutorFee(params) {
188
+ const path = '/ton/calculator/ton-executor-fee';
189
+ const requestLabel = this.getRequestLabel('POST', path);
170
190
  try {
171
- const response = await this.httpClient.post(new URL('/ton/calculator/ton-executor-fee', this.endpoint).toString(), params, {
191
+ const response = await this.httpClient.post(new URL(path, this.endpoint).toString(), params, {
172
192
  transformResponse: [Utils_1.toCamelCaseTransformer],
173
193
  });
174
194
  return response.data.response;
175
195
  }
176
196
  catch (error) {
177
- throw (0, instances_1.getTONFeeInfoFetchError)(`endpoint ${this.endpoint} failed to complete request`, error);
197
+ throw (0, instances_1.getTONFeeInfoFetchError)(`request ${requestLabel} failed to complete request`, error);
178
198
  }
179
199
  }
180
200
  async processChunkedRequest(identifiers, requestFn, chunkSize = this.maxChunkSize) {
@@ -50,7 +50,7 @@ class OperationTracker {
50
50
  }
51
51
  }
52
52
  this.logger.error('All endpoints failed to get operation id by transactionHash');
53
- throw (0, errors_1.allEndpointsFailedError)(lastError);
53
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
54
54
  };
55
55
  return waitOptions
56
56
  ? await (0, Utils_1.waitUntilSuccess)(waitOptions, requestFn, 'OperationTracker: Getting operation ID by transaction hash')
@@ -72,7 +72,7 @@ class OperationTracker {
72
72
  }
73
73
  }
74
74
  this.logger.error('All endpoints failed to get operation type');
75
- throw (0, errors_1.allEndpointsFailedError)(lastError);
75
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
76
76
  };
77
77
  return waitOptions
78
78
  ? await (0, Utils_1.waitUntilSuccess)(waitOptions, requestFn, 'OperationTracker: Getting operation type')
@@ -94,7 +94,7 @@ class OperationTracker {
94
94
  }
95
95
  }
96
96
  this.logger.error('All endpoints failed to get operation id');
97
- throw (0, errors_1.allEndpointsFailedError)(lastError);
97
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
98
98
  };
99
99
  return waitOptions
100
100
  ? await (0, Utils_1.waitUntilSuccess)(waitOptions, requestFn, 'OperationTracker: Getting operation ID by transaction linker')
@@ -117,7 +117,7 @@ class OperationTracker {
117
117
  }
118
118
  }
119
119
  this.logger.error('All endpoints failed to get operation ids by shards keys');
120
- throw (0, errors_1.allEndpointsFailedError)(lastError);
120
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
121
121
  };
122
122
  return waitOptions
123
123
  ? await (0, Utils_1.waitUntilSuccess)(waitOptions, requestFn, 'OperationTracker: Getting operation IDs by shards keys')
@@ -144,7 +144,7 @@ class OperationTracker {
144
144
  }
145
145
  }
146
146
  this.logger.error('All endpoints failed to get stage profiling');
147
- throw (0, errors_1.allEndpointsFailedError)(lastError);
147
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
148
148
  };
149
149
  return waitOptions
150
150
  ? await (0, Utils_1.waitUntilSuccess)(waitOptions, requestFn, 'OperationTracker: Getting stage profiling')
@@ -167,7 +167,7 @@ class OperationTracker {
167
167
  }
168
168
  }
169
169
  this.logger.error('All endpoints failed to get stage profilings');
170
- throw (0, errors_1.allEndpointsFailedError)(lastError);
170
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
171
171
  };
172
172
  return waitOptions
173
173
  ? await (0, Utils_1.waitUntilSuccess)(waitOptions, requestFn, 'OperationTracker: Getting stage profilings')
@@ -190,7 +190,7 @@ class OperationTracker {
190
190
  }
191
191
  }
192
192
  this.logger.error('All endpoints failed to get operation statuses');
193
- throw (0, errors_1.allEndpointsFailedError)(lastError);
193
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
194
194
  };
195
195
  return waitOptions
196
196
  ? await (0, Utils_1.waitUntilSuccess)(waitOptions, requestFn, 'OperationTracker: Getting operation statuses')
@@ -208,7 +208,6 @@ class OperationTracker {
208
208
  this.logger.warn(`No operation status for operationId=${operationId}`);
209
209
  throw new Error(`No operation status for operationId=${operationId}`);
210
210
  }
211
- this.logger.debug(`Operation status retrieved successfully`);
212
211
  return result;
213
212
  }
214
213
  catch (error) {
@@ -217,11 +216,13 @@ class OperationTracker {
217
216
  }
218
217
  }
219
218
  this.logger.error('All endpoints failed to get operation status');
220
- throw (0, errors_1.allEndpointsFailedError)(lastError);
219
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
221
220
  };
222
- return waitOptions
221
+ const status = waitOptions
223
222
  ? await (0, Utils_1.waitUntilSuccess)(waitOptions, requestFn, 'OperationTracker: Getting operation status')
224
223
  : await requestFn();
224
+ this.logger.debug(`operation status resolved stage=${status.stage ?? 'unknown'} success=${(String(status.success))}`);
225
+ return status;
225
226
  }
226
227
  async getSimplifiedOperationStatus(transactionLinker) {
227
228
  this.logger.debug(`Getting simplified operation status for transaction linker: ${(0, Utils_1.formatObjectForLogging)(transactionLinker)}`);
@@ -258,7 +259,7 @@ class OperationTracker {
258
259
  }
259
260
  }
260
261
  this.logger.error('All endpoints failed to convert currency');
261
- throw (0, errors_1.allEndpointsFailedError)(lastError);
262
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
262
263
  };
263
264
  return waitOptions
264
265
  ? await (0, Utils_1.waitUntilSuccess)(waitOptions, requestFn, 'OperationTracker: Converting currency')
@@ -281,7 +282,7 @@ class OperationTracker {
281
282
  }
282
283
  }
283
284
  this.logger.error('All endpoints failed to simulate TAC message');
284
- throw (0, errors_1.allEndpointsFailedError)(lastError);
285
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
285
286
  };
286
287
  return waitOptions
287
288
  ? await (0, Utils_1.waitUntilSuccess)(waitOptions, requestFn, 'OperationTracker: Simulating TAC message')
@@ -303,7 +304,7 @@ class OperationTracker {
303
304
  }
304
305
  }
305
306
  this.logger.error('All endpoints failed to get TVM executor fee');
306
- throw (0, errors_1.allEndpointsFailedError)(lastError);
307
+ throw (0, errors_1.allEndpointsFailedError)(lastError, waitOptions?.includeErrorTrace ?? false);
307
308
  };
308
309
  return waitOptions
309
310
  ? await (0, Utils_1.waitUntilSuccess)(waitOptions, requestFn, 'OperationTracker: Getting TVM executor fee')
@@ -18,7 +18,7 @@ class TONTransactionManager {
18
18
  this.logger = logger;
19
19
  }
20
20
  async buildFeeParams(options, evmProxyMsg, sender, tx) {
21
- const { withoutSimulation, protocolFee, evmExecutorFee, tvmExecutorFee, isRoundTrip } = options;
21
+ const { withoutSimulation, protocolFee, evmExecutorFee, tvmExecutorFee, isRoundTrip, shouldValidateFees = true, } = options;
22
22
  if (withoutSimulation) {
23
23
  if (protocolFee === undefined || evmExecutorFee === undefined) {
24
24
  throw errors_1.missingFeeParamsError;
@@ -40,6 +40,20 @@ class TONTransactionManager {
40
40
  const simulationResult = await this.simulator.getSimulationInfo(sender, tx);
41
41
  if (!evmProxyMsg.gasLimit)
42
42
  evmProxyMsg.gasLimit = simulationResult.feeParams.gasLimit;
43
+ const shouldValidateSuggestedFees = shouldValidateFees && (simulationResult.simulation?.simulationStatus ?? true);
44
+ if (shouldValidateSuggestedFees) {
45
+ if (protocolFee !== undefined && protocolFee < simulationResult.feeParams.protocolFee) {
46
+ throw (0, errors_1.insufficientFeeParamsError)('protocolFee', protocolFee, simulationResult.feeParams.protocolFee);
47
+ }
48
+ if (evmExecutorFee !== undefined && evmExecutorFee < simulationResult.feeParams.evmExecutorFee) {
49
+ throw (0, errors_1.insufficientFeeParamsError)('evmExecutorFee', evmExecutorFee, simulationResult.feeParams.evmExecutorFee);
50
+ }
51
+ if (simulationResult.feeParams.isRoundTrip &&
52
+ tvmExecutorFee !== undefined &&
53
+ tvmExecutorFee < simulationResult.feeParams.tvmExecutorFee) {
54
+ throw (0, errors_1.insufficientFeeParamsError)('tvmExecutorFee', tvmExecutorFee, simulationResult.feeParams.tvmExecutorFee);
55
+ }
56
+ }
43
57
  return {
44
58
  protocolFee: protocolFee ?? simulationResult.feeParams.protocolFee,
45
59
  evmExecutorFee: evmExecutorFee ?? simulationResult.feeParams.evmExecutorFee,
@@ -168,10 +182,9 @@ class TONTransactionManager {
168
182
  if (!shouldWaitForOperationId) {
169
183
  return { sendTransactionResult, ...transactionLinker };
170
184
  }
171
- const waitOptions = tx.options?.waitOptions ?? {
172
- ensureTxExecuted: true,
173
- };
174
- if (waitOptions.ensureTxExecuted && sendTransactionResult.boc) {
185
+ const waitOptions = tx.options?.waitOptions ?? {};
186
+ const ensureTxExecuted = tx.options?.ensureTxExecuted ?? true;
187
+ if (ensureTxExecuted && sendTransactionResult.boc) {
175
188
  const hash = (0, Utils_1.getNormalizedExtMessageHash)((0, ton_1.loadMessage)(ton_1.Cell.fromBase64(sendTransactionResult.boc).beginParse()));
176
189
  this.logger.info(`Tracking transaction tree for hash: ${hash}`);
177
190
  await this.config.TONParams.contractOpener.trackTransactionTree(sender.getSenderAddress(), hash, {
@@ -26,6 +26,7 @@ class TacSdk {
26
26
  static async create(sdkParams, logger = new Logger_1.NoopLogger()) {
27
27
  const network = sdkParams.network;
28
28
  const delay = sdkParams.delay ?? Consts_1.DEFAULT_DELAY;
29
+ const passLoggerToOpeners = sdkParams.passLoggerToOpeners ?? true;
29
30
  let artifacts;
30
31
  switch (network) {
31
32
  case Struct_1.Network.MAINNET:
@@ -40,7 +41,7 @@ class TacSdk {
40
41
  default:
41
42
  throw new Error(`Unsupported network: ${network}`);
42
43
  }
43
- const config = await Configuration_1.Configuration.create(network, artifacts, sdkParams.TONParams, sdkParams.TACParams, sdkParams.customLiteSequencerEndpoints, delay, logger);
44
+ const config = await Configuration_1.Configuration.create(network, artifacts, sdkParams.TONParams, sdkParams.TACParams, sdkParams.customLiteSequencerEndpoints, delay, logger, passLoggerToOpeners);
44
45
  const operationTracker = new OperationTracker_1.OperationTracker(network, config.liteSequencerEndpoints);
45
46
  const explorerClient = new TacExplorerClient_1.TacExplorerClient(artifacts.TAC_EXPLORER_API_ENDPOINT);
46
47
  const simulator = new Simulator_1.Simulator(config, operationTracker, logger);
@@ -168,9 +168,8 @@ async function waitUntilSuccess(options = {}, operation, operationDescription, .
168
168
  if (result === undefined || result === null) {
169
169
  throw new Error(`Empty result`);
170
170
  }
171
- options.logger?.debug(`${contextPrefix}Result: ${formatObjectForLogging(result)}`);
172
171
  if (successCheck && !successCheck(result, context)) {
173
- throw new Error(`Result is not successful`);
172
+ throw new Error(`Result is not successful: ${formatObjectForLogging(result)}`);
174
173
  }
175
174
  options.logger?.debug(`${contextPrefix}Attempt ${attempt} successful`);
176
175
  // Execute custom onSuccess callback if provided
@@ -193,8 +192,13 @@ async function waitUntilSuccess(options = {}, operation, operationDescription, .
193
192
  options.logger?.debug(`${contextPrefix}Max attempts (${maxAttempts}) reached`);
194
193
  throw error;
195
194
  }
196
- options.logger?.debug(`${contextPrefix}Error on attempt ${attempt}: ${error}`);
197
- options.logger?.debug(`${contextPrefix}Waiting ${delay}ms before next attempt`);
195
+ const pendingMessage = statusRetryMessageFromError(error, attempt, maxAttempts, delay);
196
+ if (pendingMessage) {
197
+ options.logger?.debug(`${contextPrefix}${pendingMessage}`);
198
+ }
199
+ else {
200
+ options.logger?.debug(`${contextPrefix}attempt=${attempt}/${maxAttempts} failed; retry_in=${delay}ms; error=${String(error)}`);
201
+ }
198
202
  await (0, exports.sleep)(delay);
199
203
  attempt++;
200
204
  }
@@ -203,6 +207,44 @@ async function waitUntilSuccess(options = {}, operation, operationDescription, .
203
207
  function formatObjectForLogging(obj) {
204
208
  return JSON.stringify(obj, (key, value) => (typeof value === 'bigint' ? value.toString() : value));
205
209
  }
210
+ function statusRetryMessageFromError(error, attempt, maxAttempts, delay) {
211
+ const prefix = 'Result is not successful: ';
212
+ const message = String(error);
213
+ const index = message.indexOf(prefix);
214
+ if (index < 0) {
215
+ return null;
216
+ }
217
+ const payloadString = message.slice(index + prefix.length).trim();
218
+ let payload;
219
+ try {
220
+ payload = JSON.parse(payloadString);
221
+ }
222
+ catch {
223
+ return null;
224
+ }
225
+ if (typeof payload !== 'object' || payload === null) {
226
+ return null;
227
+ }
228
+ const statusPayload = payload;
229
+ if (statusPayload.stage === undefined &&
230
+ statusPayload.success === undefined &&
231
+ statusPayload.transactions === undefined) {
232
+ return null;
233
+ }
234
+ const stage = typeof statusPayload.stage === 'string' && statusPayload.stage ? statusPayload.stage : 'unknown';
235
+ const success = typeof statusPayload.success === 'boolean' ? String(statusPayload.success) : 'unknown';
236
+ let txHash = '-';
237
+ if (Array.isArray(statusPayload.transactions) && statusPayload.transactions.length > 0) {
238
+ const first = statusPayload.transactions[0];
239
+ if (typeof first === 'object' && first !== null && 'hash' in first) {
240
+ const maybeHash = first.hash;
241
+ if (typeof maybeHash === 'string' && maybeHash) {
242
+ txHash = maybeHash;
243
+ }
244
+ }
245
+ }
246
+ return `pending attempt=${attempt}/${maxAttempts} stage=${stage} success=${success} tx=${txHash} retry_in=${delay}ms`;
247
+ }
206
248
  function getBouncedAddress(tvmAddress) {
207
249
  return ton_1.Address.parse(tvmAddress).toString({
208
250
  bounceable: true,
@@ -82,6 +82,11 @@ export type SDKParams = {
82
82
  * URLs of lite sequencers
83
83
  */
84
84
  customLiteSequencerEndpoints?: string[];
85
+ /**
86
+ * Whether SDK logger should be passed to TON contract opener(s).
87
+ * Default: true
88
+ */
89
+ passLoggerToOpeners?: boolean;
85
90
  };
86
91
  export declare enum AssetType {
87
92
  NFT = "NFT",
@@ -284,6 +289,16 @@ export type FeeParams = {
284
289
  export type evmDataBuilder = (transactionLinker: TransactionLinker, evmProxyMsg: EvmProxyMsg, validExecutors: ValidExecutors) => Cell;
285
290
  export type CrossChainTransactionOptions = {
286
291
  allowSimulationError?: boolean;
292
+ /**
293
+ * If true, ensures TON transaction execution is validated before waiting for operation id.
294
+ * @default true
295
+ */
296
+ ensureTxExecuted?: boolean;
297
+ /**
298
+ * If true, validates explicitly provided fee params against suggested values.
299
+ * @default true
300
+ */
301
+ shouldValidateFees?: boolean;
287
302
  isRoundTrip?: boolean;
288
303
  protocolFee?: bigint;
289
304
  evmValidExecutors?: string[];
@@ -297,7 +312,7 @@ export type CrossChainTransactionOptions = {
297
312
  waitOptions?: WaitOptions<string>;
298
313
  evmDataBuilder?: evmDataBuilder;
299
314
  };
300
- export type BatchCrossChainTransactionOptions = Omit<CrossChainTransactionOptions, 'waitOperationId' | 'waitOptions'>;
315
+ export type BatchCrossChainTransactionOptions = Omit<CrossChainTransactionOptions, 'waitOperationId' | 'waitOptions' | 'ensureTxExecuted'>;
301
316
  export type CrossChainTransactionsOptions = {
302
317
  waitOperationIds?: boolean;
303
318
  waitOptions?: WaitOptions<OperationIdsByShardsKey>;
@@ -371,10 +386,10 @@ export interface WaitOptions<T = unknown, TContext = unknown> {
371
386
  */
372
387
  onSuccess?: (result: T, context?: TContext) => Promise<void> | void;
373
388
  /**
374
- * Ensure that TON transaction is succesful
375
- * @default true
389
+ * Include underlying error stack trace in FetchError (innerStack)
390
+ * @default false
376
391
  */
377
- ensureTxExecuted?: boolean;
392
+ includeErrorTrace?: boolean;
378
393
  }
379
394
  export declare const defaultWaitOptions: WaitOptions;
380
395
  export declare enum Origin {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonappchain/sdk",
3
- "version": "0.7.2-alpha-15",
3
+ "version": "0.7.2-alpha-16",
4
4
  "repository": "https://github.com/TacBuild/tac-sdk.git",
5
5
  "author": "TAC. <developers@tac>",
6
6
  "license": "MIT",