@tonconnect/sdk 3.3.0-beta.0 → 3.3.0-beta.1
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/dist/tonconnect-sdk.min.js +1 -1
- package/dist/tonconnect-sdk.min.js.map +1 -1
- package/lib/cjs/index.cjs +615 -180
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/index.mjs +614 -181
- package/lib/esm/index.mjs.map +1 -1
- package/lib/types/index.d.ts +4 -0
- package/package.json +18 -22
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
|
|
|
@@ -445,8 +452,8 @@ function createAbortController(signal) {
|
|
|
445
452
|
* @param {CallForSuccessOptions} [options] - optional configuration options
|
|
446
453
|
*/
|
|
447
454
|
function callForSuccess(fn, options) {
|
|
448
|
-
var _a, _b;
|
|
449
455
|
return __awaiter(this, void 0, void 0, function* () {
|
|
456
|
+
var _a, _b;
|
|
450
457
|
const attempts = (_a = options === null || options === void 0 ? void 0 : options.attempts) !== null && _a !== void 0 ? _a : 10;
|
|
451
458
|
const delayMs = (_b = options === null || options === void 0 ? void 0 : options.delayMs) !== null && _b !== void 0 ? _b : 200;
|
|
452
459
|
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
@@ -617,6 +624,18 @@ function timeout(fn, options) {
|
|
|
617
624
|
}
|
|
618
625
|
|
|
619
626
|
class BridgeGateway {
|
|
627
|
+
get isReady() {
|
|
628
|
+
const eventSource = this.eventSource.current();
|
|
629
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.OPEN;
|
|
630
|
+
}
|
|
631
|
+
get isClosed() {
|
|
632
|
+
const eventSource = this.eventSource.current();
|
|
633
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) !== EventSource.OPEN;
|
|
634
|
+
}
|
|
635
|
+
get isConnecting() {
|
|
636
|
+
const eventSource = this.eventSource.current();
|
|
637
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.CONNECTING;
|
|
638
|
+
}
|
|
620
639
|
constructor(storage, bridgeUrl, sessionId, listener, errorsListener) {
|
|
621
640
|
this.bridgeUrl = bridgeUrl;
|
|
622
641
|
this.sessionId = sessionId;
|
|
@@ -645,26 +664,14 @@ class BridgeGateway {
|
|
|
645
664
|
}));
|
|
646
665
|
this.bridgeGatewayStorage = new HttpBridgeGatewayStorage(storage, bridgeUrl);
|
|
647
666
|
}
|
|
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
667
|
registerSession(options) {
|
|
661
668
|
return __awaiter(this, void 0, void 0, function* () {
|
|
662
669
|
yield this.eventSource.create(options === null || options === void 0 ? void 0 : options.signal, options === null || options === void 0 ? void 0 : options.openingDeadlineMS);
|
|
663
670
|
});
|
|
664
671
|
}
|
|
665
672
|
send(message, receiver, topic, ttlOrOptions) {
|
|
666
|
-
var _a;
|
|
667
673
|
return __awaiter(this, void 0, void 0, function* () {
|
|
674
|
+
var _a;
|
|
668
675
|
// TODO: remove deprecated method
|
|
669
676
|
const options = {};
|
|
670
677
|
if (typeof ttlOrOptions === 'number') {
|
|
@@ -1013,6 +1020,16 @@ class BridgeConnectionStorage {
|
|
|
1013
1020
|
const PROTOCOL_VERSION = 2;
|
|
1014
1021
|
|
|
1015
1022
|
class BridgeProvider {
|
|
1023
|
+
static fromStorage(storage) {
|
|
1024
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1025
|
+
const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
|
|
1026
|
+
const connection = yield bridgeConnectionStorage.getHttpConnection();
|
|
1027
|
+
if (isPendingConnectionHttp(connection)) {
|
|
1028
|
+
return new BridgeProvider(storage, connection.connectionSource);
|
|
1029
|
+
}
|
|
1030
|
+
return new BridgeProvider(storage, { bridgeUrl: connection.session.bridgeUrl });
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1016
1033
|
constructor(storage, walletConnectionSource) {
|
|
1017
1034
|
this.storage = storage;
|
|
1018
1035
|
this.walletConnectionSource = walletConnectionSource;
|
|
@@ -1027,16 +1044,6 @@ class BridgeProvider {
|
|
|
1027
1044
|
this.defaultRetryTimeoutMS = 2000;
|
|
1028
1045
|
this.connectionStorage = new BridgeConnectionStorage(storage);
|
|
1029
1046
|
}
|
|
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
1047
|
connect(message, options) {
|
|
1041
1048
|
var _a;
|
|
1042
1049
|
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
@@ -1079,8 +1086,8 @@ class BridgeProvider {
|
|
|
1079
1086
|
return this.generateUniversalLink(universalLink, message);
|
|
1080
1087
|
}
|
|
1081
1088
|
restoreConnection(options) {
|
|
1082
|
-
var _a, _b;
|
|
1083
1089
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1090
|
+
var _a, _b;
|
|
1084
1091
|
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
1085
1092
|
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
1086
1093
|
this.abortController = abortController;
|
|
@@ -1426,15 +1433,15 @@ function isJSBridgeWithMetadata(value) {
|
|
|
1426
1433
|
* Uses as a fallback for localStorage in Safari's private mode.
|
|
1427
1434
|
*/
|
|
1428
1435
|
class InMemoryStorage {
|
|
1429
|
-
constructor() {
|
|
1430
|
-
this.storage = {};
|
|
1431
|
-
}
|
|
1432
1436
|
static getInstance() {
|
|
1433
1437
|
if (!InMemoryStorage.instance) {
|
|
1434
1438
|
InMemoryStorage.instance = new InMemoryStorage();
|
|
1435
1439
|
}
|
|
1436
1440
|
return InMemoryStorage.instance;
|
|
1437
1441
|
}
|
|
1442
|
+
constructor() {
|
|
1443
|
+
this.storage = {};
|
|
1444
|
+
}
|
|
1438
1445
|
get length() {
|
|
1439
1446
|
return Object.keys(this.storage).length;
|
|
1440
1447
|
}
|
|
@@ -1529,19 +1536,6 @@ function isNodeJs() {
|
|
|
1529
1536
|
}
|
|
1530
1537
|
|
|
1531
1538
|
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
1539
|
static fromStorage(storage) {
|
|
1546
1540
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1547
1541
|
const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
|
|
@@ -1583,6 +1577,19 @@ class InjectedProvider {
|
|
|
1583
1577
|
typeof window[injectedWalletKey] === 'object' &&
|
|
1584
1578
|
'tonconnect' in window[injectedWalletKey]);
|
|
1585
1579
|
}
|
|
1580
|
+
constructor(storage, injectedWalletKey) {
|
|
1581
|
+
this.injectedWalletKey = injectedWalletKey;
|
|
1582
|
+
this.type = 'injected';
|
|
1583
|
+
this.unsubscribeCallback = null;
|
|
1584
|
+
this.listenSubscriptions = false;
|
|
1585
|
+
this.listeners = [];
|
|
1586
|
+
const window = InjectedProvider.window;
|
|
1587
|
+
if (!InjectedProvider.isWindowContainsWallet(window, injectedWalletKey)) {
|
|
1588
|
+
throw new WalletNotInjectedError();
|
|
1589
|
+
}
|
|
1590
|
+
this.connectionStorage = new BridgeConnectionStorage(storage);
|
|
1591
|
+
this.injectedWallet = window[injectedWalletKey].tonconnect;
|
|
1592
|
+
}
|
|
1586
1593
|
connect(message) {
|
|
1587
1594
|
this._connect(PROTOCOL_VERSION, message);
|
|
1588
1595
|
}
|
|
@@ -1644,8 +1651,8 @@ class InjectedProvider {
|
|
|
1644
1651
|
return () => (this.listeners = this.listeners.filter(listener => listener !== eventsCallback));
|
|
1645
1652
|
}
|
|
1646
1653
|
sendRequest(request, optionsOrOnRequestSent) {
|
|
1647
|
-
var _a;
|
|
1648
1654
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1655
|
+
var _a;
|
|
1649
1656
|
// TODO: remove deprecated method
|
|
1650
1657
|
const options = {};
|
|
1651
1658
|
if (typeof optionsOrOnRequestSent === 'function') {
|
|
@@ -2084,13 +2091,132 @@ const FALLBACK_WALLETS_LIST = [
|
|
|
2084
2091
|
}
|
|
2085
2092
|
];
|
|
2086
2093
|
|
|
2094
|
+
let qaModeEnabled = false;
|
|
2095
|
+
let bannerObserver = null;
|
|
2096
|
+
function enableQaMode() {
|
|
2097
|
+
qaModeEnabled = true;
|
|
2098
|
+
console.warn('🚨 QA Mode enabled - validation is disabled. This is unsafe for production!');
|
|
2099
|
+
showQaModeBanner();
|
|
2100
|
+
startBannerObserver();
|
|
2101
|
+
addQaModeStyles();
|
|
2102
|
+
}
|
|
2103
|
+
function isQaModeEnabled() {
|
|
2104
|
+
return qaModeEnabled;
|
|
2105
|
+
}
|
|
2106
|
+
function logValidationError(message) {
|
|
2107
|
+
if (isQaModeEnabled()) {
|
|
2108
|
+
console.error(`[QA Mode] Validation failed: ${message}`);
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
function showQaModeBanner() {
|
|
2112
|
+
if (typeof window === 'undefined')
|
|
2113
|
+
return;
|
|
2114
|
+
const existingBanner = document.getElementById('ton-connect-qa-banner');
|
|
2115
|
+
if (existingBanner)
|
|
2116
|
+
return;
|
|
2117
|
+
const banner = document.createElement('div');
|
|
2118
|
+
banner.id = 'ton-connect-qa-banner';
|
|
2119
|
+
banner.style.cssText = `
|
|
2120
|
+
position: fixed;
|
|
2121
|
+
top: 0;
|
|
2122
|
+
left: 0;
|
|
2123
|
+
right: 0;
|
|
2124
|
+
background: linear-gradient(90deg, #ff6b6b, #ff8e8e);
|
|
2125
|
+
color: white;
|
|
2126
|
+
padding: 12px 20px;
|
|
2127
|
+
text-align: center;
|
|
2128
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
2129
|
+
font-weight: 600;
|
|
2130
|
+
font-size: 14px;
|
|
2131
|
+
z-index: 999999;
|
|
2132
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
|
2133
|
+
animation: slideDown 0.3s ease-out;
|
|
2134
|
+
user-select: none;
|
|
2135
|
+
pointer-events: none;
|
|
2136
|
+
`;
|
|
2137
|
+
banner.innerHTML = `
|
|
2138
|
+
🚨 QA Mode Active - Validation Disabled (Unsafe for Production)
|
|
2139
|
+
`;
|
|
2140
|
+
// Add CSS animation
|
|
2141
|
+
const style = document.createElement('style');
|
|
2142
|
+
style.textContent = `
|
|
2143
|
+
@keyframes slideDown {
|
|
2144
|
+
from { transform: translateY(-100%); }
|
|
2145
|
+
to { transform: translateY(0); }
|
|
2146
|
+
}
|
|
2147
|
+
`;
|
|
2148
|
+
document.head.appendChild(style);
|
|
2149
|
+
document.body.appendChild(banner);
|
|
2150
|
+
addQaModeStyles();
|
|
2151
|
+
}
|
|
2152
|
+
function addQaModeStyles() {
|
|
2153
|
+
if (typeof window === 'undefined')
|
|
2154
|
+
return;
|
|
2155
|
+
const existingStyle = document.getElementById('ton-connect-qa-mode-styles');
|
|
2156
|
+
if (existingStyle)
|
|
2157
|
+
return;
|
|
2158
|
+
const style = document.createElement('style');
|
|
2159
|
+
style.id = 'ton-connect-qa-mode-styles';
|
|
2160
|
+
style.textContent = `
|
|
2161
|
+
body.qa-mode-active {
|
|
2162
|
+
padding-top: 48px !important;
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
body.qa-mode-active header {
|
|
2166
|
+
margin-top: 48px !important;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
body.qa-mode-active .qa-mode-control {
|
|
2170
|
+
top: 128px !important;
|
|
2171
|
+
}
|
|
2172
|
+
`;
|
|
2173
|
+
document.head.appendChild(style);
|
|
2174
|
+
document.body.classList.add('qa-mode-active');
|
|
2175
|
+
}
|
|
2176
|
+
function startBannerObserver() {
|
|
2177
|
+
if (typeof window === 'undefined' || bannerObserver)
|
|
2178
|
+
return;
|
|
2179
|
+
bannerObserver = new MutationObserver((mutations) => {
|
|
2180
|
+
mutations.forEach((mutation) => {
|
|
2181
|
+
if (mutation.type === 'childList') {
|
|
2182
|
+
mutation.removedNodes.forEach((node) => {
|
|
2183
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
2184
|
+
const element = node;
|
|
2185
|
+
if (element.id === 'ton-connect-qa-banner' && qaModeEnabled) {
|
|
2186
|
+
console.warn('QA Mode banner was removed, restoring...');
|
|
2187
|
+
setTimeout(() => showQaModeBanner(), 100);
|
|
2188
|
+
}
|
|
2189
|
+
else if (element.id === 'ton-connect-qa-mode-styles' && qaModeEnabled) {
|
|
2190
|
+
console.warn('QA Mode styles were removed, restoring...');
|
|
2191
|
+
setTimeout(() => addQaModeStyles(), 100);
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
});
|
|
2195
|
+
}
|
|
2196
|
+
});
|
|
2197
|
+
});
|
|
2198
|
+
bannerObserver.observe(document.body, {
|
|
2199
|
+
childList: true,
|
|
2200
|
+
subtree: false
|
|
2201
|
+
});
|
|
2202
|
+
bannerObserver.observe(document.head, {
|
|
2203
|
+
childList: true,
|
|
2204
|
+
subtree: false
|
|
2205
|
+
});
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2087
2208
|
class WalletsListManager {
|
|
2088
2209
|
constructor(options) {
|
|
2089
2210
|
var _a;
|
|
2090
2211
|
this.walletsListCache = null;
|
|
2091
2212
|
this.walletsListCacheCreationTimestamp = null;
|
|
2092
|
-
|
|
2093
|
-
|
|
2213
|
+
if (isQaModeEnabled()) {
|
|
2214
|
+
this.walletsListSource = 'https://raw.githubusercontent.com/ton-connect/wallets-list-staging/refs/heads/main/wallets-v2.json';
|
|
2215
|
+
}
|
|
2216
|
+
else {
|
|
2217
|
+
this.walletsListSource =
|
|
2218
|
+
(_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';
|
|
2219
|
+
}
|
|
2094
2220
|
this.cacheTTLMs = options === null || options === void 0 ? void 0 : options.cacheTTLMs;
|
|
2095
2221
|
}
|
|
2096
2222
|
getWallets() {
|
|
@@ -2517,8 +2643,8 @@ class BrowserEventDispatcher {
|
|
|
2517
2643
|
* @returns A promise that resolves when the event has been dispatched.
|
|
2518
2644
|
*/
|
|
2519
2645
|
dispatchEvent(eventName, eventDetails) {
|
|
2520
|
-
var _a;
|
|
2521
2646
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2647
|
+
var _a;
|
|
2522
2648
|
const event = new CustomEvent(eventName, { detail: eventDetails });
|
|
2523
2649
|
(_a = this.window) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
|
|
2524
2650
|
});
|
|
@@ -2531,8 +2657,8 @@ class BrowserEventDispatcher {
|
|
|
2531
2657
|
* @returns A function that removes the listener.
|
|
2532
2658
|
*/
|
|
2533
2659
|
addEventListener(eventName, listener, options) {
|
|
2534
|
-
var _a;
|
|
2535
2660
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2661
|
+
var _a;
|
|
2536
2662
|
(_a = this.window) === null || _a === void 0 ? void 0 : _a.addEventListener(eventName, listener, options);
|
|
2537
2663
|
return () => {
|
|
2538
2664
|
var _a;
|
|
@@ -2570,6 +2696,15 @@ class BrowserEventDispatcher {
|
|
|
2570
2696
|
* @internal
|
|
2571
2697
|
*/
|
|
2572
2698
|
class TonConnectTracker {
|
|
2699
|
+
/**
|
|
2700
|
+
* Version of the library.
|
|
2701
|
+
*/
|
|
2702
|
+
get version() {
|
|
2703
|
+
return createVersionInfo({
|
|
2704
|
+
ton_connect_sdk_lib: this.tonConnectSdkVersion,
|
|
2705
|
+
ton_connect_ui_lib: this.tonConnectUiVersion
|
|
2706
|
+
});
|
|
2707
|
+
}
|
|
2573
2708
|
constructor(options) {
|
|
2574
2709
|
var _a;
|
|
2575
2710
|
/**
|
|
@@ -2585,15 +2720,6 @@ class TonConnectTracker {
|
|
|
2585
2720
|
this.tonConnectSdkVersion = options.tonConnectSdkVersion;
|
|
2586
2721
|
this.init().catch();
|
|
2587
2722
|
}
|
|
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
2723
|
/**
|
|
2598
2724
|
* Called once when the tracker is created and request version other libraries.
|
|
2599
2725
|
*/
|
|
@@ -2794,36 +2920,377 @@ class TonConnectTracker {
|
|
|
2794
2920
|
}
|
|
2795
2921
|
}
|
|
2796
2922
|
|
|
2797
|
-
const tonConnectSdkVersion = "3.3.0-beta.
|
|
2923
|
+
const tonConnectSdkVersion = "3.3.0-beta.1";
|
|
2798
2924
|
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2925
|
+
const noBounceableTag = 0x51;
|
|
2926
|
+
const testOnlyTag = 0x80;
|
|
2927
|
+
/**
|
|
2928
|
+
* Converts raw TON address to no-bounceable user-friendly format. [See details]{@link https://ton.org/docs/learn/overviews/addresses#user-friendly-address}
|
|
2929
|
+
* @param hexAddress raw TON address formatted as "0:<hex string without 0x>".
|
|
2930
|
+
* @param [testOnly=false] convert address to test-only form. [See details]{@link https://ton.org/docs/learn/overviews/addresses#user-friendly-address}
|
|
2931
|
+
*/
|
|
2932
|
+
function toUserFriendlyAddress(hexAddress, testOnly = false) {
|
|
2933
|
+
const { wc, hex } = parseHexAddress(hexAddress);
|
|
2934
|
+
let tag = noBounceableTag;
|
|
2935
|
+
if (testOnly) {
|
|
2936
|
+
tag |= testOnlyTag;
|
|
2937
|
+
}
|
|
2938
|
+
const addr = new Int8Array(34);
|
|
2939
|
+
addr[0] = tag;
|
|
2940
|
+
addr[1] = wc;
|
|
2941
|
+
addr.set(hex, 2);
|
|
2942
|
+
const addressWithChecksum = new Uint8Array(36);
|
|
2943
|
+
addressWithChecksum.set(addr);
|
|
2944
|
+
addressWithChecksum.set(crc16(addr), 34);
|
|
2945
|
+
let addressBase64 = protocol.Base64.encode(addressWithChecksum);
|
|
2946
|
+
return addressBase64.replace(/\+/g, '-').replace(/\//g, '_');
|
|
2947
|
+
}
|
|
2948
|
+
/**
|
|
2949
|
+
* Validates if the address is in user-friendly format by attempting to parse it.
|
|
2950
|
+
* @param address address to validate
|
|
2951
|
+
* @returns true if the address is valid user-friendly format, false otherwise
|
|
2952
|
+
*/
|
|
2953
|
+
function isValidUserFriendlyAddress(address) {
|
|
2954
|
+
try {
|
|
2955
|
+
parseUserFriendlyAddress(address);
|
|
2956
|
+
return true;
|
|
2957
|
+
}
|
|
2958
|
+
catch (_a) {
|
|
2959
|
+
return false;
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
/**
|
|
2963
|
+
* Validates if the address is in raw hex format (e.g., "0:1234..." or "-1:1234...").
|
|
2964
|
+
* @param address address to validate
|
|
2965
|
+
* @returns true if the address is valid raw format, false otherwise
|
|
2966
|
+
*/
|
|
2967
|
+
function isValidRawAddress(address) {
|
|
2968
|
+
try {
|
|
2969
|
+
parseHexAddress(address);
|
|
2970
|
+
return true;
|
|
2971
|
+
}
|
|
2972
|
+
catch (_a) {
|
|
2973
|
+
return false;
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
/**
|
|
2977
|
+
* Parses user-friendly address and returns its components.
|
|
2978
|
+
* @param address user-friendly address
|
|
2979
|
+
* @returns parsed address components
|
|
2980
|
+
*/
|
|
2981
|
+
function parseUserFriendlyAddress(address) {
|
|
2982
|
+
const base64 = address.replace(/-/g, '+').replace(/_/g, '/');
|
|
2983
|
+
let decoded;
|
|
2984
|
+
try {
|
|
2985
|
+
decoded = protocol.Base64.decode(base64).toUint8Array();
|
|
2986
|
+
}
|
|
2987
|
+
catch (_a) {
|
|
2988
|
+
throw new WrongAddressError(`Invalid base64 encoding in address: ${address}`);
|
|
2989
|
+
}
|
|
2990
|
+
if (decoded.length !== 36) {
|
|
2991
|
+
throw new WrongAddressError(`Invalid address length: ${address}`);
|
|
2992
|
+
}
|
|
2993
|
+
const addr = decoded.slice(0, 34);
|
|
2994
|
+
const checksum = decoded.slice(34);
|
|
2995
|
+
const calculatedChecksum = crc16(addr);
|
|
2996
|
+
if (!checksum.every((byte, i) => byte === calculatedChecksum[i])) {
|
|
2997
|
+
throw new WrongAddressError(`Invalid checksum in address: ${address}`);
|
|
2998
|
+
}
|
|
2999
|
+
const tag = addr[0];
|
|
3000
|
+
const wc = addr[1];
|
|
3001
|
+
const hex = addr.slice(2);
|
|
3002
|
+
if (wc !== 0 && wc !== -1) {
|
|
3003
|
+
throw new WrongAddressError(`Invalid workchain: ${wc}`);
|
|
3004
|
+
}
|
|
3005
|
+
const testOnly = (tag & testOnlyTag) !== 0;
|
|
3006
|
+
const isBounceable = (tag & 0x40) !== 0;
|
|
3007
|
+
return {
|
|
3008
|
+
wc,
|
|
3009
|
+
hex: Array.from(hex).map(b => b.toString(16).padStart(2, '0')).join(''),
|
|
3010
|
+
testOnly,
|
|
3011
|
+
isBounceable
|
|
3012
|
+
};
|
|
3013
|
+
}
|
|
3014
|
+
function parseHexAddress(hexAddress) {
|
|
3015
|
+
if (!hexAddress.includes(':')) {
|
|
3016
|
+
throw new WrongAddressError(`Wrong address ${hexAddress}. Address must include ":".`);
|
|
3017
|
+
}
|
|
3018
|
+
const parts = hexAddress.split(':');
|
|
3019
|
+
if (parts.length !== 2) {
|
|
3020
|
+
throw new WrongAddressError(`Wrong address ${hexAddress}. Address must include ":" only once.`);
|
|
3021
|
+
}
|
|
3022
|
+
const wc = parseInt(parts[0]);
|
|
3023
|
+
if (wc !== 0 && wc !== -1) {
|
|
3024
|
+
throw new WrongAddressError(`Wrong address ${hexAddress}. WC must be eq 0 or -1, but ${wc} received.`);
|
|
3025
|
+
}
|
|
3026
|
+
const hex = parts[1];
|
|
3027
|
+
if ((hex === null || hex === void 0 ? void 0 : hex.length) !== 64) {
|
|
3028
|
+
throw new WrongAddressError(`Wrong address ${hexAddress}. Hex part must be 64bytes length, but ${hex === null || hex === void 0 ? void 0 : hex.length} received.`);
|
|
3029
|
+
}
|
|
3030
|
+
return {
|
|
3031
|
+
wc,
|
|
3032
|
+
hex: hexToBytes(hex)
|
|
3033
|
+
};
|
|
3034
|
+
}
|
|
3035
|
+
function crc16(data) {
|
|
3036
|
+
const poly = 0x1021;
|
|
3037
|
+
let reg = 0;
|
|
3038
|
+
const message = new Uint8Array(data.length + 2);
|
|
3039
|
+
message.set(data);
|
|
3040
|
+
for (let byte of message) {
|
|
3041
|
+
let mask = 0x80;
|
|
3042
|
+
while (mask > 0) {
|
|
3043
|
+
reg <<= 1;
|
|
3044
|
+
if (byte & mask) {
|
|
3045
|
+
reg += 1;
|
|
3046
|
+
}
|
|
3047
|
+
mask >>= 1;
|
|
3048
|
+
if (reg > 0xffff) {
|
|
3049
|
+
reg &= 0xffff;
|
|
3050
|
+
reg ^= poly;
|
|
3051
|
+
}
|
|
2821
3052
|
}
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
3053
|
+
}
|
|
3054
|
+
return new Uint8Array([Math.floor(reg / 256), reg % 256]);
|
|
3055
|
+
}
|
|
3056
|
+
const toByteMap = {};
|
|
3057
|
+
for (let ord = 0; ord <= 0xff; ord++) {
|
|
3058
|
+
let s = ord.toString(16);
|
|
3059
|
+
if (s.length < 2) {
|
|
3060
|
+
s = '0' + s;
|
|
3061
|
+
}
|
|
3062
|
+
toByteMap[s] = ord;
|
|
3063
|
+
}
|
|
3064
|
+
function hexToBytes(hex) {
|
|
3065
|
+
hex = hex.toLowerCase();
|
|
3066
|
+
const length2 = hex.length;
|
|
3067
|
+
if (length2 % 2 !== 0) {
|
|
3068
|
+
throw new ParseHexError('Hex string must have length a multiple of 2: ' + hex);
|
|
3069
|
+
}
|
|
3070
|
+
const length = length2 / 2;
|
|
3071
|
+
const result = new Uint8Array(length);
|
|
3072
|
+
for (let i = 0; i < length; i++) {
|
|
3073
|
+
const doubled = i * 2;
|
|
3074
|
+
const hexSubstring = hex.substring(doubled, doubled + 2);
|
|
3075
|
+
if (!toByteMap.hasOwnProperty(hexSubstring)) {
|
|
3076
|
+
throw new ParseHexError('Invalid hex character: ' + hexSubstring);
|
|
3077
|
+
}
|
|
3078
|
+
result[i] = toByteMap[hexSubstring];
|
|
3079
|
+
}
|
|
3080
|
+
return result;
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
const BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
3084
|
+
const BOC_PREFIX = 'te6cc';
|
|
3085
|
+
const INTEGER_REGEX = /^-?\d+$/;
|
|
3086
|
+
const POSITIVE_INTEGER_REGEX = /^\d+$/;
|
|
3087
|
+
function isValidNumber(value) {
|
|
3088
|
+
return typeof value === 'number' && !isNaN(value);
|
|
3089
|
+
}
|
|
3090
|
+
function isValidString(value) {
|
|
3091
|
+
return typeof value === 'string' && value.length > 0;
|
|
3092
|
+
}
|
|
3093
|
+
function isValidBoc(value) {
|
|
3094
|
+
return typeof value === 'string' && BASE64_REGEX.test(value) && value.startsWith(BOC_PREFIX);
|
|
3095
|
+
}
|
|
3096
|
+
function isValidObject(value) {
|
|
3097
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3098
|
+
}
|
|
3099
|
+
function isValidArray(value) {
|
|
3100
|
+
return Array.isArray(value);
|
|
3101
|
+
}
|
|
3102
|
+
function hasExtraProperties(obj, allowedKeys) {
|
|
3103
|
+
return Object.keys(obj).some(key => !allowedKeys.includes(key));
|
|
3104
|
+
}
|
|
3105
|
+
function validateSendTransactionRequest(data) {
|
|
3106
|
+
console.log('[Validation Debug] validateSendTransactionRequest called');
|
|
3107
|
+
console.log('[Validation Debug] isQaModeEnabled():', isQaModeEnabled());
|
|
3108
|
+
if (!isValidObject(data)) {
|
|
3109
|
+
const error = "Request must be an object";
|
|
3110
|
+
logValidationError(error);
|
|
3111
|
+
const shouldReturnNull = isQaModeEnabled();
|
|
3112
|
+
console.log('[Validation Debug] Should return null:', shouldReturnNull);
|
|
3113
|
+
return shouldReturnNull ? null : error;
|
|
3114
|
+
}
|
|
3115
|
+
const allowedKeys = ['validUntil', 'network', 'from', 'messages'];
|
|
3116
|
+
if (hasExtraProperties(data, allowedKeys)) {
|
|
3117
|
+
const error = "Request contains extra properties";
|
|
3118
|
+
logValidationError(error);
|
|
3119
|
+
return isQaModeEnabled() ? null : error;
|
|
3120
|
+
}
|
|
3121
|
+
if (!isValidNumber(data.validUntil)) {
|
|
3122
|
+
const error = "Incorrect 'validUntil'";
|
|
3123
|
+
logValidationError(error);
|
|
3124
|
+
return isQaModeEnabled() ? null : error;
|
|
3125
|
+
}
|
|
3126
|
+
const now = Math.floor(Date.now() / 1000);
|
|
3127
|
+
const fiveMinutesFromNow = now + 300;
|
|
3128
|
+
if (data.validUntil > fiveMinutesFromNow) {
|
|
3129
|
+
console.warn(`validUntil (${data.validUntil}) is more than 5 minutes from now (${now})`);
|
|
3130
|
+
}
|
|
3131
|
+
if (data.network !== undefined) {
|
|
3132
|
+
if (!isValidString(data.network) || !/^[\d-]+$/.test(data.network)) {
|
|
3133
|
+
const error = "Invalid 'network' format";
|
|
3134
|
+
logValidationError(error);
|
|
3135
|
+
return isQaModeEnabled() ? null : error;
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
if (data.from !== undefined) {
|
|
3139
|
+
if (!isValidString(data.from) || !isValidRawAddress(data.from)) {
|
|
3140
|
+
const error = "Invalid 'from' address format";
|
|
3141
|
+
logValidationError(error);
|
|
3142
|
+
return isQaModeEnabled() ? null : error;
|
|
2825
3143
|
}
|
|
2826
3144
|
}
|
|
3145
|
+
if (!isValidArray(data.messages) || data.messages.length === 0) {
|
|
3146
|
+
const error = "'messages' is required";
|
|
3147
|
+
logValidationError(error);
|
|
3148
|
+
return isQaModeEnabled() ? null : error;
|
|
3149
|
+
}
|
|
3150
|
+
for (let i = 0; i < data.messages.length; i++) {
|
|
3151
|
+
const message = data.messages[i];
|
|
3152
|
+
const messageError = validateTransactionMessage(message, i);
|
|
3153
|
+
if (messageError) {
|
|
3154
|
+
return messageError;
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
return null;
|
|
3158
|
+
}
|
|
3159
|
+
function validateTransactionMessage(message, index) {
|
|
3160
|
+
if (!isValidObject(message)) {
|
|
3161
|
+
return `Message at index ${index} must be an object`;
|
|
3162
|
+
}
|
|
3163
|
+
const allowedKeys = ['address', 'amount', 'stateInit', 'payload', 'extraCurrency'];
|
|
3164
|
+
if (hasExtraProperties(message, allowedKeys)) {
|
|
3165
|
+
return `Message at index ${index} contains extra properties`;
|
|
3166
|
+
}
|
|
3167
|
+
if (!isValidString(message.address)) {
|
|
3168
|
+
return `'address' is required in message at index ${index}`;
|
|
3169
|
+
}
|
|
3170
|
+
if (!isValidUserFriendlyAddress(message.address)) {
|
|
3171
|
+
return `Wrong 'address' format in message at index ${index}`;
|
|
3172
|
+
}
|
|
3173
|
+
if (!isValidString(message.amount)) {
|
|
3174
|
+
return `'amount' is required in message at index ${index}`;
|
|
3175
|
+
}
|
|
3176
|
+
if (!/^[0-9]+$/.test(message.amount)) {
|
|
3177
|
+
return `Incorrect 'amount' in message at index ${index}`;
|
|
3178
|
+
}
|
|
3179
|
+
if (message.stateInit !== undefined) {
|
|
3180
|
+
if (!isValidString(message.stateInit) || !isValidBoc(message.stateInit)) {
|
|
3181
|
+
return `Invalid 'stateInit' in message at index ${index}`;
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
if (message.payload !== undefined) {
|
|
3185
|
+
if (!isValidString(message.payload) || !isValidBoc(message.payload)) {
|
|
3186
|
+
return `Invalid 'payload' in message at index ${index}`;
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
if (message.extraCurrency !== undefined) {
|
|
3190
|
+
if (!isValidObject(message.extraCurrency)) {
|
|
3191
|
+
return `Invalid 'extraCurrency' in message at index ${index}`;
|
|
3192
|
+
}
|
|
3193
|
+
for (const [key, value] of Object.entries(message.extraCurrency)) {
|
|
3194
|
+
if (!INTEGER_REGEX.test(key) || typeof value !== 'string' || !POSITIVE_INTEGER_REGEX.test(value)) {
|
|
3195
|
+
return `Invalid 'extraCurrency' format in message at index ${index}`;
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3199
|
+
return null;
|
|
3200
|
+
}
|
|
3201
|
+
function validateConnectAdditionalRequest(data) {
|
|
3202
|
+
if (!isValidObject(data)) {
|
|
3203
|
+
return "Request must be an object";
|
|
3204
|
+
}
|
|
3205
|
+
const allowedKeys = ['tonProof'];
|
|
3206
|
+
if (hasExtraProperties(data, allowedKeys)) {
|
|
3207
|
+
return "Request contains extra properties";
|
|
3208
|
+
}
|
|
3209
|
+
if (data.tonProof !== undefined && !isValidString(data.tonProof)) {
|
|
3210
|
+
return "Invalid 'tonProof'";
|
|
3211
|
+
}
|
|
3212
|
+
return null;
|
|
3213
|
+
}
|
|
3214
|
+
function validateSignDataPayload(data) {
|
|
3215
|
+
if (!isValidObject(data)) {
|
|
3216
|
+
return "Payload must be an object";
|
|
3217
|
+
}
|
|
3218
|
+
if (!isValidString(data.type)) {
|
|
3219
|
+
return "'type' is required";
|
|
3220
|
+
}
|
|
3221
|
+
switch (data.type) {
|
|
3222
|
+
case 'text':
|
|
3223
|
+
return validateSignDataPayloadText(data);
|
|
3224
|
+
case 'binary':
|
|
3225
|
+
return validateSignDataPayloadBinary(data);
|
|
3226
|
+
case 'cell':
|
|
3227
|
+
return validateSignDataPayloadCell(data);
|
|
3228
|
+
default:
|
|
3229
|
+
return "Invalid 'type' value";
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
function validateSignDataPayloadText(data) {
|
|
3233
|
+
const allowedKeys = ['type', 'text', 'network', 'from'];
|
|
3234
|
+
if (hasExtraProperties(data, allowedKeys)) {
|
|
3235
|
+
return "Text payload contains extra properties";
|
|
3236
|
+
}
|
|
3237
|
+
if (!isValidString(data.text)) {
|
|
3238
|
+
return "'text' is required";
|
|
3239
|
+
}
|
|
3240
|
+
if (data.network !== undefined) {
|
|
3241
|
+
if (!isValidString(data.network) || !/^\d+$/.test(data.network)) {
|
|
3242
|
+
return "Invalid 'network' format";
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
if (data.from !== undefined && !isValidString(data.from)) {
|
|
3246
|
+
return "Invalid 'from'";
|
|
3247
|
+
}
|
|
3248
|
+
return null;
|
|
3249
|
+
}
|
|
3250
|
+
function validateSignDataPayloadBinary(data) {
|
|
3251
|
+
const allowedKeys = ['type', 'bytes', 'network', 'from'];
|
|
3252
|
+
if (hasExtraProperties(data, allowedKeys)) {
|
|
3253
|
+
return "Binary payload contains extra properties";
|
|
3254
|
+
}
|
|
3255
|
+
if (!isValidString(data.bytes)) {
|
|
3256
|
+
return "'bytes' is required";
|
|
3257
|
+
}
|
|
3258
|
+
if (data.network !== undefined) {
|
|
3259
|
+
if (!isValidString(data.network) || !/^\d+$/.test(data.network)) {
|
|
3260
|
+
return "Invalid 'network' format";
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3263
|
+
if (data.from !== undefined && !isValidString(data.from)) {
|
|
3264
|
+
return "Invalid 'from'";
|
|
3265
|
+
}
|
|
3266
|
+
return null;
|
|
3267
|
+
}
|
|
3268
|
+
function validateSignDataPayloadCell(data) {
|
|
3269
|
+
const allowedKeys = ['type', 'schema', 'cell', 'network', 'from'];
|
|
3270
|
+
if (hasExtraProperties(data, allowedKeys)) {
|
|
3271
|
+
return "Cell payload contains extra properties";
|
|
3272
|
+
}
|
|
3273
|
+
if (!isValidString(data.schema)) {
|
|
3274
|
+
return "'schema' is required";
|
|
3275
|
+
}
|
|
3276
|
+
if (!isValidString(data.cell)) {
|
|
3277
|
+
return "'cell' is required";
|
|
3278
|
+
}
|
|
3279
|
+
if (!isValidBoc(data.cell)) {
|
|
3280
|
+
return "Invalid 'cell' format (must be valid base64)";
|
|
3281
|
+
}
|
|
3282
|
+
if (data.network !== undefined) {
|
|
3283
|
+
if (!isValidString(data.network) || !/^\d+$/.test(data.network)) {
|
|
3284
|
+
return "Invalid 'network' format";
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
if (data.from !== undefined && !isValidString(data.from)) {
|
|
3288
|
+
return "Invalid 'from'";
|
|
3289
|
+
}
|
|
3290
|
+
return null;
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3293
|
+
class TonConnect {
|
|
2827
3294
|
/**
|
|
2828
3295
|
* Returns available wallets list.
|
|
2829
3296
|
*/
|
|
@@ -2853,6 +3320,33 @@ class TonConnect {
|
|
|
2853
3320
|
this._wallet = value;
|
|
2854
3321
|
this.statusChangeSubscriptions.forEach(callback => callback(this._wallet));
|
|
2855
3322
|
}
|
|
3323
|
+
constructor(options) {
|
|
3324
|
+
this.walletsList = new WalletsListManager();
|
|
3325
|
+
this._wallet = null;
|
|
3326
|
+
this.provider = null;
|
|
3327
|
+
this.statusChangeSubscriptions = [];
|
|
3328
|
+
this.statusChangeErrorSubscriptions = [];
|
|
3329
|
+
this.dappSettings = {
|
|
3330
|
+
manifestUrl: (options === null || options === void 0 ? void 0 : options.manifestUrl) || getWebPageManifest(),
|
|
3331
|
+
storage: (options === null || options === void 0 ? void 0 : options.storage) || new DefaultStorage()
|
|
3332
|
+
};
|
|
3333
|
+
this.walletsRequiredFeatures = options === null || options === void 0 ? void 0 : options.walletsRequiredFeatures;
|
|
3334
|
+
this.walletsList = new WalletsListManager({
|
|
3335
|
+
walletsListSource: options === null || options === void 0 ? void 0 : options.walletsListSource,
|
|
3336
|
+
cacheTTLMs: options === null || options === void 0 ? void 0 : options.walletsListCacheTTLMs
|
|
3337
|
+
});
|
|
3338
|
+
this.tracker = new TonConnectTracker({
|
|
3339
|
+
eventDispatcher: options === null || options === void 0 ? void 0 : options.eventDispatcher,
|
|
3340
|
+
tonConnectSdkVersion: tonConnectSdkVersion
|
|
3341
|
+
});
|
|
3342
|
+
if (!this.dappSettings.manifestUrl) {
|
|
3343
|
+
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');
|
|
3344
|
+
}
|
|
3345
|
+
this.bridgeConnectionStorage = new BridgeConnectionStorage(this.dappSettings.storage);
|
|
3346
|
+
if (!(options === null || options === void 0 ? void 0 : options.disableAutoPauseConnection)) {
|
|
3347
|
+
this.addWindowFocusAndBlurSubscriptions();
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
2856
3350
|
/**
|
|
2857
3351
|
* Returns available wallets list.
|
|
2858
3352
|
*/
|
|
@@ -2892,6 +3386,17 @@ class TonConnect {
|
|
|
2892
3386
|
options.openingDeadlineMS = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.openingDeadlineMS;
|
|
2893
3387
|
options.signal = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.signal;
|
|
2894
3388
|
}
|
|
3389
|
+
if (options.request) {
|
|
3390
|
+
const validationError = validateConnectAdditionalRequest(options.request);
|
|
3391
|
+
if (validationError) {
|
|
3392
|
+
if (isQaModeEnabled()) {
|
|
3393
|
+
console.error('ConnectAdditionalRequest validation failed: ' + validationError);
|
|
3394
|
+
}
|
|
3395
|
+
else {
|
|
3396
|
+
throw new TonConnectError('ConnectAdditionalRequest validation failed: ' + validationError);
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
2895
3400
|
if (this.connected) {
|
|
2896
3401
|
throw new WalletAlreadyConnectedError();
|
|
2897
3402
|
}
|
|
@@ -2918,8 +3423,8 @@ class TonConnect {
|
|
|
2918
3423
|
* Try to restore existing session and reconnect to the corresponding wallet. Call it immediately when your app is loaded.
|
|
2919
3424
|
*/
|
|
2920
3425
|
restoreConnection(options) {
|
|
2921
|
-
var _a, _b;
|
|
2922
3426
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3427
|
+
var _a, _b;
|
|
2923
3428
|
this.tracker.trackConnectionRestoringStarted();
|
|
2924
3429
|
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
2925
3430
|
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
@@ -3014,6 +3519,16 @@ class TonConnect {
|
|
|
3014
3519
|
options.onRequestSent = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.onRequestSent;
|
|
3015
3520
|
options.signal = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.signal;
|
|
3016
3521
|
}
|
|
3522
|
+
// Validate transaction
|
|
3523
|
+
const validationError = validateSendTransactionRequest(transaction);
|
|
3524
|
+
if (validationError) {
|
|
3525
|
+
if (isQaModeEnabled()) {
|
|
3526
|
+
console.error('SendTransactionRequest validation failed: ' + validationError);
|
|
3527
|
+
}
|
|
3528
|
+
else {
|
|
3529
|
+
throw new TonConnectError('SendTransactionRequest validation failed: ' + validationError);
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3017
3532
|
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
3018
3533
|
if (abortController.signal.aborted) {
|
|
3019
3534
|
throw new TonConnectError('Transaction sending was aborted');
|
|
@@ -3049,6 +3564,16 @@ class TonConnect {
|
|
|
3049
3564
|
if (abortController.signal.aborted) {
|
|
3050
3565
|
throw new TonConnectError('data sending was aborted');
|
|
3051
3566
|
}
|
|
3567
|
+
// Validate sign data
|
|
3568
|
+
const validationError = validateSignDataPayload(data);
|
|
3569
|
+
if (validationError) {
|
|
3570
|
+
if (isQaModeEnabled()) {
|
|
3571
|
+
console.error('SignDataPayload validation failed: ' + validationError);
|
|
3572
|
+
}
|
|
3573
|
+
else {
|
|
3574
|
+
throw new TonConnectError('SignDataPayload validation failed: ' + validationError);
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3052
3577
|
this.checkConnection();
|
|
3053
3578
|
checkSignDataSupport(this.wallet.device.features, { requiredTypes: [data.type] });
|
|
3054
3579
|
this.tracker.trackDataSentForSignature(this.wallet, data);
|
|
@@ -3069,8 +3594,8 @@ class TonConnect {
|
|
|
3069
3594
|
* Disconnect form thw connected wallet and drop current session.
|
|
3070
3595
|
*/
|
|
3071
3596
|
disconnect(options) {
|
|
3072
|
-
var _a;
|
|
3073
3597
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3598
|
+
var _a;
|
|
3074
3599
|
if (!this.connected) {
|
|
3075
3600
|
throw new WalletNotConnectedError();
|
|
3076
3601
|
}
|
|
@@ -3266,98 +3791,6 @@ TonConnect.isWalletInjected = (walletJSKey) => InjectedProvider.isWalletInjected
|
|
|
3266
3791
|
*/
|
|
3267
3792
|
TonConnect.isInsideWalletBrowser = (walletJSKey) => InjectedProvider.isInsideWalletBrowser(walletJSKey);
|
|
3268
3793
|
|
|
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
3794
|
Object.defineProperty(exports, 'CHAIN', {
|
|
3362
3795
|
enumerable: true,
|
|
3363
3796
|
get: function () { return protocol.CHAIN; }
|
|
@@ -3413,7 +3846,9 @@ exports.createTransactionSignedEvent = createTransactionSignedEvent;
|
|
|
3413
3846
|
exports.createTransactionSigningFailedEvent = createTransactionSigningFailedEvent;
|
|
3414
3847
|
exports.createVersionInfo = createVersionInfo;
|
|
3415
3848
|
exports.default = TonConnect;
|
|
3849
|
+
exports.enableQaMode = enableQaMode;
|
|
3416
3850
|
exports.encodeTelegramUrlParameters = encodeTelegramUrlParameters;
|
|
3851
|
+
exports.isQaModeEnabled = isQaModeEnabled;
|
|
3417
3852
|
exports.isTelegramUrl = isTelegramUrl;
|
|
3418
3853
|
exports.isWalletInfoCurrentlyEmbedded = isWalletInfoCurrentlyEmbedded;
|
|
3419
3854
|
exports.isWalletInfoCurrentlyInjected = isWalletInfoCurrentlyInjected;
|