@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/dist/tonconnect-sdk.min.js +1 -1
- package/dist/tonconnect-sdk.min.js.map +1 -1
- package/lib/cjs/index.cjs +639 -192
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/index.mjs +633 -188
- package/lib/esm/index.mjs.map +1 -1
- package/lib/types/index.d.ts +4 -0
- package/package.json +19 -23
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 =
|
|
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 =
|
|
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
|
-
|
|
2093
|
-
|
|
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.
|
|
2926
|
+
const tonConnectSdkVersion = "3.3.0-beta.2";
|
|
2798
2927
|
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
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
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
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) {
|
|
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) {
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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;
|