@tonconnect/sdk 3.3.0-beta.0 → 3.3.0-beta.2

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.
package/lib/cjs/index.cjs CHANGED
@@ -6,7 +6,7 @@ var protocol = require('@tonconnect/protocol');
6
6
  require('@tonconnect/isomorphic-eventsource');
7
7
  require('@tonconnect/isomorphic-fetch');
8
8
 
9
- /*! *****************************************************************************
9
+ /******************************************************************************
10
10
  Copyright (c) Microsoft Corporation.
11
11
 
12
12
  Permission to use, copy, modify, and/or distribute this software for any
@@ -20,6 +20,8 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
20
20
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21
21
  PERFORMANCE OF THIS SOFTWARE.
22
22
  ***************************************************************************** */
23
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
24
+
23
25
 
24
26
  function __rest(s, e) {
25
27
  var t = {};
@@ -41,20 +43,25 @@ function __awaiter(thisArg, _arguments, P, generator) {
41
43
  function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
44
  step((generator = generator.apply(thisArg, _arguments || [])).next());
43
45
  });
44
- }
46
+ }
47
+
48
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
49
+ var e = new Error(message);
50
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
51
+ };
45
52
 
46
53
  /**
47
54
  * Base class for TonConnect errors. You can check if the error was triggered by the @tonconnect/sdk using `err instanceof TonConnectError`.
48
55
  */
49
56
  class TonConnectError extends Error {
57
+ get info() {
58
+ return '';
59
+ }
50
60
  constructor(message, options) {
51
61
  super(message, options);
52
62
  this.message = `${TonConnectError.prefix} ${this.constructor.name}${this.info ? ': ' + this.info : ''}${message ? '\n' + message : ''}`;
53
63
  Object.setPrototypeOf(this, TonConnectError.prototype);
54
64
  }
55
- get info() {
56
- return '';
57
- }
58
65
  }
59
66
  TonConnectError.prefix = '[TON_CONNECT_SDK_ERROR]';
60
67
 
