@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/esm/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ export { CHAIN, CONNECT_EVENT_ERROR_CODES, CONNECT_ITEM_ERROR_CODES, SEND_TRANSA
|
|
|
3
3
|
import '@tonconnect/isomorphic-eventsource';
|
|
4
4
|
import '@tonconnect/isomorphic-fetch';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
/******************************************************************************
|
|
7
7
|
Copyright (c) Microsoft Corporation.
|
|
8
8
|
|
|
9
9
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
@@ -17,6 +17,8 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
17
17
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
18
18
|
PERFORMANCE OF THIS SOFTWARE.
|
|
19
19
|
***************************************************************************** */
|
|
20
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
21
|
+
|
|
20
22
|
|
|
21
23
|
function __rest(s, e) {
|
|
22
24
|
var t = {};
|
|
@@ -38,20 +40,25 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
38
40
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
39
41
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
40
42
|
});
|
|
41
|
-
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
46
|
+
var e = new Error(message);
|
|
47
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
48
|
+
};
|
|
42
49
|
|
|
43
50
|
/**
|
|
44
51
|
* Base class for TonConnect errors. You can check if the error was triggered by the @tonconnect/sdk using `err instanceof TonConnectError`.
|
|
45
52
|
*/
|
|
46
53
|
class TonConnectError extends Error {
|
|
54
|
+
get info() {
|
|
55
|
+
return '';
|
|
56
|
+
}
|
|
47
57
|
constructor(message, options) {
|
|
48
58
|
super(message, options);
|
|
49
59
|
this.message = `${TonConnectError.prefix} ${this.constructor.name}${this.info ? ': ' + this.info : ''}${message ? '\n' + message : ''}`;
|
|
50
60
|
Object.setPrototypeOf(this, TonConnectError.prototype);
|
|
51
61
|
}
|
|
52
|
-
get info() {
|
|
53
|
-
return '';
|
|
54
|
-
}
|
|
55
62
|
}
|
|
56
63
|
TonConnectError.prefix = '[TON_CONNECT_SDK_ERROR]';
|
|
57
64
|
|
|
@@ -405,12 +412,12 @@ function delay(timeout, options) {
|
|
|
405
412
|
return __awaiter(this, void 0, void 0, function* () {
|
|
406
413
|
return new Promise((resolve, reject) => {
|
|
407
414
|
var _a, _b;
|
|
408
|
-
if ((_a =
|
|
415
|
+
if ((_a = void 0 ) === null || _a === void 0 ? void 0 : _a.aborted) {
|
|
409
416
|
reject(new TonConnectError('Delay aborted'));
|
|
410
417
|
return;
|
|
411
418
|
}
|
|
412
419
|
const timeoutId = setTimeout(() => resolve(), timeout);
|
|
413
|
-
(_b =
|
|
420
|
+
(_b = void 0 ) === null || _b === void 0 ? void 0 : _b.addEventListener('abort', () => {
|
|
414
421
|
clearTimeout(timeoutId);
|
|
415
422
|
reject(new TonConnectError('Delay aborted'));
|
|
416
423
|
});
|
|
@@ -441,9 +448,10 @@ function createAbortController(signal) {
|
|
|
441
448
|
* @param {T} fn - function to call
|
|
442
449
|
* @param {CallForSuccessOptions} [options] - optional configuration options
|
|
443
450
|
*/
|
|
451
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
444
452
|
function callForSuccess(fn, options) {
|
|
445
|
-
var _a, _b;
|
|
446
453
|
return __awaiter(this, void 0, void 0, function* () {
|
|
454
|
+
var _a, _b;
|
|
447
455
|
const attempts = (_a = options === null || options === void 0 ? void 0 : options.attempts) !== null && _a !== void 0 ? _a : 10;
|
|
448
456
|
const delayMs = (_b = options === null || options === void 0 ? void 0 : options.delayMs) !== null && _b !== void 0 ? _b : 200;
|
|
449
457
|
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
@@ -505,6 +513,7 @@ function logWarning(...args) {
|
|
|
505
513
|
* @param {(...args: Args) => Promise<T>} createFn - A function that creates the resource.
|
|
506
514
|
* @param {(resource: T) => Promise<void>} [disposeFn] - An optional function that disposes the resource.
|
|
507
515
|
*/
|
|
516
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
508
517
|
function createResource(createFn, disposeFn) {
|
|
509
518
|
let currentResource = null;
|
|
510
519
|
let currentArgs = null;
|
|
@@ -614,6 +623,18 @@ function timeout(fn, options) {
|
|
|
614
623
|
}
|
|
615
624
|
|
|
616
625
|
class BridgeGateway {
|
|
626
|
+
get isReady() {
|
|
627
|
+
const eventSource = this.eventSource.current();
|
|
628
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.OPEN;
|
|
629
|
+
}
|
|
630
|
+
get isClosed() {
|
|
631
|
+
const eventSource = this.eventSource.current();
|
|
632
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) !== EventSource.OPEN;
|
|
633
|
+
}
|
|
634
|
+
get isConnecting() {
|
|
635
|
+
const eventSource = this.eventSource.current();
|
|
636
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.CONNECTING;
|
|
637
|
+
}
|
|
617
638
|
constructor(storage, bridgeUrl, sessionId, listener, errorsListener) {
|
|
618
639
|
this.bridgeUrl = bridgeUrl;
|
|
619
640
|
this.sessionId = sessionId;
|
|
@@ -642,26 +663,14 @@ class BridgeGateway {
|
|
|
642
663
|
}));
|
|
643
664
|
this.bridgeGatewayStorage = new HttpBridgeGatewayStorage(storage, bridgeUrl);
|
|
644
665
|
}
|
|
645
|
-
get isReady() {
|
|
646
|
-
const eventSource = this.eventSource.current();
|
|
647
|
-
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.OPEN;
|
|
648
|
-
}
|
|
649
|
-
get isClosed() {
|
|
650
|
-
const eventSource = this.eventSource.current();
|
|
651
|
-
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) !== EventSource.OPEN;
|
|
652
|
-
}
|
|
653
|
-
get isConnecting() {
|
|
654
|
-
const eventSource = this.eventSource.current();
|
|
655
|
-
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.CONNECTING;
|
|
656
|
-
}
|
|
657
666
|
registerSession(options) {
|
|
658
667
|
return __awaiter(this, void 0, void 0, function* () {
|
|
659
668
|
yield this.eventSource.create(options === null || options === void 0 ? void 0 : options.signal, options === null || options === void 0 ? void 0 : options.openingDeadlineMS);
|
|
660
669
|
});
|
|
661
670
|
}
|
|
662
671
|
send(message, receiver, topic, ttlOrOptions) {
|
|
663
|
-
var _a;
|
|
664
672
|
return __awaiter(this, void 0, void 0, function* () {
|
|
673
|
+
var _a;
|
|
665
674
|
// TODO: remove deprecated method
|
|
666
675
|
const options = {};
|
|
667
676
|
if (typeof ttlOrOptions === 'number') {
|
|
@@ -1010,6 +1019,16 @@ class BridgeConnectionStorage {
|
|
|
1010
1019
|
const PROTOCOL_VERSION = 2;
|
|
1011
1020
|
|
|
1012
1021
|
class BridgeProvider {
|
|
1022
|
+
static fromStorage(storage) {
|
|
1023
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1024
|
+
const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
|
|
1025
|
+
const connection = yield bridgeConnectionStorage.getHttpConnection();
|
|
1026
|
+
if (isPendingConnectionHttp(connection)) {
|
|
1027
|
+
return new BridgeProvider(storage, connection.connectionSource);
|
|
1028
|
+
}
|
|
1029
|
+
return new BridgeProvider(storage, { bridgeUrl: connection.session.bridgeUrl });
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1013
1032
|
constructor(storage, walletConnectionSource) {
|
|
1014
1033
|
this.storage = storage;
|
|
1015
1034
|
this.walletConnectionSource = walletConnectionSource;
|
|
@@ -1024,16 +1043,6 @@ class BridgeProvider {
|
|
|
1024
1043
|
this.defaultRetryTimeoutMS = 2000;
|
|
1025
1044
|
this.connectionStorage = new BridgeConnectionStorage(storage);
|
|
1026
1045
|
}
|
|
1027
|
-
static fromStorage(storage) {
|
|
1028
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1029
|
-
const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
|
|
1030
|
-
const connection = yield bridgeConnectionStorage.getHttpConnection();
|
|
1031
|
-
if (isPendingConnectionHttp(connection)) {
|
|
1032
|
-
return new BridgeProvider(storage, connection.connectionSource);
|
|
1033
|
-
}
|
|
1034
|
-
return new BridgeProvider(storage, { bridgeUrl: connection.session.bridgeUrl });
|
|
1035
|
-
});
|
|
1036
|
-
}
|
|
1037
1046
|
connect(message, options) {
|
|
1038
1047
|
var _a;
|
|
1039
1048
|
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
@@ -1076,8 +1085,8 @@ class BridgeProvider {
|
|
|
1076
1085
|
return this.generateUniversalLink(universalLink, message);
|
|
1077
1086
|
}
|
|
1078
1087
|
restoreConnection(options) {
|
|
1079
|
-
var _a, _b;
|
|
1080
1088
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1089
|
+
var _a, _b;
|
|
1081
1090
|
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
1082
1091
|
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
1083
1092
|
this.abortController = abortController;
|
|
@@ -1423,15 +1432,15 @@ function isJSBridgeWithMetadata(value) {
|
|
|
1423
1432
|
* Uses as a fallback for localStorage in Safari's private mode.
|
|
1424
1433
|
*/
|
|
1425
1434
|
class InMemoryStorage {
|
|
1426
|
-
constructor() {
|
|
1427
|
-
this.storage = {};
|
|
1428
|
-
}
|
|
1429
1435
|
static getInstance() {
|
|
1430
1436
|
if (!InMemoryStorage.instance) {
|
|
1431
1437
|
InMemoryStorage.instance = new InMemoryStorage();
|
|
1432
1438
|
}
|
|
1433
1439
|
return InMemoryStorage.instance;
|
|
1434
1440
|
}
|
|
1441
|
+
constructor() {
|
|
1442
|
+
this.storage = {};
|
|
1443
|
+
}
|
|
1435
1444
|
get length() {
|
|
1436
1445
|
return Object.keys(this.storage).length;
|
|
1437
1446
|
}
|
|
@@ -1526,19 +1535,6 @@ function isNodeJs() {
|
|
|
1526
1535
|
}
|
|
1527
1536
|
|
|
1528
1537
|
class InjectedProvider {
|
|
1529
|
-
constructor(storage, injectedWalletKey) {
|
|
1530
|
-
this.injectedWalletKey = injectedWalletKey;
|
|
1531
|
-
this.type = 'injected';
|
|
1532
|
-
this.unsubscribeCallback = null;
|
|
1533
|
-
this.listenSubscriptions = false;
|
|
1534
|
-
this.listeners = [];
|
|
1535
|
-
const window = InjectedProvider.window;
|
|
1536
|
-
if (!InjectedProvider.isWindowContainsWallet(window, injectedWalletKey)) {
|
|
1537
|
-
throw new WalletNotInjectedError();
|
|
1538
|
-
}
|
|
1539
|
-
this.connectionStorage = new BridgeConnectionStorage(storage);
|
|
1540
|
-
this.injectedWallet = window[injectedWalletKey].tonconnect;
|
|
1541
|
-
}
|
|
1542
1538
|
static fromStorage(storage) {
|
|
1543
1539
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1544
1540
|
const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
|
|
@@ -1580,6 +1576,19 @@ class InjectedProvider {
|
|
|
1580
1576
|
typeof window[injectedWalletKey] === 'object' &&
|
|
1581
1577
|
'tonconnect' in window[injectedWalletKey]);
|
|
1582
1578
|
}
|
|
1579
|
+
constructor(storage, injectedWalletKey) {
|
|
1580
|
+
this.injectedWalletKey = injectedWalletKey;
|
|
1581
|
+
this.type = 'injected';
|
|
1582
|
+
this.unsubscribeCallback = null;
|
|
1583
|
+
this.listenSubscriptions = false;
|
|
1584
|
+
this.listeners = [];
|
|
1585
|
+
const window = InjectedProvider.window;
|
|
1586
|
+
if (!InjectedProvider.isWindowContainsWallet(window, injectedWalletKey)) {
|
|
1587
|
+
throw new WalletNotInjectedError();
|
|
1588
|
+
}
|
|
1589
|
+
this.connectionStorage = new BridgeConnectionStorage(storage);
|
|
1590
|
+
this.injectedWallet = window[injectedWalletKey].tonconnect;
|
|
1591
|
+
}
|
|
1583
1592
|
connect(message) {
|
|
1584
1593
|
this._connect(PROTOCOL_VERSION, message);
|
|
1585
1594
|
}
|
|
@@ -1641,8 +1650,8 @@ class InjectedProvider {
|
|
|
1641
1650
|
return () => (this.listeners = this.listeners.filter(listener => listener !== eventsCallback));
|
|
1642
1651
|
}
|
|
1643
1652
|
sendRequest(request, optionsOrOnRequestSent) {
|
|
1644
|
-
var _a;
|
|
1645
1653
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1654
|
+
var _a;
|
|
1646
1655
|
// TODO: remove deprecated method
|
|
1647
1656
|
const options = {};
|
|
1648
1657
|
if (typeof optionsOrOnRequestSent === 'function') {
|
|
@@ -2081,13 +2090,133 @@ const FALLBACK_WALLETS_LIST = [
|
|
|
2081
2090
|
}
|
|
2082
2091
|
];
|
|
2083
2092
|
|
|
2093
|
+
let qaModeEnabled = false;
|
|
2094
|
+
let bannerObserver = null;
|
|
2095
|
+
function enableQaMode() {
|
|
2096
|
+
qaModeEnabled = true;
|
|
2097
|
+
console.warn('🚨 QA Mode enabled - validation is disabled. This is unsafe for production!');
|
|
2098
|
+
showQaModeBanner();
|
|
2099
|
+
startBannerObserver();
|
|
2100
|
+
addQaModeStyles();
|
|
2101
|
+
}
|
|
2102
|
+
function isQaModeEnabled() {
|
|
2103
|
+
return qaModeEnabled;
|
|
2104
|
+
}
|
|
2105
|
+
function logValidationError(message) {
|
|
2106
|
+
if (isQaModeEnabled()) {
|
|
2107
|
+
console.error(`[QA Mode] Validation failed: ${message}`);
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
function showQaModeBanner() {
|
|
2111
|
+
if (typeof window === 'undefined')
|
|
2112
|
+
return;
|
|
2113
|
+
const existingBanner = document.getElementById('ton-connect-qa-banner');
|
|
2114
|
+
if (existingBanner)
|
|
2115
|
+
return;
|
|
2116
|
+
const banner = document.createElement('div');
|
|
2117
|
+
banner.id = 'ton-connect-qa-banner';
|
|
2118
|
+
banner.style.cssText = `
|
|
2119
|
+
position: fixed;
|
|
2120
|
+
top: 0;
|
|
2121
|
+
left: 0;
|
|
2122
|
+
right: 0;
|
|
2123
|
+
background: linear-gradient(90deg, #ff6b6b, #ff8e8e);
|
|
2124
|
+
color: white;
|
|
2125
|
+
padding: 12px 20px;
|
|
2126
|
+
text-align: center;
|
|
2127
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
2128
|
+
font-weight: 600;
|
|
2129
|
+
font-size: 14px;
|
|
2130
|
+
z-index: 999999;
|
|
2131
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
|
2132
|
+
animation: slideDown 0.3s ease-out;
|
|
2133
|
+
user-select: none;
|
|
2134
|
+
pointer-events: none;
|
|
2135
|
+
`;
|
|
2136
|
+
banner.innerHTML = `
|
|
2137
|
+
🚨 QA Mode Active - Validation Disabled (Unsafe for Production)
|
|
2138
|
+
`;
|
|
2139
|
+
// Add CSS animation
|
|
2140
|
+
const style = document.createElement('style');
|
|
2141
|
+
style.textContent = `
|
|
2142
|
+
@keyframes slideDown {
|
|
2143
|
+
from { transform: translateY(-100%); }
|
|
2144
|
+
to { transform: translateY(0); }
|
|
2145
|
+
}
|
|
2146
|
+
`;
|
|
2147
|
+
document.head.appendChild(style);
|
|
2148
|
+
document.body.appendChild(banner);
|
|
2149
|
+
addQaModeStyles();
|
|
2150
|
+
}
|
|
2151
|
+
function addQaModeStyles() {
|
|
2152
|
+
if (typeof window === 'undefined')
|
|
2153
|
+
return;
|
|
2154
|
+
const existingStyle = document.getElementById('ton-connect-qa-mode-styles');
|
|
2155
|
+
if (existingStyle)
|
|
2156
|
+
return;
|
|
2157
|
+
const style = document.createElement('style');
|
|
2158
|
+
style.id = 'ton-connect-qa-mode-styles';
|
|
2159
|
+
style.textContent = `
|
|
2160
|
+
body.qa-mode-active {
|
|
2161
|
+
padding-top: 48px !important;
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
body.qa-mode-active header {
|
|
2165
|
+
margin-top: 48px !important;
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
body.qa-mode-active .qa-mode-control {
|
|
2169
|
+
top: 128px !important;
|
|
2170
|
+
}
|
|
2171
|
+
`;
|
|
2172
|
+
document.head.appendChild(style);
|
|
2173
|
+
document.body.classList.add('qa-mode-active');
|
|
2174
|
+
}
|
|
2175
|
+
function startBannerObserver() {
|
|
2176
|
+
if (typeof window === 'undefined' || bannerObserver)
|
|
2177
|
+
return;
|
|
2178
|
+
bannerObserver = new MutationObserver(mutations => {
|
|
2179
|
+
mutations.forEach(mutation => {
|
|
2180
|
+
if (mutation.type === 'childList') {
|
|
2181
|
+
mutation.removedNodes.forEach(node => {
|
|
2182
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
2183
|
+
const element = node;
|
|
2184
|
+
if (element.id === 'ton-connect-qa-banner' && qaModeEnabled) {
|
|
2185
|
+
console.warn('QA Mode banner was removed, restoring...');
|
|
2186
|
+
setTimeout(() => showQaModeBanner(), 100);
|
|
2187
|
+
}
|
|
2188
|
+
else if (element.id === 'ton-connect-qa-mode-styles' && qaModeEnabled) {
|
|
2189
|
+
console.warn('QA Mode styles were removed, restoring...');
|
|
2190
|
+
setTimeout(() => addQaModeStyles(), 100);
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
});
|
|
2194
|
+
}
|
|
2195
|
+
});
|
|
2196
|
+
});
|
|
2197
|
+
bannerObserver.observe(document.body, {
|
|
2198
|
+
childList: true,
|
|
2199
|
+
subtree: false
|
|
2200
|
+
});
|
|
2201
|
+
bannerObserver.observe(document.head, {
|
|
2202
|
+
childList: true,
|
|
2203
|
+
subtree: false
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2084
2207
|
class WalletsListManager {
|
|
2085
2208
|
constructor(options) {
|
|
2086
2209
|
var _a;
|
|
2087
2210
|
this.walletsListCache = null;
|
|
2088
2211
|
this.walletsListCacheCreationTimestamp = null;
|
|
2089
|
-
|
|
2090
|
-
|
|
2212
|
+
if (isQaModeEnabled()) {
|
|
2213
|
+
this.walletsListSource =
|
|
2214
|
+
'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
|
+
}
|
|
2091
2220
|
this.cacheTTLMs = options === null || options === void 0 ? void 0 : options.cacheTTLMs;
|
|
2092
2221
|
}
|
|
2093
2222
|
getWallets() {
|
|
@@ -2514,8 +2643,8 @@ class BrowserEventDispatcher {
|
|
|
2514
2643
|
* @returns A promise that resolves when the event has been dispatched.
|
|
2515
2644
|
*/
|
|
2516
2645
|
dispatchEvent(eventName, eventDetails) {
|
|
2517
|
-
var _a;
|
|
2518
2646
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2647
|
+
var _a;
|
|
2519
2648
|
const event = new CustomEvent(eventName, { detail: eventDetails });
|
|
2520
2649
|
(_a = this.window) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
|
|
2521
2650
|
});
|
|
@@ -2528,8 +2657,8 @@ class BrowserEventDispatcher {
|
|
|
2528
2657
|
* @returns A function that removes the listener.
|
|
2529
2658
|
*/
|
|
2530
2659
|
addEventListener(eventName, listener, options) {
|
|
2531
|
-
var _a;
|
|
2532
2660
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2661
|
+
var _a;
|
|
2533
2662
|
(_a = this.window) === null || _a === void 0 ? void 0 : _a.addEventListener(eventName, listener, options);
|
|
2534
2663
|
return () => {
|
|
2535
2664
|
var _a;
|
|
@@ -2567,6 +2696,15 @@ class BrowserEventDispatcher {
|
|
|
2567
2696
|
* @internal
|
|
2568
2697
|
*/
|
|
2569
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
|
+
}
|
|
2570
2708
|
constructor(options) {
|
|
2571
2709
|
var _a;
|
|
2572
2710
|
/**
|
|
@@ -2582,15 +2720,6 @@ class TonConnectTracker {
|
|
|
2582
2720
|
this.tonConnectSdkVersion = options.tonConnectSdkVersion;
|
|
2583
2721
|
this.init().catch();
|
|
2584
2722
|
}
|
|
2585
|
-
/**
|
|
2586
|
-
* Version of the library.
|
|
2587
|
-
*/
|
|
2588
|
-
get version() {
|
|
2589
|
-
return createVersionInfo({
|
|
2590
|
-
ton_connect_sdk_lib: this.tonConnectSdkVersion,
|
|
2591
|
-
ton_connect_ui_lib: this.tonConnectUiVersion
|
|
2592
|
-
});
|
|
2593
|
-
}
|
|
2594
2723
|
/**
|
|
2595
2724
|
* Called once when the tracker is created and request version other libraries.
|
|
2596
2725
|
*/
|
|
@@ -2791,36 +2920,384 @@ class TonConnectTracker {
|
|
|
2791
2920
|
}
|
|
2792
2921
|
}
|
|
2793
2922
|
|
|
2794
|
-
const tonConnectSdkVersion = "3.3.0-beta.
|
|
2923
|
+
const tonConnectSdkVersion = "3.3.0-beta.2";
|
|
2795
2924
|
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
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 = 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 = 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)
|
|
3010
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
3011
|
+
.join(''),
|
|
3012
|
+
testOnly,
|
|
3013
|
+
isBounceable
|
|
3014
|
+
};
|
|
3015
|
+
}
|
|
3016
|
+
function parseHexAddress(hexAddress) {
|
|
3017
|
+
if (!hexAddress.includes(':')) {
|
|
3018
|
+
throw new WrongAddressError(`Wrong address ${hexAddress}. Address must include ":".`);
|
|
3019
|
+
}
|
|
3020
|
+
const parts = hexAddress.split(':');
|
|
3021
|
+
if (parts.length !== 2) {
|
|
3022
|
+
throw new WrongAddressError(`Wrong address ${hexAddress}. Address must include ":" only once.`);
|
|
3023
|
+
}
|
|
3024
|
+
const wc = parseInt(parts[0]);
|
|
3025
|
+
if (wc !== 0 && wc !== -1) {
|
|
3026
|
+
throw new WrongAddressError(`Wrong address ${hexAddress}. WC must be eq 0 or -1, but ${wc} received.`);
|
|
3027
|
+
}
|
|
3028
|
+
const hex = parts[1];
|
|
3029
|
+
if ((hex === null || hex === void 0 ? void 0 : hex.length) !== 64) {
|
|
3030
|
+
throw new WrongAddressError(`Wrong address ${hexAddress}. Hex part must be 64bytes length, but ${hex === null || hex === void 0 ? void 0 : hex.length} received.`);
|
|
3031
|
+
}
|
|
3032
|
+
return {
|
|
3033
|
+
wc,
|
|
3034
|
+
hex: hexToBytes(hex)
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
3037
|
+
function crc16(data) {
|
|
3038
|
+
const poly = 0x1021;
|
|
3039
|
+
let reg = 0;
|
|
3040
|
+
const message = new Uint8Array(data.length + 2);
|
|
3041
|
+
message.set(data);
|
|
3042
|
+
for (let byte of message) {
|
|
3043
|
+
let mask = 0x80;
|
|
3044
|
+
while (mask > 0) {
|
|
3045
|
+
reg <<= 1;
|
|
3046
|
+
if (byte & mask) {
|
|
3047
|
+
reg += 1;
|
|
3048
|
+
}
|
|
3049
|
+
mask >>= 1;
|
|
3050
|
+
if (reg > 0xffff) {
|
|
3051
|
+
reg &= 0xffff;
|
|
3052
|
+
reg ^= poly;
|
|
3053
|
+
}
|
|
2818
3054
|
}
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
3055
|
+
}
|
|
3056
|
+
return new Uint8Array([Math.floor(reg / 256), reg % 256]);
|
|
3057
|
+
}
|
|
3058
|
+
const toByteMap = {};
|
|
3059
|
+
for (let ord = 0; ord <= 0xff; ord++) {
|
|
3060
|
+
let s = ord.toString(16);
|
|
3061
|
+
if (s.length < 2) {
|
|
3062
|
+
s = '0' + s;
|
|
3063
|
+
}
|
|
3064
|
+
toByteMap[s] = ord;
|
|
3065
|
+
}
|
|
3066
|
+
function hexToBytes(hex) {
|
|
3067
|
+
hex = hex.toLowerCase();
|
|
3068
|
+
const length2 = hex.length;
|
|
3069
|
+
if (length2 % 2 !== 0) {
|
|
3070
|
+
throw new ParseHexError('Hex string must have length a multiple of 2: ' + hex);
|
|
3071
|
+
}
|
|
3072
|
+
const length = length2 / 2;
|
|
3073
|
+
const result = new Uint8Array(length);
|
|
3074
|
+
for (let i = 0; i < length; i++) {
|
|
3075
|
+
const doubled = i * 2;
|
|
3076
|
+
const hexSubstring = hex.substring(doubled, doubled + 2);
|
|
3077
|
+
if (!toByteMap.hasOwnProperty(hexSubstring)) {
|
|
3078
|
+
throw new ParseHexError('Invalid hex character: ' + hexSubstring);
|
|
3079
|
+
}
|
|
3080
|
+
result[i] = toByteMap[hexSubstring];
|
|
3081
|
+
}
|
|
3082
|
+
return result;
|
|
3083
|
+
}
|
|
3084
|
+
|
|
3085
|
+
const BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
3086
|
+
const BOC_PREFIX = 'te6cc';
|
|
3087
|
+
const INTEGER_REGEX = /^-?\d+$/;
|
|
3088
|
+
const POSITIVE_INTEGER_REGEX = /^\d+$/;
|
|
3089
|
+
function isValidNumber(value) {
|
|
3090
|
+
return typeof value === 'number' && !isNaN(value);
|
|
3091
|
+
}
|
|
3092
|
+
function isValidString(value) {
|
|
3093
|
+
return typeof value === 'string' && value.length > 0;
|
|
3094
|
+
}
|
|
3095
|
+
function isValidBoc(value) {
|
|
3096
|
+
return typeof value === 'string' && BASE64_REGEX.test(value) && value.startsWith(BOC_PREFIX);
|
|
3097
|
+
}
|
|
3098
|
+
function isValidObject(value) {
|
|
3099
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3100
|
+
}
|
|
3101
|
+
function isValidArray(value) {
|
|
3102
|
+
return Array.isArray(value);
|
|
3103
|
+
}
|
|
3104
|
+
function hasExtraProperties(obj, allowedKeys) {
|
|
3105
|
+
return Object.keys(obj).some(key => !allowedKeys.includes(key));
|
|
3106
|
+
}
|
|
3107
|
+
function validateSendTransactionRequest(data) {
|
|
3108
|
+
// eslint-disable-next-line no-console
|
|
3109
|
+
console.log('[Validation Debug] validateSendTransactionRequest called');
|
|
3110
|
+
// eslint-disable-next-line no-console
|
|
3111
|
+
console.log('[Validation Debug] isQaModeEnabled():', isQaModeEnabled());
|
|
3112
|
+
if (!isValidObject(data)) {
|
|
3113
|
+
const error = 'Request must be an object';
|
|
3114
|
+
logValidationError(error);
|
|
3115
|
+
const shouldReturnNull = isQaModeEnabled();
|
|
3116
|
+
// eslint-disable-next-line no-console
|
|
3117
|
+
console.log('[Validation Debug] Should return null:', shouldReturnNull);
|
|
3118
|
+
return shouldReturnNull ? null : error;
|
|
3119
|
+
}
|
|
3120
|
+
const allowedKeys = ['validUntil', 'network', 'from', 'messages'];
|
|
3121
|
+
if (hasExtraProperties(data, allowedKeys)) {
|
|
3122
|
+
const error = 'Request contains extra properties';
|
|
3123
|
+
logValidationError(error);
|
|
3124
|
+
return isQaModeEnabled() ? null : error;
|
|
3125
|
+
}
|
|
3126
|
+
if (!isValidNumber(data.validUntil)) {
|
|
3127
|
+
const error = "Incorrect 'validUntil'";
|
|
3128
|
+
logValidationError(error);
|
|
3129
|
+
return isQaModeEnabled() ? null : error;
|
|
3130
|
+
}
|
|
3131
|
+
const now = Math.floor(Date.now() / 1000);
|
|
3132
|
+
const fiveMinutesFromNow = now + 300;
|
|
3133
|
+
if (data.validUntil > fiveMinutesFromNow) {
|
|
3134
|
+
console.warn(`validUntil (${data.validUntil}) is more than 5 minutes from now (${now})`);
|
|
3135
|
+
}
|
|
3136
|
+
if (data.network !== undefined) {
|
|
3137
|
+
if (!isValidString(data.network) || !/^[\d-]+$/.test(data.network)) {
|
|
3138
|
+
const error = "Invalid 'network' format";
|
|
3139
|
+
logValidationError(error);
|
|
3140
|
+
return isQaModeEnabled() ? null : error;
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
if (data.from !== undefined) {
|
|
3144
|
+
if (!isValidString(data.from) || !isValidRawAddress(data.from)) {
|
|
3145
|
+
const error = "Invalid 'from' address format";
|
|
3146
|
+
logValidationError(error);
|
|
3147
|
+
return isQaModeEnabled() ? null : error;
|
|
2822
3148
|
}
|
|
2823
3149
|
}
|
|
3150
|
+
if (!isValidArray(data.messages) || data.messages.length === 0) {
|
|
3151
|
+
const error = "'messages' is required";
|
|
3152
|
+
logValidationError(error);
|
|
3153
|
+
return isQaModeEnabled() ? null : error;
|
|
3154
|
+
}
|
|
3155
|
+
for (let i = 0; i < data.messages.length; i++) {
|
|
3156
|
+
const message = data.messages[i];
|
|
3157
|
+
const messageError = validateTransactionMessage(message, i);
|
|
3158
|
+
if (messageError) {
|
|
3159
|
+
return messageError;
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
return null;
|
|
3163
|
+
}
|
|
3164
|
+
function validateTransactionMessage(message, index) {
|
|
3165
|
+
if (!isValidObject(message)) {
|
|
3166
|
+
return `Message at index ${index} must be an object`;
|
|
3167
|
+
}
|
|
3168
|
+
const allowedKeys = ['address', 'amount', 'stateInit', 'payload', 'extraCurrency'];
|
|
3169
|
+
if (hasExtraProperties(message, allowedKeys)) {
|
|
3170
|
+
return `Message at index ${index} contains extra properties`;
|
|
3171
|
+
}
|
|
3172
|
+
if (!isValidString(message.address)) {
|
|
3173
|
+
return `'address' is required in message at index ${index}`;
|
|
3174
|
+
}
|
|
3175
|
+
if (!isValidUserFriendlyAddress(message.address)) {
|
|
3176
|
+
return `Wrong 'address' format in message at index ${index}`;
|
|
3177
|
+
}
|
|
3178
|
+
if (!isValidString(message.amount)) {
|
|
3179
|
+
return `'amount' is required in message at index ${index}`;
|
|
3180
|
+
}
|
|
3181
|
+
if (!/^[0-9]+$/.test(message.amount)) {
|
|
3182
|
+
return `Incorrect 'amount' in message at index ${index}`;
|
|
3183
|
+
}
|
|
3184
|
+
if (message.stateInit !== undefined) {
|
|
3185
|
+
if (!isValidString(message.stateInit) || !isValidBoc(message.stateInit)) {
|
|
3186
|
+
return `Invalid 'stateInit' in message at index ${index}`;
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
if (message.payload !== undefined) {
|
|
3190
|
+
if (!isValidString(message.payload) || !isValidBoc(message.payload)) {
|
|
3191
|
+
return `Invalid 'payload' in message at index ${index}`;
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3194
|
+
if (message.extraCurrency !== undefined) {
|
|
3195
|
+
if (!isValidObject(message.extraCurrency)) {
|
|
3196
|
+
return `Invalid 'extraCurrency' in message at index ${index}`;
|
|
3197
|
+
}
|
|
3198
|
+
for (const [key, value] of Object.entries(message.extraCurrency)) {
|
|
3199
|
+
if (!INTEGER_REGEX.test(key) ||
|
|
3200
|
+
typeof value !== 'string' ||
|
|
3201
|
+
!POSITIVE_INTEGER_REGEX.test(value)) {
|
|
3202
|
+
return `Invalid 'extraCurrency' format in message at index ${index}`;
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
return null;
|
|
3207
|
+
}
|
|
3208
|
+
function validateConnectAdditionalRequest(data) {
|
|
3209
|
+
if (!isValidObject(data)) {
|
|
3210
|
+
return 'Request must be an object';
|
|
3211
|
+
}
|
|
3212
|
+
const allowedKeys = ['tonProof'];
|
|
3213
|
+
if (hasExtraProperties(data, allowedKeys)) {
|
|
3214
|
+
return 'Request contains extra properties';
|
|
3215
|
+
}
|
|
3216
|
+
if (data.tonProof !== undefined && !isValidString(data.tonProof)) {
|
|
3217
|
+
return "Invalid 'tonProof'";
|
|
3218
|
+
}
|
|
3219
|
+
return null;
|
|
3220
|
+
}
|
|
3221
|
+
function validateSignDataPayload(data) {
|
|
3222
|
+
if (!isValidObject(data)) {
|
|
3223
|
+
return 'Payload must be an object';
|
|
3224
|
+
}
|
|
3225
|
+
if (!isValidString(data.type)) {
|
|
3226
|
+
return "'type' is required";
|
|
3227
|
+
}
|
|
3228
|
+
switch (data.type) {
|
|
3229
|
+
case 'text':
|
|
3230
|
+
return validateSignDataPayloadText(data);
|
|
3231
|
+
case 'binary':
|
|
3232
|
+
return validateSignDataPayloadBinary(data);
|
|
3233
|
+
case 'cell':
|
|
3234
|
+
return validateSignDataPayloadCell(data);
|
|
3235
|
+
default:
|
|
3236
|
+
return "Invalid 'type' value";
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
function validateSignDataPayloadText(data) {
|
|
3240
|
+
const allowedKeys = ['type', 'text', 'network', 'from'];
|
|
3241
|
+
if (hasExtraProperties(data, allowedKeys)) {
|
|
3242
|
+
return 'Text payload contains extra properties';
|
|
3243
|
+
}
|
|
3244
|
+
if (!isValidString(data.text)) {
|
|
3245
|
+
return "'text' is required";
|
|
3246
|
+
}
|
|
3247
|
+
if (data.network !== undefined) {
|
|
3248
|
+
if (!isValidString(data.network) || !/^\d+$/.test(data.network)) {
|
|
3249
|
+
return "Invalid 'network' format";
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
if (data.from !== undefined && !isValidString(data.from)) {
|
|
3253
|
+
return "Invalid 'from'";
|
|
3254
|
+
}
|
|
3255
|
+
return null;
|
|
3256
|
+
}
|
|
3257
|
+
function validateSignDataPayloadBinary(data) {
|
|
3258
|
+
const allowedKeys = ['type', 'bytes', 'network', 'from'];
|
|
3259
|
+
if (hasExtraProperties(data, allowedKeys)) {
|
|
3260
|
+
return 'Binary payload contains extra properties';
|
|
3261
|
+
}
|
|
3262
|
+
if (!isValidString(data.bytes)) {
|
|
3263
|
+
return "'bytes' is required";
|
|
3264
|
+
}
|
|
3265
|
+
if (data.network !== undefined) {
|
|
3266
|
+
if (!isValidString(data.network) || !/^\d+$/.test(data.network)) {
|
|
3267
|
+
return "Invalid 'network' format";
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
if (data.from !== undefined && !isValidString(data.from)) {
|
|
3271
|
+
return "Invalid 'from'";
|
|
3272
|
+
}
|
|
3273
|
+
return null;
|
|
3274
|
+
}
|
|
3275
|
+
function validateSignDataPayloadCell(data) {
|
|
3276
|
+
const allowedKeys = ['type', 'schema', 'cell', 'network', 'from'];
|
|
3277
|
+
if (hasExtraProperties(data, allowedKeys)) {
|
|
3278
|
+
return 'Cell payload contains extra properties';
|
|
3279
|
+
}
|
|
3280
|
+
if (!isValidString(data.schema)) {
|
|
3281
|
+
return "'schema' is required";
|
|
3282
|
+
}
|
|
3283
|
+
if (!isValidString(data.cell)) {
|
|
3284
|
+
return "'cell' is required";
|
|
3285
|
+
}
|
|
3286
|
+
if (!isValidBoc(data.cell)) {
|
|
3287
|
+
return "Invalid 'cell' format (must be valid base64)";
|
|
3288
|
+
}
|
|
3289
|
+
if (data.network !== undefined) {
|
|
3290
|
+
if (!isValidString(data.network) || !/^\d+$/.test(data.network)) {
|
|
3291
|
+
return "Invalid 'network' format";
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
if (data.from !== undefined && !isValidString(data.from)) {
|
|
3295
|
+
return "Invalid 'from'";
|
|
3296
|
+
}
|
|
3297
|
+
return null;
|
|
3298
|
+
}
|
|
3299
|
+
|
|
3300
|
+
class TonConnect {
|
|
2824
3301
|
/**
|
|
2825
3302
|
* Returns available wallets list.
|
|
2826
3303
|
*/
|
|
@@ -2850,6 +3327,33 @@ class TonConnect {
|
|
|
2850
3327
|
this._wallet = value;
|
|
2851
3328
|
this.statusChangeSubscriptions.forEach(callback => callback(this._wallet));
|
|
2852
3329
|
}
|
|
3330
|
+
constructor(options) {
|
|
3331
|
+
this.walletsList = new WalletsListManager();
|
|
3332
|
+
this._wallet = null;
|
|
3333
|
+
this.provider = null;
|
|
3334
|
+
this.statusChangeSubscriptions = [];
|
|
3335
|
+
this.statusChangeErrorSubscriptions = [];
|
|
3336
|
+
this.dappSettings = {
|
|
3337
|
+
manifestUrl: (options === null || options === void 0 ? void 0 : options.manifestUrl) || getWebPageManifest(),
|
|
3338
|
+
storage: (options === null || options === void 0 ? void 0 : options.storage) || new DefaultStorage()
|
|
3339
|
+
};
|
|
3340
|
+
this.walletsRequiredFeatures = options === null || options === void 0 ? void 0 : options.walletsRequiredFeatures;
|
|
3341
|
+
this.walletsList = new WalletsListManager({
|
|
3342
|
+
walletsListSource: options === null || options === void 0 ? void 0 : options.walletsListSource,
|
|
3343
|
+
cacheTTLMs: options === null || options === void 0 ? void 0 : options.walletsListCacheTTLMs
|
|
3344
|
+
});
|
|
3345
|
+
this.tracker = new TonConnectTracker({
|
|
3346
|
+
eventDispatcher: options === null || options === void 0 ? void 0 : options.eventDispatcher,
|
|
3347
|
+
tonConnectSdkVersion: tonConnectSdkVersion
|
|
3348
|
+
});
|
|
3349
|
+
if (!this.dappSettings.manifestUrl) {
|
|
3350
|
+
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');
|
|
3351
|
+
}
|
|
3352
|
+
this.bridgeConnectionStorage = new BridgeConnectionStorage(this.dappSettings.storage);
|
|
3353
|
+
if (!(options === null || options === void 0 ? void 0 : options.disableAutoPauseConnection)) {
|
|
3354
|
+
this.addWindowFocusAndBlurSubscriptions();
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
2853
3357
|
/**
|
|
2854
3358
|
* Returns available wallets list.
|
|
2855
3359
|
*/
|
|
@@ -2889,6 +3393,17 @@ class TonConnect {
|
|
|
2889
3393
|
options.openingDeadlineMS = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.openingDeadlineMS;
|
|
2890
3394
|
options.signal = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.signal;
|
|
2891
3395
|
}
|
|
3396
|
+
if (options.request) {
|
|
3397
|
+
const validationError = validateConnectAdditionalRequest(options.request);
|
|
3398
|
+
if (validationError) {
|
|
3399
|
+
if (isQaModeEnabled()) {
|
|
3400
|
+
console.error('ConnectAdditionalRequest validation failed: ' + validationError);
|
|
3401
|
+
}
|
|
3402
|
+
else {
|
|
3403
|
+
throw new TonConnectError('ConnectAdditionalRequest validation failed: ' + validationError);
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
2892
3407
|
if (this.connected) {
|
|
2893
3408
|
throw new WalletAlreadyConnectedError();
|
|
2894
3409
|
}
|
|
@@ -2915,8 +3430,8 @@ class TonConnect {
|
|
|
2915
3430
|
* Try to restore existing session and reconnect to the corresponding wallet. Call it immediately when your app is loaded.
|
|
2916
3431
|
*/
|
|
2917
3432
|
restoreConnection(options) {
|
|
2918
|
-
var _a, _b;
|
|
2919
3433
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3434
|
+
var _a, _b;
|
|
2920
3435
|
this.tracker.trackConnectionRestoringStarted();
|
|
2921
3436
|
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
2922
3437
|
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
@@ -3011,6 +3526,16 @@ class TonConnect {
|
|
|
3011
3526
|
options.onRequestSent = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.onRequestSent;
|
|
3012
3527
|
options.signal = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.signal;
|
|
3013
3528
|
}
|
|
3529
|
+
// Validate transaction
|
|
3530
|
+
const validationError = validateSendTransactionRequest(transaction);
|
|
3531
|
+
if (validationError) {
|
|
3532
|
+
if (isQaModeEnabled()) {
|
|
3533
|
+
console.error('SendTransactionRequest validation failed: ' + validationError);
|
|
3534
|
+
}
|
|
3535
|
+
else {
|
|
3536
|
+
throw new TonConnectError('SendTransactionRequest validation failed: ' + validationError);
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3014
3539
|
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
3015
3540
|
if (abortController.signal.aborted) {
|
|
3016
3541
|
throw new TonConnectError('Transaction sending was aborted');
|
|
@@ -3046,6 +3571,16 @@ class TonConnect {
|
|
|
3046
3571
|
if (abortController.signal.aborted) {
|
|
3047
3572
|
throw new TonConnectError('data sending was aborted');
|
|
3048
3573
|
}
|
|
3574
|
+
// Validate sign data
|
|
3575
|
+
const validationError = validateSignDataPayload(data);
|
|
3576
|
+
if (validationError) {
|
|
3577
|
+
if (isQaModeEnabled()) {
|
|
3578
|
+
console.error('SignDataPayload validation failed: ' + validationError);
|
|
3579
|
+
}
|
|
3580
|
+
else {
|
|
3581
|
+
throw new TonConnectError('SignDataPayload validation failed: ' + validationError);
|
|
3582
|
+
}
|
|
3583
|
+
}
|
|
3049
3584
|
this.checkConnection();
|
|
3050
3585
|
checkSignDataSupport(this.wallet.device.features, { requiredTypes: [data.type] });
|
|
3051
3586
|
this.tracker.trackDataSentForSignature(this.wallet, data);
|
|
@@ -3066,8 +3601,8 @@ class TonConnect {
|
|
|
3066
3601
|
* Disconnect form thw connected wallet and drop current session.
|
|
3067
3602
|
*/
|
|
3068
3603
|
disconnect(options) {
|
|
3069
|
-
var _a;
|
|
3070
3604
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3605
|
+
var _a;
|
|
3071
3606
|
if (!this.connected) {
|
|
3072
3607
|
throw new WalletNotConnectedError();
|
|
3073
3608
|
}
|
|
@@ -3175,26 +3710,28 @@ class TonConnect {
|
|
|
3175
3710
|
if (tonProofItem) {
|
|
3176
3711
|
let tonProof = undefined;
|
|
3177
3712
|
try {
|
|
3178
|
-
if ('proof' in tonProofItem) {
|
|
3713
|
+
if ('proof' in tonProofItem) {
|
|
3714
|
+
// success
|
|
3179
3715
|
tonProof = {
|
|
3180
3716
|
name: 'ton_proof',
|
|
3181
3717
|
proof: {
|
|
3182
3718
|
timestamp: tonProofItem.proof.timestamp,
|
|
3183
3719
|
domain: {
|
|
3184
3720
|
lengthBytes: tonProofItem.proof.domain.lengthBytes,
|
|
3185
|
-
value: tonProofItem.proof.domain.value
|
|
3721
|
+
value: tonProofItem.proof.domain.value
|
|
3186
3722
|
},
|
|
3187
3723
|
payload: tonProofItem.proof.payload,
|
|
3188
|
-
signature: tonProofItem.proof.signature
|
|
3724
|
+
signature: tonProofItem.proof.signature
|
|
3189
3725
|
}
|
|
3190
3726
|
};
|
|
3191
3727
|
}
|
|
3192
|
-
else if ('error' in tonProofItem) {
|
|
3728
|
+
else if ('error' in tonProofItem) {
|
|
3729
|
+
// error
|
|
3193
3730
|
tonProof = {
|
|
3194
3731
|
name: 'ton_proof',
|
|
3195
3732
|
error: {
|
|
3196
3733
|
code: tonProofItem.error.code,
|
|
3197
|
-
message: tonProofItem.error.message
|
|
3734
|
+
message: tonProofItem.error.message
|
|
3198
3735
|
}
|
|
3199
3736
|
};
|
|
3200
3737
|
}
|
|
@@ -3263,97 +3800,5 @@ TonConnect.isWalletInjected = (walletJSKey) => InjectedProvider.isWalletInjected
|
|
|
3263
3800
|
*/
|
|
3264
3801
|
TonConnect.isInsideWalletBrowser = (walletJSKey) => InjectedProvider.isInsideWalletBrowser(walletJSKey);
|
|
3265
3802
|
|
|
3266
|
-
|
|
3267
|
-
const testOnlyTag = 0x80;
|
|
3268
|
-
/**
|
|
3269
|
-
* Converts raw TON address to no-bounceable user-friendly format. [See details]{@link https://ton.org/docs/learn/overviews/addresses#user-friendly-address}
|
|
3270
|
-
* @param hexAddress raw TON address formatted as "0:<hex string without 0x>".
|
|
3271
|
-
* @param [testOnly=false] convert address to test-only form. [See details]{@link https://ton.org/docs/learn/overviews/addresses#user-friendly-address}
|
|
3272
|
-
*/
|
|
3273
|
-
function toUserFriendlyAddress(hexAddress, testOnly = false) {
|
|
3274
|
-
const { wc, hex } = parseHexAddress(hexAddress);
|
|
3275
|
-
let tag = noBounceableTag;
|
|
3276
|
-
if (testOnly) {
|
|
3277
|
-
tag |= testOnlyTag;
|
|
3278
|
-
}
|
|
3279
|
-
const addr = new Int8Array(34);
|
|
3280
|
-
addr[0] = tag;
|
|
3281
|
-
addr[1] = wc;
|
|
3282
|
-
addr.set(hex, 2);
|
|
3283
|
-
const addressWithChecksum = new Uint8Array(36);
|
|
3284
|
-
addressWithChecksum.set(addr);
|
|
3285
|
-
addressWithChecksum.set(crc16(addr), 34);
|
|
3286
|
-
let addressBase64 = Base64.encode(addressWithChecksum);
|
|
3287
|
-
return addressBase64.replace(/\+/g, '-').replace(/\//g, '_');
|
|
3288
|
-
}
|
|
3289
|
-
function parseHexAddress(hexAddress) {
|
|
3290
|
-
if (!hexAddress.includes(':')) {
|
|
3291
|
-
throw new WrongAddressError(`Wrong address ${hexAddress}. Address must include ":".`);
|
|
3292
|
-
}
|
|
3293
|
-
const parts = hexAddress.split(':');
|
|
3294
|
-
if (parts.length !== 2) {
|
|
3295
|
-
throw new WrongAddressError(`Wrong address ${hexAddress}. Address must include ":" only once.`);
|
|
3296
|
-
}
|
|
3297
|
-
const wc = parseInt(parts[0]);
|
|
3298
|
-
if (wc !== 0 && wc !== -1) {
|
|
3299
|
-
throw new WrongAddressError(`Wrong address ${hexAddress}. WC must be eq 0 or -1, but ${wc} received.`);
|
|
3300
|
-
}
|
|
3301
|
-
const hex = parts[1];
|
|
3302
|
-
if ((hex === null || hex === void 0 ? void 0 : hex.length) !== 64) {
|
|
3303
|
-
throw new WrongAddressError(`Wrong address ${hexAddress}. Hex part must be 64bytes length, but ${hex === null || hex === void 0 ? void 0 : hex.length} received.`);
|
|
3304
|
-
}
|
|
3305
|
-
return {
|
|
3306
|
-
wc,
|
|
3307
|
-
hex: hexToBytes(hex)
|
|
3308
|
-
};
|
|
3309
|
-
}
|
|
3310
|
-
function crc16(data) {
|
|
3311
|
-
const poly = 0x1021;
|
|
3312
|
-
let reg = 0;
|
|
3313
|
-
const message = new Uint8Array(data.length + 2);
|
|
3314
|
-
message.set(data);
|
|
3315
|
-
for (let byte of message) {
|
|
3316
|
-
let mask = 0x80;
|
|
3317
|
-
while (mask > 0) {
|
|
3318
|
-
reg <<= 1;
|
|
3319
|
-
if (byte & mask) {
|
|
3320
|
-
reg += 1;
|
|
3321
|
-
}
|
|
3322
|
-
mask >>= 1;
|
|
3323
|
-
if (reg > 0xffff) {
|
|
3324
|
-
reg &= 0xffff;
|
|
3325
|
-
reg ^= poly;
|
|
3326
|
-
}
|
|
3327
|
-
}
|
|
3328
|
-
}
|
|
3329
|
-
return new Uint8Array([Math.floor(reg / 256), reg % 256]);
|
|
3330
|
-
}
|
|
3331
|
-
const toByteMap = {};
|
|
3332
|
-
for (let ord = 0; ord <= 0xff; ord++) {
|
|
3333
|
-
let s = ord.toString(16);
|
|
3334
|
-
if (s.length < 2) {
|
|
3335
|
-
s = '0' + s;
|
|
3336
|
-
}
|
|
3337
|
-
toByteMap[s] = ord;
|
|
3338
|
-
}
|
|
3339
|
-
function hexToBytes(hex) {
|
|
3340
|
-
hex = hex.toLowerCase();
|
|
3341
|
-
const length2 = hex.length;
|
|
3342
|
-
if (length2 % 2 !== 0) {
|
|
3343
|
-
throw new ParseHexError('Hex string must have length a multiple of 2: ' + hex);
|
|
3344
|
-
}
|
|
3345
|
-
const length = length2 / 2;
|
|
3346
|
-
const result = new Uint8Array(length);
|
|
3347
|
-
for (let i = 0; i < length; i++) {
|
|
3348
|
-
const doubled = i * 2;
|
|
3349
|
-
const hexSubstring = hex.substring(doubled, doubled + 2);
|
|
3350
|
-
if (!toByteMap.hasOwnProperty(hexSubstring)) {
|
|
3351
|
-
throw new ParseHexError('Invalid hex character: ' + hexSubstring);
|
|
3352
|
-
}
|
|
3353
|
-
result[i] = toByteMap[hexSubstring];
|
|
3354
|
-
}
|
|
3355
|
-
return result;
|
|
3356
|
-
}
|
|
3357
|
-
|
|
3358
|
-
export { BadRequestError, BrowserEventDispatcher, FetchWalletsError, LocalstorageNotFoundError, ParseHexError, TonConnect, TonConnectError, UnknownAppError, UnknownError, UserRejectsError, WalletAlreadyConnectedError, WalletMissingRequiredFeaturesError, WalletNotConnectedError, WalletNotInjectedError, WalletNotSupportFeatureError, WalletsListManager, WrongAddressError, checkRequiredWalletFeatures, createConnectionCompletedEvent, createConnectionErrorEvent, createConnectionRestoringCompletedEvent, createConnectionRestoringErrorEvent, createConnectionRestoringStartedEvent, createConnectionStartedEvent, createDataSentForSignatureEvent, createDataSignedEvent, createDataSigningFailedEvent, createDisconnectionEvent, createRequestVersionEvent, createResponseVersionEvent, createTransactionSentForSignatureEvent, createTransactionSignedEvent, createTransactionSigningFailedEvent, createVersionInfo, TonConnect as default, encodeTelegramUrlParameters, isTelegramUrl, isWalletInfoCurrentlyEmbedded, isWalletInfoCurrentlyInjected, isWalletInfoInjectable, isWalletInfoInjected, isWalletInfoRemote, toUserFriendlyAddress };
|
|
3803
|
+
export { BadRequestError, BrowserEventDispatcher, FetchWalletsError, LocalstorageNotFoundError, ParseHexError, TonConnect, TonConnectError, UnknownAppError, UnknownError, UserRejectsError, WalletAlreadyConnectedError, WalletMissingRequiredFeaturesError, WalletNotConnectedError, WalletNotInjectedError, WalletNotSupportFeatureError, WalletsListManager, WrongAddressError, checkRequiredWalletFeatures, createConnectionCompletedEvent, createConnectionErrorEvent, createConnectionRestoringCompletedEvent, createConnectionRestoringErrorEvent, createConnectionRestoringStartedEvent, createConnectionStartedEvent, createDataSentForSignatureEvent, createDataSignedEvent, createDataSigningFailedEvent, createDisconnectionEvent, createRequestVersionEvent, createResponseVersionEvent, createTransactionSentForSignatureEvent, createTransactionSignedEvent, createTransactionSigningFailedEvent, createVersionInfo, TonConnect as default, enableQaMode, encodeTelegramUrlParameters, isQaModeEnabled, isTelegramUrl, isWalletInfoCurrentlyEmbedded, isWalletInfoCurrentlyInjected, isWalletInfoInjectable, isWalletInfoInjected, isWalletInfoRemote, toUserFriendlyAddress };
|
|
3359
3804
|
//# sourceMappingURL=index.mjs.map
|