@@ -408,12 +415,12 @@ function delay(timeout, options) {
408
415
  return __awaiter(this, void 0, void 0, function* () {
409
416
  return new Promise((resolve, reject) => {
410
417
  var _a, _b;
411
- if ((_a = options === null || options === void 0 ? void 0 : options.signal) === null || _a === void 0 ? void 0 : _a.aborted) {
418
+ if ((_a = void 0 ) === null || _a === void 0 ? void 0 : _a.aborted) {
412
419
  reject(new TonConnectError('Delay aborted'));
413
420
  return;
414
421
  }
415
422
  const timeoutId = setTimeout(() => resolve(), timeout);
416
- (_b = options === null || options === void 0 ? void 0 : options.signal) === null || _b === void 0 ? void 0 : _b.addEventListener('abort', () => {
423
+ (_b = void 0 ) === null || _b === void 0 ? void 0 : _b.addEventListener('abort', () => {
417
424
  clearTimeout(timeoutId);
418
425
  reject(new TonConnectError('Delay aborted'));
419
426
  });
@@ -444,9 +451,10 @@ function createAbortController(signal) {
444
451
  * @param {T} fn - function to call
445
452
  * @param {CallForSuccessOptions} [options] - optional configuration options
446
453
  */
454
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
447
455
  function callForSuccess(fn, options) {
448
- var _a, _b;
449
456
  return __awaiter(this, void 0, void 0, function* () {
457
+ var _a, _b;
450
458
  const attempts = (_a = options === null || options === void 0 ? void 0 : options.attempts) !== null && _a !== void 0 ? _a : 10;
451
459
  const delayMs = (_b = options === null || options === void 0 ? void 0 : options.delayMs) !== null && _b !== void 0 ? _b : 200;
452
460
  const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
@@ -508,6 +516,7 @@ function logWarning(...args) {
508
516
  * @param {(...args: Args) => Promise<T>} createFn - A function that creates the resource.
509
517
  * @param {(resource: T) => Promise<void>} [disposeFn] - An optional function that disposes the resource.
510
518
  */
519
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
511
520
  function createResource(createFn, disposeFn) {
512
521
  let currentResource = null;
513
522
  let currentArgs = null;
@@ -617,6 +626,18 @@ function timeout(fn, options) {
617
626
  }
618
627
 
619
628
  class BridgeGateway {
629
+ get isReady() {
630
+ const eventSource = this.eventSource.current();
631
+ return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.OPEN;
632
+ }
633
+ get isClosed() {
634
+ const eventSource = this.eventSource.current();
635
+ return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) !== EventSource.OPEN;
636
+ }
637
+ get isConnecting() {
638
+ const eventSource = this.eventSource.current();
639
+ return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.CONNECTING;
640
+ }
620
641
  constructor(storage, bridgeUrl, sessionId, listener, errorsListener) {
621
642
  this.bridgeUrl = bridgeUrl;
622
643
  this.sessionId = sessionId;
@@ -645,26 +666,14 @@ class BridgeGateway {
645
666
  }));
646
667
  this.bridgeGatewayStorage = new HttpBridgeGatewayStorage(storage, bridgeUrl);
647
668
  }
648
- get isReady() {
649
- const eventSource = this.eventSource.current();
650
- return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.OPEN;
651
- }
652
- get isClosed() {
653
- const eventSource = this.eventSource.current();
654
- return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) !== EventSource.OPEN;
655
- }
656
- get isConnecting() {
657
- const eventSource = this.eventSource.current();
658
- return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.CONNECTING;
659
- }
660
669
  registerSession(options) {
661
670
  return __awaiter(this, void 0, void 0, function* () {
662
671
  yield this.eventSource.create(options === null || options === void 0 ? void 0 : options.signal, options === null || options === void 0 ? void 0 : options.openingDeadlineMS);
663
672
  });
664
673
  }
665
674
  send(message, receiver, topic, ttlOrOptions) {
666
- var _a;
667
675
  return __awaiter(this, void 0, void 0, function* () {
676
+ var _a;
668
677
  // TODO: remove deprecated method
669
678
  const options = {};
670
679
  if (typeof ttlOrOptions === 'number') {
@@ -1013,6 +1022,16 @@ class BridgeConnectionStorage {
1013
1022
  const PROTOCOL_VERSION = 2;
1014
1023
 
1015
1024
  class BridgeProvider {
1025
+ static fromStorage(storage) {
1026
+ return __awaiter(this, void 0, void 0, function* () {
1027
+ const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
1028
+ const connection = yield bridgeConnectionStorage.getHttpConnection();
1029
+ if (isPendingConnectionHttp(connection)) {
1030
+ return new BridgeProvider(storage, connection.connectionSource);
1031
+ }
1032
+ return new BridgeProvider(storage, { bridgeUrl: connection.session.bridgeUrl });
1033
+ });
1034
+ }
1016
1035
  constructor(storage, walletConnectionSource) {
1017
1036
  this.storage = storage;
1018
1037
  this.walletConnectionSource = walletConnectionSource;
@@ -1027,16 +1046,6 @@ class BridgeProvider {
1027
1046
  this.defaultRetryTimeoutMS = 2000;
1028
1047
  this.connectionStorage = new BridgeConnectionStorage(storage);
1029
1048
  }
1030
- static fromStorage(storage) {
1031
- return __awaiter(this, void 0, void 0, function* () {
1032
- const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
1033
- const connection = yield bridgeConnectionStorage.getHttpConnection();
1034
- if (isPendingConnectionHttp(connection)) {
1035
- return new BridgeProvider(storage, connection.connectionSource);
1036
- }
1037
- return new BridgeProvider(storage, { bridgeUrl: connection.session.bridgeUrl });
1038
- });
1039
- }
1040
1049
  connect(message, options) {
1041
1050
  var _a;
1042
1051
  const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
@@ -1079,8 +1088,8 @@ class BridgeProvider {
1079
1088
  return this.generateUniversalLink(universalLink, message);
1080
1089
  }
1081
1090
  restoreConnection(options) {
1082
- var _a, _b;
1083
1091
  return __awaiter(this, void 0, void 0, function* () {
1092
+ var _a, _b;
1084
1093
  const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
1085
1094
  (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
1086
1095
  this.abortController = abortController;
@@ -1426,15 +1435,15 @@ function isJSBridgeWithMetadata(value) {
1426
1435
  * Uses as a fallback for localStorage in Safari's private mode.
1427
1436
  */
1428
1437
  class InMemoryStorage {
1429
- constructor() {
1430
- this.storage = {};
1431
- }
1432
1438
  static getInstance() {
1433
1439
  if (!InMemoryStorage.instance) {
1434
1440
  InMemoryStorage.instance = new InMemoryStorage();
1435
1441
  }
1436
1442
  return InMemoryStorage.instance;
1437
1443
  }
1444
+ constructor() {
1445
+ this.storage = {};
1446
+ }
1438
1447
  get length() {
1439
1448
  return Object.keys(this.storage).length;
1440
1449
  }
@@ -1529,19 +1538,6 @@ function isNodeJs() {
1529
1538
  }
1530
1539
 
1531
1540
  class InjectedProvider {
1532
- constructor(storage, injectedWalletKey) {
1533
- this.injectedWalletKey = injectedWalletKey;
1534
- this.type = 'injected';
1535
- this.unsubscribeCallback = null;
1536
- this.listenSubscriptions = false;
1537
- this.listeners = [];
1538
- const window = InjectedProvider.window;
1539
- if (!InjectedProvider.isWindowContainsWallet(window, injectedWalletKey)) {
1540
- throw new WalletNotInjectedError();
1541
- }
1542
- this.connectionStorage = new BridgeConnectionStorage(storage);
1543
- this.injectedWallet = window[injectedWalletKey].tonconnect;
1544
- }
1545
1541
  static fromStorage(storage) {
1546
1542
  return __awaiter(this, void 0, void 0, function* () {
1547
1543
  const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
@@ -1583,6 +1579,19 @@ class InjectedProvider {
1583
1579
  typeof window[injectedWalletKey] === 'object' &&
1584
1580
  'tonconnect' in window[injectedWalletKey]);
1585
1581
  }
1582
+ constructor(storage, injectedWalletKey) {
1583
+ this.injectedWalletKey = injectedWalletKey;
1584
+ this.type = 'injected';
1585
+ this.unsubscribeCallback = null;
1586
+ this.listenSubscriptions = false;
1587
+ this.listeners = [];
1588
+ const window = InjectedProvider.window;
1589
+ if (!InjectedProvider.isWindowContainsWallet(window, injectedWalletKey)) {
1590
+ throw new WalletNotInjectedError();
1591
+ }
1592
+ this.connectionStorage = new BridgeConnectionStorage(storage);
1593
+ this.injectedWallet = window[injectedWalletKey].tonconnect;
1594
+ }
1586
1595
  connect(message) {
1587
1596
  this._connect(PROTOCOL_VERSION, message);
1588
1597
  }
@@ -1644,8 +1653,8 @@ class InjectedProvider {
1644
1653
  return () => (this.listeners = this.listeners.filter(listener => listener !== eventsCallback));
1645
1654
  }
1646
1655
  sendRequest(request, optionsOrOnRequestSent) {
1647
- var _a;
1648
1656
  return __awaiter(this, void 0, void 0, function* () {
1657
+ var _a;
1649
1658
  // TODO: remove deprecated method
1650
1659
  const options = {};
1651
1660
  if (typeof optionsOrOnRequestSent === 'function') {
@@ -2084,13 +2093,133 @@ const FALLBACK_WALLETS_LIST = [
2084
2093
  }
2085
2094
  ];
2086
2095
 
2096
+ let qaModeEnabled = false;
2097
+ let bannerObserver = null;
2098
+ function enableQaMode() {
2099
+ qaModeEnabled = true;
2100
+ console.warn('🚨 QA Mode enabled - validation is disabled. This is unsafe for production!');
2101
+ showQaModeBanner();
2102
+ startBannerObserver();
2103
+ addQaModeStyles();
2104
+ }
2105
+ function isQaModeEnabled() {
2106
+ return qaModeEnabled;
2107
+ }
2108
+ function logValidationError(message) {
2109
+ if (isQaModeEnabled()) {
2110
+ console.error(`[QA Mode] Validation failed: ${message}`);
2111
+ }
2112
+ }
2113
+ function showQaModeBanner() {
2114
+ if (typeof window === 'undefined')
2115
+ return;
2116
+ const existingBanner = document.getElementById('ton-connect-qa-banner');
2117
+ if (existingBanner)
2118
+ return;
2119
+ const banner = document.createElement('div');
2120
+ banner.id = 'ton-connect-qa-banner';
2121
+ banner.style.cssText = `
2122
+ position: fixed;
2123
+ top: 0;
2124
+ left: 0;
2125
+ right: 0;
2126
+ background: linear-gradient(90deg, #ff6b6b, #ff8e8e);
2127
+ color: white;
2128
+ padding: 12px 20px;
2129
+ text-align: center;
2130
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
2131
+ font-weight: 600;
2132
+ font-size: 14px;
2133
+ z-index: 999999;
2134
+ box-shadow: 0 2px 8px rgba(0,0,0,0.2);
2135
+ animation: slideDown 0.3s ease-out;
2136
+ user-select: none;
2137
+ pointer-events: none;
2138
+ `;
2139
+ banner.innerHTML = `
2140
+ 🚨 QA Mode Active - Validation Disabled (Unsafe for Production)
2141
+ `;
2142
+ // Add CSS animation
2143
+ const style = document.createElement('style');
2144
+ style.textContent = `
2145
+ @keyframes slideDown {
2146
+ from { transform: translateY(-100%); }
2147
+ to { transform: translateY(0); }
2148
+ }
2149
+ `;
2150
+ document.head.appendChild(style);
2151
+ document.body.appendChild(banner);
2152
+ addQaModeStyles();
2153
+ }
2154
+ function addQaModeStyles() {
2155
+ if (typeof window === 'undefined')
2156
+ return;
2157
+ const existingStyle = document.getElementById('ton-connect-qa-mode-styles');
2158
+ if (existingStyle)
2159
+ return;
2160
+ const style = document.createElement('style');
2161
+ style.id = 'ton-connect-qa-mode-styles';
2162
+ style.textContent = `
2163
+ body.qa-mode-active {
2164
+ padding-top: 48px !important;
2165
+ }
2166
+
2167
+ body.qa-mode-active header {
2168
+ margin-top: 48px !important;
2169
+ }
2170
+
2171
+ body.qa-mode-active .qa-mode-control {
2172
+ top: 128px !important;
2173
+ }
2174
+ `;
2175
+ document.head.appendChild(style);
2176
+ document.body.classList.add('qa-mode-active');
2177
+ }
2178
+ function startBannerObserver() {
2179
+ if (typeof window === 'undefined' || bannerObserver)
2180
+ return;
2181
+ bannerObserver = new MutationObserver(mutations => {
2182
+ mutations.forEach(mutation => {
2183
+ if (mutation.type === 'childList') {
2184
+ mutation.removedNodes.forEach(node => {
2185
+ if (node.nodeType === Node.ELEMENT_NODE) {
2186
+ const element = node;
2187
+ if (element.id === 'ton-connect-qa-banner' && qaModeEnabled) {
2188
+ console.warn('QA Mode banner was removed, restoring...');
2189
+ setTimeout(() => showQaModeBanner(), 100);
2190
+ }
2191
+ else if (element.id === 'ton-connect-qa-mode-styles' && qaModeEnabled) {
2192
+ console.warn('QA Mode styles were removed, restoring...');
2193
+ setTimeout(() => addQaModeStyles(), 100);
2194
+ }
2195
+ }
2196
+ });
2197
+ }
2198
+ });
2199
+ });
2200
+ bannerObserver.observe(document.body, {
2201
+ childList: true,
2202
+ subtree: false
2203
+ });
2204
+ bannerObserver.observe(document.head, {
2205
+ childList: true,
2206
+ subtree: false
2207
+ });
2208
+ }
2209
+
2087
2210
  class WalletsListManager {
2088
2211
  constructor(options) {
2089
2212
  var _a;
2090
2213
  this.walletsListCache = null;
2091
2214
  this.walletsListCacheCreationTimestamp = null;
2092
- this.walletsListSource =
2093
- (_a = options === null || options === void 0 ? void 0 : options.walletsListSource) !== null && _a !== void 0 ? _a : 'https://raw.githubusercontent.com/ton-blockchain/wallets-list/main/wallets-v2.json';
2215
+ if (isQaModeEnabled()) {
2216
+ this.walletsListSource =
2217
+ 'https://raw.githubusercontent.com/ton-connect/wallets-list-staging/refs/heads/main/wallets-v2.json';
2218
+ }
2219
+ else {
2220
+ this.walletsListSource =
2221
+ (_a = options === null || options === void 0 ? void 0 : options.walletsListSource) !== null && _a !== void 0 ? _a : 'https://raw.githubusercontent.com/ton-blockchain/wallets-list/main/wallets-v2.json';
2222
+ }
2094
2223
  this.cacheTTLMs = options === null || options === void 0 ? void 0 : options.cacheTTLMs;
2095
2224
  }
2096
2225
  getWallets() {
@@ -2517,8 +2646,8 @@ class BrowserEventDispatcher {
2517
2646
  * @returns A promise that resolves when the event has been dispatched.
2518
2647
  */
2519
2648
  dispatchEvent(eventName, eventDetails) {
2520
- var _a;
2521
2649
  return __awaiter(this, void 0, void 0, function* () {
2650
+ var _a;
2522
2651
  const event = new CustomEvent(eventName, { detail: eventDetails });
2523
2652
  (_a = this.window) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
2524
2653
  });
@@ -2531,8 +2660,8 @@ class BrowserEventDispatcher {
2531
2660
  * @returns A function that removes the listener.
2532
2661
  */
2533
2662
  addEventListener(eventName, listener, options) {
2534
- var _a;
2535
2663
  return __awaiter(this, void 0, void 0, function* () {
2664
+ var _a;
2536
2665
  (_a = this.window) === null || _a === void 0 ? void 0 : _a.addEventListener(eventName, listener, options);
2537
2666
  return () => {
2538
2667
  var _a;
@@ -2570,6 +2699,15 @@ class BrowserEventDispatcher {
2570
2699
  * @internal
2571
2700
  */
2572
2701
  class TonConnectTracker {
2702
+ /**
2703
+ * Version of the library.
2704
+ */
2705
+ get version() {
2706
+ return createVersionInfo({
2707
+ ton_connect_sdk_lib: this.tonConnectSdkVersion,
2708
+ ton_connect_ui_lib: this.tonConnectUiVersion
2709
+ });
2710
+ }
2573
2711
  constructor(options) {
2574
2712
  var _a;
2575
2713
  /**
@@ -2585,15 +2723,6 @@ class TonConnectTracker {
2585
2723
  this.tonConnectSdkVersion = options.tonConnectSdkVersion;
2586
2724
  this.init().catch();
2587
2725
  }
2588
- /**
2589
- * Version of the library.
2590
- */
2591
- get version() {
2592
- return createVersionInfo({
2593
- ton_connect_sdk_lib: this.tonConnectSdkVersion,
2594
- ton_connect_ui_lib: this.tonConnectUiVersion
2595
- });
2596
- }
2597
2726
  /**
2598
2727
  * Called once when the tracker is created and request version other libraries.
2599
2728
  */
@@ -2794,36 +2923,384 @@ class TonConnectTracker {
2794
2923
  }
2795
2924
  }
2796
2925
 
2797
- const tonConnectSdkVersion = "3.3.0-beta.0";
2926
+ const tonConnectSdkVersion = "3.3.0-beta.2";
2798
2927
 
2799
- class TonConnect {
2800
- constructor(options) {
2801
- this.walletsList = new WalletsListManager();
2802
- this._wallet = null;
2803
- this.provider = null;
2804
- this.statusChangeSubscriptions = [];
2805
- this.statusChangeErrorSubscriptions = [];
2806
- this.dappSettings = {
2807
- manifestUrl: (options === null || options === void 0 ? void 0 : options.manifestUrl) || getWebPageManifest(),
2808
- storage: (options === null || options === void 0 ? void 0 : options.storage) || new DefaultStorage()
2809
- };
2810
- this.walletsRequiredFeatures = options === null || options === void 0 ? void 0 : options.walletsRequiredFeatures;
2811
- this.walletsList = new WalletsListManager({
2812
- walletsListSource: options === null || options === void 0 ? void 0 : options.walletsListSource,
2813
- cacheTTLMs: options === null || options === void 0 ? void 0 : options.walletsListCacheTTLMs
2814
- });
2815
- this.tracker = new TonConnectTracker({
2816
- eventDispatcher: options === null || options === void 0 ? void 0 : options.eventDispatcher,
2817
- tonConnectSdkVersion: tonConnectSdkVersion
2818
- });
2819
- if (!this.dappSettings.manifestUrl) {
2820
- throw new DappMetadataError('Dapp tonconnect-manifest.json must be specified if window.location.origin is undefined. See more https://github.com/ton-connect/docs/blob/main/requests-responses.md#app-manifest');
2928
+ const noBounceableTag = 0x51;
2929
+ const testOnlyTag = 0x80;
2930
+ /**
2931
+ * Converts raw TON address to no-bounceable user-friendly format. [See details]{@link https://ton.org/docs/learn/overviews/addresses#user-friendly-address}
2932
+ * @param hexAddress raw TON address formatted as "0:<hex string without 0x>".
2933
+ * @param [testOnly=false] convert address to test-only form. [See details]{@link https://ton.org/docs/learn/overviews/addresses#user-friendly-address}
2934
+ */
2935
+ function toUserFriendlyAddress(hexAddress, testOnly = false) {
2936
+ const { wc, hex } = parseHexAddress(hexAddress);
2937
+ let tag = noBounceableTag;
2938
+ if (testOnly) {
2939
+ tag |= testOnlyTag;
2940
+ }
2941
+ const addr = new Int8Array(34);
2942
+ addr[0] = tag;
2943
+ addr[1] = wc;
2944
+ addr.set(hex, 2);
2945
+ const addressWithChecksum = new Uint8Array(36);
2946
+ addressWithChecksum.set(addr);
2947
+ addressWithChecksum.set(crc16(addr), 34);
2948
+ let addressBase64 = protocol.Base64.encode(addressWithChecksum);
2949
+ return addressBase64.replace(/\+/g, '-').replace(/\//g, '_');
2950
+ }
2951
+ /**
2952
+ * Validates if the address is in user-friendly format by attempting to parse it.
2953
+ * @param address address to validate
2954
+ * @returns true if the address is valid user-friendly format, false otherwise
2955
+ */
2956
+ function isValidUserFriendlyAddress(address) {
2957
+ try {
2958
+ parseUserFriendlyAddress(address);
2959
+ return true;
2960
+ }
2961
+ catch (_a) {
2962
+ return false;
2963
+ }
2964
+ }
2965
+ /**
2966
+ * Validates if the address is in raw hex format (e.g., "0:1234..." or "-1:1234...").
2967
+ * @param address address to validate
2968
+ * @returns true if the address is valid raw format, false otherwise
2969
+ */
2970
+ function isValidRawAddress(address) {
2971
+ try {
2972
+ parseHexAddress(address);
2973
+ return true;
2974
+ }
2975
+ catch (_a) {
2976
+ return false;
2977
+ }
2978
+ }
2979
+ /**
2980
+ * Parses user-friendly address and returns its components.
2981
+ * @param address user-friendly address
2982
+ * @returns parsed address components
2983
+ */
2984
+ function parseUserFriendlyAddress(address) {
2985
+ const base64 = address.replace(/-/g, '+').replace(/_/g, '/');
2986
+ let decoded;
2987
+ try {
2988
+ decoded = protocol.Base64.decode(base64).toUint8Array();
2989
+ }
2990
+ catch (_a) {
2991
+ throw new WrongAddressError(`Invalid base64 encoding in address: ${address}`);
2992
+ }
2993
+ if (decoded.length !== 36) {
2994
+ throw new WrongAddressError(`Invalid address length: ${address}`);
2995
+ }
2996
+ const addr = decoded.slice(0, 34);
2997
+ const checksum = decoded.slice(34);
2998
+ const calculatedChecksum = crc16(addr);
2999
+ if (!checksum.every((byte, i) => byte === calculatedChecksum[i])) {
3000
+ throw new WrongAddressError(`Invalid checksum in address: ${address}`);
3001
+ }
3002
+ const tag = addr[0];
3003
+ const wc = addr[1];
3004
+ const hex = addr.slice(2);
3005
+ if (wc !== 0 && wc !== -1) {
3006
+ throw new WrongAddressError(`Invalid workchain: ${wc}`);
3007
+ }
3008
+ const testOnly = (tag & testOnlyTag) !== 0;
3009
+ const isBounceable = (tag & 0x40) !== 0;
3010
+ return {
3011
+ wc,
3012
+ hex: Array.from(hex)
3013
+ .map(b => b.toString(16).padStart(2, '0'))
3014
+ .join(''),
3015
+ testOnly,
3016
+ isBounceable
3017
+ };
3018
+ }
3019
+ function parseHexAddress(hexAddress) {
3020
+ if (!hexAddress.includes(':')) {
3021
+ throw new WrongAddressError(`Wrong address ${hexAddress}. Address must include ":".`);
3022
+ }
3023
+ const parts = hexAddress.split(':');
3024
+ if (parts.length !== 2) {
3025
+ throw new WrongAddressError(`Wrong address ${hexAddress}. Address must include ":" only once.`);
3026
+ }
3027
+ const wc = parseInt(parts[0]);
3028
+ if (wc !== 0 && wc !== -1) {
3029
+ throw new WrongAddressError(`Wrong address ${hexAddress}. WC must be eq 0 or -1, but ${wc} received.`);
3030
+ }
3031
+ const hex = parts[1];
3032
+ if ((hex === null || hex === void 0 ? void 0 : hex.length) !== 64) {
3033
+ throw new WrongAddressError(`Wrong address ${hexAddress}. Hex part must be 64bytes length, but ${hex === null || hex === void 0 ? void 0 : hex.length} received.`);
3034
+ }
3035
+ return {
3036
+ wc,
3037
+ hex: hexToBytes(hex)
3038
+ };
3039
+ }
3040
+ function crc16(data) {
3041
+ const poly = 0x1021;
3042
+ let reg = 0;
3043
+ const message = new Uint8Array(data.length + 2);
3044
+ message.set(data);
3045
+ for (let byte of message) {
3046
+ let mask = 0x80;
3047
+ while (mask > 0) {
3048
+ reg <<= 1;
3049
+ if (byte & mask) {
3050
+ reg += 1;
3051
+ }
3052
+ mask >>= 1;
3053
+ if (reg > 0xffff) {
3054
+ reg &= 0xffff;
3055
+ reg ^= poly;
3056
+ }
2821
3057
  }
2822
- this.bridgeConnectionStorage = new BridgeConnectionStorage(this.dappSettings.storage);
2823
- if (!(options === null || options === void 0 ? void 0 : options.disableAutoPauseConnection)) {
2824
- this.addWindowFocusAndBlurSubscriptions();
3058
+ }
3059
+ return new Uint8Array([Math.floor(reg / 256), reg % 256]);
3060
+ }
3061
+ const toByteMap = {};
3062
+ for (let ord = 0; ord <= 0xff; ord++) {
3063
+ let s = ord.toString(16);
3064
+ if (s.length < 2) {
3065
+ s = '0' + s;
3066
+ }
3067
+ toByteMap[s] = ord;
3068
+ }
3069
+ function hexToBytes(hex) {
3070
+ hex = hex.toLowerCase();
3071
+ const length2 = hex.length;
3072
+ if (length2 % 2 !== 0) {
3073
+ throw new ParseHexError('Hex string must have length a multiple of 2: ' + hex);
3074
+ }
3075
+ const length = length2 / 2;
3076
+ const result = new Uint8Array(length);
3077
+ for (let i = 0; i < length; i++) {
3078
+ const doubled = i * 2;
3079
+ const hexSubstring = hex.substring(doubled, doubled + 2);
3080
+ if (!toByteMap.hasOwnProperty(hexSubstring)) {
3081
+ throw new ParseHexError('Invalid hex character: ' + hexSubstring);
3082
+ }
3083
+ result[i] = toByteMap[hexSubstring];
3084
+ }
3085
+ return result;
3086
+ }
3087
+
3088
+ const BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
3089
+ const BOC_PREFIX = 'te6cc';
3090
+ const INTEGER_REGEX = /^-?\d+$/;
3091
+ const POSITIVE_INTEGER_REGEX = /^\d+$/;
3092
+ function isValidNumber(value) {
3093
+ return typeof value === 'number' && !isNaN(value);
3094
+ }
3095
+ function isValidString(value) {
3096
+ return typeof value === 'string' && value.length > 0;
3097
+ }
3098
+ function isValidBoc(value) {
3099
+ return typeof value === 'string' && BASE64_REGEX.test(value) && value.startsWith(BOC_PREFIX);
3100
+ }
3101
+ function isValidObject(value) {
3102
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3103
+ }
3104
+ function isValidArray(value) {
3105
+ return Array.isArray(value);
3106
+ }
3107
+ function hasExtraProperties(obj, allowedKeys) {
3108
+ return Object.keys(obj).some(key => !allowedKeys.includes(key));
3109
+ }
3110
+ function validateSendTransactionRequest(data) {
3111
+ // eslint-disable-next-line no-console
3112
+ console.log('[Validation Debug] validateSendTransactionRequest called');
3113
+ // eslint-disable-next-line no-console
3114
+ console.log('[Validation Debug] isQaModeEnabled():', isQaModeEnabled());
3115
+ if (!isValidObject(data)) {
3116
+ const error = 'Request must be an object';
3117
+ logValidationError(error);
3118
+ const shouldReturnNull = isQaModeEnabled();
3119
+ // eslint-disable-next-line no-console
3120
+ console.log('[Validation Debug] Should return null:', shouldReturnNull);
3121
+ return shouldReturnNull ? null : error;
3122
+ }
3123
+ const allowedKeys = ['validUntil', 'network', 'from', 'messages'];
3124
+ if (hasExtraProperties(data, allowedKeys)) {
3125
+ const error = 'Request contains extra properties';
3126
+ logValidationError(error);
3127
+ return isQaModeEnabled() ? null : error;
3128
+ }
3129
+ if (!isValidNumber(data.validUntil)) {
3130
+ const error = "Incorrect 'validUntil'";
3131
+ logValidationError(error);
3132
+ return isQaModeEnabled() ? null : error;
3133
+ }
3134
+ const now = Math.floor(Date.now() / 1000);
3135
+ const fiveMinutesFromNow = now + 300;
3136
+ if (data.validUntil > fiveMinutesFromNow) {
3137
+ console.warn(`validUntil (${data.validUntil}) is more than 5 minutes from now (${now})`);
3138
+ }
3139
+ if (data.network !== undefined) {
3140
+ if (!isValidString(data.network) || !/^[\d-]+$/.test(data.network)) {
3141
+ const error = "Invalid 'network' format";
3142
+ logValidationError(error);
3143
+ return isQaModeEnabled() ? null : error;
3144
+ }
3145
+ }
3146
+ if (data.from !== undefined) {
3147
+ if (!isValidString(data.from) || !isValidRawAddress(data.from)) {
3148
+ const error = "Invalid 'from' address format";
3149
+ logValidationError(error);
3150
+ return isQaModeEnabled() ? null : error;
2825
3151
  }
2826
3152
  }
3153
+ if (!isValidArray(data.messages) || data.messages.length === 0) {
3154
+ const error = "'messages' is required";
3155
+ logValidationError(error);
3156
+ return isQaModeEnabled() ? null : error;
3157
+ }
3158
+ for (let i = 0; i < data.messages.length; i++) {
3159
+ const message = data.messages[i];
3160
+ const messageError = validateTransactionMessage(message, i);
3161
+ if (messageError) {
3162
+ return messageError;
3163
+ }
3164
+ }
3165
+ return null;
3166
+ }
3167
+ function validateTransactionMessage(message, index) {
3168
+ if (!isValidObject(message)) {
3169
+ return `Message at index ${index} must be an object`;
3170
+ }
3171
+ const allowedKeys = ['address', 'amount', 'stateInit', 'payload', 'extraCurrency'];
3172
+ if (hasExtraProperties(message, allowedKeys)) {
3173
+ return `Message at index ${index} contains extra properties`;
3174
+ }
3175
+ if (!isValidString(message.address)) {
3176
+ return `'address' is required in message at index ${index}`;
3177
+ }
3178
+ if (!isValidUserFriendlyAddress(message.address)) {
3179
+ return `Wrong 'address' format in message at index ${index}`;
3180
+ }
3181
+ if (!isValidString(message.amount)) {
3182
+ return `'amount' is required in message at index ${index}`;
3183
+ }
3184
+ if (!/^[0-9]+$/.test(message.amount)) {
3185
+ return `Incorrect 'amount' in message at index ${index}`;
3186
+ }
3187
+ if (message.stateInit !== undefined) {
3188
+ if (!isValidString(message.stateInit) || !isValidBoc(message.stateInit)) {
3189
+ return `Invalid 'stateInit' in message at index ${index}`;
3190
+ }
3191
+ }
3192
+ if (message.payload !== undefined) {
3193
+ if (!isValidString(message.payload) || !isValidBoc(message.payload)) {
3194
+ return `Invalid 'payload' in message at index ${index}`;
3195
+ }
3196
+ }
3197
+ if (message.extraCurrency !== undefined) {
3198
+ if (!isValidObject(message.extraCurrency)) {
3199
+ return `Invalid 'extraCurrency' in message at index ${index}`;
3200
+ }
3201
+ for (const [key, value] of Object.entries(message.extraCurrency)) {
3202
+ if (!INTEGER_REGEX.test(key) ||
3203
+ typeof value !== 'string' ||
3204
+ !POSITIVE_INTEGER_REGEX.test(value)) {
3205
+ return `Invalid 'extraCurrency' format in message at index ${index}`;
3206
+ }
3207
+ }
3208
+ }
3209
+ return null;
3210
+ }
3211
+ function validateConnectAdditionalRequest(data) {
3212
+ if (!isValidObject(data)) {
3213
+ return 'Request must be an object';
3214
+ }
3215
+ const allowedKeys = ['tonProof'];
3216
+ if (hasExtraProperties(data, allowedKeys)) {
3217
+ return 'Request contains extra properties';
3218
+ }
3219
+ if (data.tonProof !== undefined && !isValidString(data.tonProof)) {
3220
+ return "Invalid 'tonProof'";
3221
+ }
3222
+ return null;
3223
+ }
3224
+ function validateSignDataPayload(data) {
3225
+ if (!isValidObject(data)) {
3226
+ return 'Payload must be an object';
3227
+ }
3228
+ if (!isValidString(data.type)) {
3229
+ return "'type' is required";
3230
+ }
3231
+ switch (data.type) {
3232
+ case 'text':
3233
+ return validateSignDataPayloadText(data);
3234
+ case 'binary':
3235
+ return validateSignDataPayloadBinary(data);
3236
+ case 'cell':
3237
+ return validateSignDataPayloadCell(data);
3238
+ default:
3239
+ return "Invalid 'type' value";
3240
+ }
3241
+ }
3242
+ function validateSignDataPayloadText(data) {
3243
+ const allowedKeys = ['type', 'text', 'network', 'from'];
3244
+ if (hasExtraProperties(data, allowedKeys)) {
3245
+ return 'Text payload contains extra properties';
3246
+ }
3247
+ if (!isValidString(data.text)) {
3248
+ return "'text' is required";
3249
+ }
3250
+ if (data.network !== undefined) {
3251
+ if (!isValidString(data.network) || !/^\d+$/.test(data.network)) {
3252
+ return "Invalid 'network' format";
3253
+ }
3254
+ }
3255
+ if (data.from !== undefined && !isValidString(data.from)) {
3256
+ return "Invalid 'from'";
3257
+ }
3258
+ return null;
3259
+ }
3260
+ function validateSignDataPayloadBinary(data) {
3261
+ const allowedKeys = ['type', 'bytes', 'network', 'from'];
3262
+ if (hasExtraProperties(data, allowedKeys)) {
3263
+ return 'Binary payload contains extra properties';
3264
+ }
3265
+ if (!isValidString(data.bytes)) {
3266
+ return "'bytes' is required";
3267
+ }
3268
+ if (data.network !== undefined) {
3269
+ if (!isValidString(data.network) || !/^\d+$/.test(data.network)) {
3270
+ return "Invalid 'network' format";
3271
+ }
3272
+ }
3273
+ if (data.from !== undefined && !isValidString(data.from)) {
3274
+ return "Invalid 'from'";
3275
+ }
3276
+ return null;
3277
+ }
3278
+ function validateSignDataPayloadCell(data) {
3279
+ const allowedKeys = ['type', 'schema', 'cell', 'network', 'from'];
3280
+ if (hasExtraProperties(data, allowedKeys)) {
3281
+ return 'Cell payload contains extra properties';
3282
+ }
3283
+ if (!isValidString(data.schema)) {
3284
+ return "'schema' is required";
3285
+ }
3286
+ if (!isValidString(data.cell)) {
3287
+ return "'cell' is required";
3288
+ }
3289
+ if (!isValidBoc(data.cell)) {
3290
+ return "Invalid 'cell' format (must be valid base64)";
3291
+ }
3292
+ if (data.network !== undefined) {
3293
+ if (!isValidString(data.network) || !/^\d+$/.test(data.network)) {
3294
+ return "Invalid 'network' format";
3295
+ }
3296
+ }
3297
+ if (data.from !== undefined && !isValidString(data.from)) {
3298
+ return "Invalid 'from'";
3299
+ }
3300
+ return null;
3301
+ }
3302
+
3303
+ class TonConnect {
2827
3304
  /**
2828
3305
  * Returns available wallets list.
2829
3306
  */
@@ -2853,6 +3330,33 @@ class TonConnect {
2853
3330
  this._wallet = value;
2854
3331
  this.statusChangeSubscriptions.forEach(callback => callback(this._wallet));
2855
3332
  }
3333
+ constructor(options) {
3334
+ this.walletsList = new WalletsListManager();
3335
+ this._wallet = null;
3336
+ this.provider = null;
3337
+ this.statusChangeSubscriptions = [];
3338
+ this.statusChangeErrorSubscriptions = [];
3339
+ this.dappSettings = {
3340
+ manifestUrl: (options === null || options === void 0 ? void 0 : options.manifestUrl) || getWebPageManifest(),
3341
+ storage: (options === null || options === void 0 ? void 0 : options.storage) || new DefaultStorage()
3342
+ };
3343
+ this.walletsRequiredFeatures = options === null || options === void 0 ? void 0 : options.walletsRequiredFeatures;
3344
+ this.walletsList = new WalletsListManager({
3345
+ walletsListSource: options === null || options === void 0 ? void 0 : options.walletsListSource,
3346
+ cacheTTLMs: options === null || options === void 0 ? void 0 : options.walletsListCacheTTLMs
3347
+ });
3348
+ this.tracker = new TonConnectTracker({
3349
+ eventDispatcher: options === null || options === void 0 ? void 0 : options.eventDispatcher,
3350
+ tonConnectSdkVersion: tonConnectSdkVersion
3351
+ });
3352
+ if (!this.dappSettings.manifestUrl) {
3353
+ throw new DappMetadataError('Dapp tonconnect-manifest.json must be specified if window.location.origin is undefined. See more https://github.com/ton-connect/docs/blob/main/requests-responses.md#app-manifest');
3354
+ }
3355
+ this.bridgeConnectionStorage = new BridgeConnectionStorage(this.dappSettings.storage);
3356
+ if (!(options === null || options === void 0 ? void 0 : options.disableAutoPauseConnection)) {
3357
+ this.addWindowFocusAndBlurSubscriptions();
3358
+ }
3359
+ }
2856
3360
  /**
2857
3361
  * Returns available wallets list.
2858
3362
  */
@@ -2892,6 +3396,17 @@ class TonConnect {
2892
3396
  options.openingDeadlineMS = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.openingDeadlineMS;
2893
3397
  options.signal = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.signal;
2894
3398
  }
3399
+ if (options.request) {
3400
+ const validationError = validateConnectAdditionalRequest(options.request);
3401
+ if (validationError) {
3402
+ if (isQaModeEnabled()) {
3403
+ console.error('ConnectAdditionalRequest validation failed: ' + validationError);
3404
+ }
3405
+ else {
3406
+ throw new TonConnectError('ConnectAdditionalRequest validation failed: ' + validationError);
3407
+ }
3408
+ }
3409
+ }
2895
3410
  if (this.connected) {
2896
3411
  throw new WalletAlreadyConnectedError();
2897
3412
  }
@@ -2918,8 +3433,8 @@ class TonConnect {
2918
3433
  * Try to restore existing session and reconnect to the corresponding wallet. Call it immediately when your app is loaded.
2919
3434
  */
2920
3435
  restoreConnection(options) {
2921
- var _a, _b;
2922
3436
  return __awaiter(this, void 0, void 0, function* () {
3437
+ var _a, _b;
2923
3438
  this.tracker.trackConnectionRestoringStarted();
2924
3439
  const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
2925
3440
  (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
@@ -3014,6 +3529,16 @@ class TonConnect {
3014
3529
  options.onRequestSent = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.onRequestSent;
3015
3530
  options.signal = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.signal;
3016
3531
  }
3532
+ // Validate transaction
3533
+ const validationError = validateSendTransactionRequest(transaction);
3534
+ if (validationError) {
3535
+ if (isQaModeEnabled()) {
3536
+ console.error('SendTransactionRequest validation failed: ' + validationError);
3537
+ }
3538
+ else {
3539
+ throw new TonConnectError('SendTransactionRequest validation failed: ' + validationError);
3540
+ }
3541
+ }
3017
3542
  const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
3018
3543
  if (abortController.signal.aborted) {
3019
3544
  throw new TonConnectError('Transaction sending was aborted');
@@ -3049,6 +3574,16 @@ class TonConnect {
3049
3574
  if (abortController.signal.aborted) {
3050
3575
  throw new TonConnectError('data sending was aborted');
3051
3576
  }
3577
+ // Validate sign data
3578
+ const validationError = validateSignDataPayload(data);
3579
+ if (validationError) {
3580
+ if (isQaModeEnabled()) {
3581
+ console.error('SignDataPayload validation failed: ' + validationError);
3582
+ }
3583
+ else {
3584
+ throw new TonConnectError('SignDataPayload validation failed: ' + validationError);
3585
+ }
3586
+ }
3052
3587
  this.checkConnection();
3053
3588
  checkSignDataSupport(this.wallet.device.features, { requiredTypes: [data.type] });
3054
3589
  this.tracker.trackDataSentForSignature(this.wallet, data);
@@ -3069,8 +3604,8 @@ class TonConnect {
3069
3604
  * Disconnect form thw connected wallet and drop current session.
3070
3605
  */
3071
3606
  disconnect(options) {
3072
- var _a;
3073
3607
  return __awaiter(this, void 0, void 0, function* () {
3608
+ var _a;
3074
3609
  if (!this.connected) {
3075
3610
  throw new WalletNotConnectedError();
3076
3611
  }
@@ -3178,26 +3713,28 @@ class TonConnect {
3178
3713
  if (tonProofItem) {
3179
3714
  let tonProof = undefined;
3180
3715
  try {
3181
- if ('proof' in tonProofItem) { // success
3716
+ if ('proof' in tonProofItem) {
3717
+ // success
3182
3718
  tonProof = {
3183
3719
  name: 'ton_proof',
3184
3720
  proof: {
3185
3721
  timestamp: tonProofItem.proof.timestamp,
3186
3722
  domain: {
3187
3723
  lengthBytes: tonProofItem.proof.domain.lengthBytes,
3188
- value: tonProofItem.proof.domain.value,
3724
+ value: tonProofItem.proof.domain.value
3189
3725
  },
3190
3726
  payload: tonProofItem.proof.payload,
3191
- signature: tonProofItem.proof.signature,
3727
+ signature: tonProofItem.proof.signature
3192
3728
  }
3193
3729
  };
3194
3730
  }
3195
- else if ('error' in tonProofItem) { // error
3731
+ else if ('error' in tonProofItem) {
3732
+ // error
3196
3733
  tonProof = {
3197
3734
  name: 'ton_proof',
3198
3735
  error: {
3199
3736
  code: tonProofItem.error.code,
3200
- message: tonProofItem.error.message,
3737
+ message: tonProofItem.error.message
3201
3738
  }
3202
3739
  };
3203
3740
  }
@@ -3266,115 +3803,23 @@ TonConnect.isWalletInjected = (walletJSKey) => InjectedProvider.isWalletInjected
3266
3803
  */
3267
3804
  TonConnect.isInsideWalletBrowser = (walletJSKey) => InjectedProvider.isInsideWalletBrowser(walletJSKey);
3268
3805
 
3269
- const noBounceableTag = 0x51;
3270
- const testOnlyTag = 0x80;
3271
- /**
3272
- * Converts raw TON address to no-bounceable user-friendly format. [See details]{@link https://ton.org/docs/learn/overviews/addresses#user-friendly-address}
3273
- * @param hexAddress raw TON address formatted as "0:<hex string without 0x>".
3274
- * @param [testOnly=false] convert address to test-only form. [See details]{@link https://ton.org/docs/learn/overviews/addresses#user-friendly-address}
3275
- */
3276
- function toUserFriendlyAddress(hexAddress, testOnly = false) {
3277
- const { wc, hex } = parseHexAddress(hexAddress);
3278
- let tag = noBounceableTag;
3279
- if (testOnly) {
3280
- tag |= testOnlyTag;
3281
- }
3282
- const addr = new Int8Array(34);
3283
- addr[0] = tag;
3284
- addr[1] = wc;
3285
- addr.set(hex, 2);
3286
- const addressWithChecksum = new Uint8Array(36);
3287
- addressWithChecksum.set(addr);
3288
- addressWithChecksum.set(crc16(addr), 34);
3289
- let addressBase64 = protocol.Base64.encode(addressWithChecksum);
3290
- return addressBase64.replace(/\+/g, '-').replace(/\//g, '_');
3291
- }
3292
- function parseHexAddress(hexAddress) {
3293
- if (!hexAddress.includes(':')) {
3294
- throw new WrongAddressError(`Wrong address ${hexAddress}. Address must include ":".`);
3295
- }
3296
- const parts = hexAddress.split(':');
3297
- if (parts.length !== 2) {
3298
- throw new WrongAddressError(`Wrong address ${hexAddress}. Address must include ":" only once.`);
3299
- }
3300
- const wc = parseInt(parts[0]);
3301
- if (wc !== 0 && wc !== -1) {
3302
- throw new WrongAddressError(`Wrong address ${hexAddress}. WC must be eq 0 or -1, but ${wc} received.`);
3303
- }
3304
- const hex = parts[1];
3305
- if ((hex === null || hex === void 0 ? void 0 : hex.length) !== 64) {
3306
- throw new WrongAddressError(`Wrong address ${hexAddress}. Hex part must be 64bytes length, but ${hex === null || hex === void 0 ? void 0 : hex.length} received.`);
3307
- }
3308
- return {
3309
- wc,
3310
- hex: hexToBytes(hex)
3311
- };
3312
- }
3313
- function crc16(data) {
3314
- const poly = 0x1021;
3315
- let reg = 0;
3316
- const message = new Uint8Array(data.length + 2);
3317
- message.set(data);
3318
- for (let byte of message) {
3319
- let mask = 0x80;
3320
- while (mask > 0) {
3321
- reg <<= 1;
3322
- if (byte & mask) {
3323
- reg += 1;
3324
- }
3325
- mask >>= 1;
3326
- if (reg > 0xffff) {
3327
- reg &= 0xffff;
3328
- reg ^= poly;
3329
- }
3330
- }
3331
- }
3332
- return new Uint8Array([Math.floor(reg / 256), reg % 256]);
3333
- }
3334
- const toByteMap = {};
3335
- for (let ord = 0; ord <= 0xff; ord++) {
3336
- let s = ord.toString(16);
3337
- if (s.length < 2) {
3338
- s = '0' + s;
3339
- }
3340
- toByteMap[s] = ord;
3341
- }
3342
- function hexToBytes(hex) {
3343
- hex = hex.toLowerCase();
3344
- const length2 = hex.length;
3345
- if (length2 % 2 !== 0) {
3346
- throw new ParseHexError('Hex string must have length a multiple of 2: ' + hex);
3347
- }
3348
- const length = length2 / 2;
3349
- const result = new Uint8Array(length);
3350
- for (let i = 0; i < length; i++) {
3351
- const doubled = i * 2;
3352
- const hexSubstring = hex.substring(doubled, doubled + 2);
3353
- if (!toByteMap.hasOwnProperty(hexSubstring)) {
3354
- throw new ParseHexError('Invalid hex character: ' + hexSubstring);
3355
- }
3356
- result[i] = toByteMap[hexSubstring];
3357
- }
3358
- return result;
3359
- }
3360
-
3361
- Object.defineProperty(exports, 'CHAIN', {
3806
+ Object.defineProperty(exports, "CHAIN", {
3362
3807
  enumerable: true,
3363
3808
  get: function () { return protocol.CHAIN; }
3364
3809
  });
3365
- Object.defineProperty(exports, 'CONNECT_EVENT_ERROR_CODES', {
3810
+ Object.defineProperty(exports, "CONNECT_EVENT_ERROR_CODES", {
3366
3811
  enumerable: true,
3367
3812
  get: function () { return protocol.CONNECT_EVENT_ERROR_CODES; }
3368
3813
  });
3369
- Object.defineProperty(exports, 'CONNECT_ITEM_ERROR_CODES', {
3814
+ Object.defineProperty(exports, "CONNECT_ITEM_ERROR_CODES", {
3370
3815
  enumerable: true,
3371
3816
  get: function () { return protocol.CONNECT_ITEM_ERROR_CODES; }
3372
3817
  });
3373
- Object.defineProperty(exports, 'SEND_TRANSACTION_ERROR_CODES', {
3818
+ Object.defineProperty(exports, "SEND_TRANSACTION_ERROR_CODES", {
3374
3819
  enumerable: true,
3375
3820
  get: function () { return protocol.SEND_TRANSACTION_ERROR_CODES; }
3376
3821
  });
3377
- Object.defineProperty(exports, 'SIGN_DATA_ERROR_CODES', {
3822
+ Object.defineProperty(exports, "SIGN_DATA_ERROR_CODES", {
3378
3823
  enumerable: true,
3379
3824
  get: function () { return protocol.SIGN_DATA_ERROR_CODES; }
3380
3825
  });
@@ -3413,7 +3858,9 @@ exports.createTransactionSignedEvent = createTransactionSignedEvent;
3413
3858
  exports.createTransactionSigningFailedEvent = createTransactionSigningFailedEvent;
3414
3859
  exports.createVersionInfo = createVersionInfo;
3415
3860
  exports.default = TonConnect;
3861
+ exports.enableQaMode = enableQaMode;
3416
3862
  exports.encodeTelegramUrlParameters = encodeTelegramUrlParameters;
3863
+ exports.isQaModeEnabled = isQaModeEnabled;
3417
3864
  exports.isTelegramUrl = isTelegramUrl;
3418
3865
  exports.isWalletInfoCurrentlyEmbedded = isWalletInfoCurrentlyEmbedded;
3419
3866
  exports.isWalletInfoCurrentlyInjected = isWalletInfoCurrentlyInjected;