@blazium/ton-connect-mobile 1.1.1 → 1.1.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/core/protocol.d.ts +2 -2
- package/dist/core/protocol.js +16 -11
- package/dist/core/wallets.d.ts +4 -0
- package/dist/core/wallets.js +8 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +188 -4
- package/dist/react/TonConnectButton.d.ts +22 -0
- package/dist/react/TonConnectButton.js +101 -0
- package/dist/react/TonConnectUIProvider.d.ts +110 -0
- package/dist/react/TonConnectUIProvider.js +209 -0
- package/dist/react/index.d.ts +8 -0
- package/dist/react/index.js +15 -0
- package/dist/types/index.d.ts +4 -2
- package/package.json +12 -1
- package/src/core/protocol.ts +22 -11
- package/src/core/wallets.ts +12 -0
- package/src/index.ts +226 -5
- package/src/react/TonConnectButton.tsx +103 -0
- package/src/react/TonConnectUIProvider.tsx +290 -0
- package/src/react/index.ts +24 -0
- package/src/types/index.ts +4 -4
package/dist/core/protocol.d.ts
CHANGED
|
@@ -17,14 +17,14 @@ export declare function decodeBase64URL<T>(encoded: string): T;
|
|
|
17
17
|
* Or universal link: https://app.tonkeeper.com/ton-connect?<base64_encoded_payload>
|
|
18
18
|
* Or custom wallet universal link
|
|
19
19
|
*/
|
|
20
|
-
export declare function buildConnectionRequest(manifestUrl: string, returnScheme: string, walletUniversalLink?: string): string;
|
|
20
|
+
export declare function buildConnectionRequest(manifestUrl: string, returnScheme: string, walletUniversalLink?: string, returnStrategy?: 'back' | 'post_redirect' | 'none', requiresReturnScheme?: boolean): string;
|
|
21
21
|
/**
|
|
22
22
|
* Build transaction request URL
|
|
23
23
|
* Format: tonconnect://send-transaction?<base64_encoded_payload>
|
|
24
24
|
* Or universal link: https://app.tonkeeper.com/ton-connect/send-transaction?<base64_encoded_payload>
|
|
25
25
|
* Or custom wallet universal link
|
|
26
26
|
*/
|
|
27
|
-
export declare function buildTransactionRequest(manifestUrl: string, request: SendTransactionRequest, returnScheme: string, walletUniversalLink?: string): string;
|
|
27
|
+
export declare function buildTransactionRequest(manifestUrl: string, request: SendTransactionRequest, returnScheme: string, walletUniversalLink?: string, returnStrategy?: 'back' | 'post_redirect' | 'none', requiresReturnScheme?: boolean): string;
|
|
28
28
|
/**
|
|
29
29
|
* Parse callback URL
|
|
30
30
|
* Format: <scheme>://tonconnect?<base64_encoded_response>
|
package/dist/core/protocol.js
CHANGED
|
@@ -105,17 +105,20 @@ function decodeBase64URL(encoded) {
|
|
|
105
105
|
* Or universal link: https://app.tonkeeper.com/ton-connect?<base64_encoded_payload>
|
|
106
106
|
* Or custom wallet universal link
|
|
107
107
|
*/
|
|
108
|
-
function buildConnectionRequest(manifestUrl, returnScheme, walletUniversalLink) {
|
|
109
|
-
//
|
|
110
|
-
// returnScheme is NOT part of the official protocol payload
|
|
111
|
-
// For mobile apps, wallets should infer the callback scheme from the manifest or use a default
|
|
108
|
+
function buildConnectionRequest(manifestUrl, returnScheme, walletUniversalLink, returnStrategy, requiresReturnScheme) {
|
|
109
|
+
// Build payload with required fields
|
|
112
110
|
const payload = {
|
|
113
111
|
manifestUrl,
|
|
114
112
|
items: [{ name: 'ton_addr' }],
|
|
115
|
-
returnStrategy: 'back',
|
|
116
|
-
// NOTE: returnScheme is NOT in the official TON Connect protocol
|
|
117
|
-
// Wallets should handle mobile app callbacks differently
|
|
113
|
+
returnStrategy: returnStrategy || 'back',
|
|
118
114
|
};
|
|
115
|
+
// CRITICAL FIX: Many wallets (Tonhub, MyTonWallet, Telegram Wallet) require returnScheme
|
|
116
|
+
// in the payload to properly handle mobile app callbacks. While not in the official
|
|
117
|
+
// protocol spec, it's a de-facto requirement for mobile apps.
|
|
118
|
+
if (requiresReturnScheme !== false) {
|
|
119
|
+
// Default to true if not specified - safer to include it
|
|
120
|
+
payload.returnScheme = returnScheme;
|
|
121
|
+
}
|
|
119
122
|
const encoded = encodeBase64URL(payload);
|
|
120
123
|
// Use custom wallet universal link if provided
|
|
121
124
|
if (walletUniversalLink) {
|
|
@@ -130,7 +133,7 @@ function buildConnectionRequest(manifestUrl, returnScheme, walletUniversalLink)
|
|
|
130
133
|
* Or universal link: https://app.tonkeeper.com/ton-connect/send-transaction?<base64_encoded_payload>
|
|
131
134
|
* Or custom wallet universal link
|
|
132
135
|
*/
|
|
133
|
-
function buildTransactionRequest(manifestUrl, request, returnScheme, walletUniversalLink) {
|
|
136
|
+
function buildTransactionRequest(manifestUrl, request, returnScheme, walletUniversalLink, returnStrategy, requiresReturnScheme) {
|
|
134
137
|
const payload = {
|
|
135
138
|
manifestUrl,
|
|
136
139
|
request: {
|
|
@@ -144,10 +147,12 @@ function buildTransactionRequest(manifestUrl, request, returnScheme, walletUnive
|
|
|
144
147
|
network: request.network,
|
|
145
148
|
from: request.from,
|
|
146
149
|
},
|
|
147
|
-
returnStrategy: 'back',
|
|
148
|
-
// NOTE: returnScheme is NOT in the official TON Connect protocol
|
|
149
|
-
// Wallets should handle mobile app callbacks differently
|
|
150
|
+
returnStrategy: returnStrategy || 'back',
|
|
150
151
|
};
|
|
152
|
+
// CRITICAL FIX: Include returnScheme for mobile wallets that require it
|
|
153
|
+
if (requiresReturnScheme !== false) {
|
|
154
|
+
payload.returnScheme = returnScheme;
|
|
155
|
+
}
|
|
151
156
|
const encoded = encodeBase64URL(payload);
|
|
152
157
|
// Use custom wallet universal link if provided
|
|
153
158
|
if (walletUniversalLink) {
|
package/dist/core/wallets.d.ts
CHANGED
|
@@ -15,6 +15,10 @@ export interface WalletDefinition {
|
|
|
15
15
|
iconUrl?: string;
|
|
16
16
|
/** Platform support */
|
|
17
17
|
platforms: ('ios' | 'android' | 'web')[];
|
|
18
|
+
/** Preferred return strategy for this wallet */
|
|
19
|
+
preferredReturnStrategy?: 'back' | 'post_redirect' | 'none';
|
|
20
|
+
/** Whether this wallet requires returnScheme in payload */
|
|
21
|
+
requiresReturnScheme?: boolean;
|
|
18
22
|
}
|
|
19
23
|
/**
|
|
20
24
|
* List of supported TON Connect wallets
|
package/dist/core/wallets.js
CHANGED
|
@@ -18,6 +18,8 @@ exports.SUPPORTED_WALLETS = [
|
|
|
18
18
|
universalLink: 'https://app.tonkeeper.com/ton-connect',
|
|
19
19
|
deepLink: 'tonkeeper://',
|
|
20
20
|
platforms: ['ios', 'android'],
|
|
21
|
+
preferredReturnStrategy: 'back',
|
|
22
|
+
requiresReturnScheme: false, // Tonkeeper can infer from manifest
|
|
21
23
|
},
|
|
22
24
|
{
|
|
23
25
|
name: 'MyTonWallet',
|
|
@@ -25,6 +27,8 @@ exports.SUPPORTED_WALLETS = [
|
|
|
25
27
|
universalLink: 'https://connect.mytonwallet.org',
|
|
26
28
|
deepLink: 'mytonwallet://',
|
|
27
29
|
platforms: ['ios', 'android', 'web'],
|
|
30
|
+
preferredReturnStrategy: 'post_redirect',
|
|
31
|
+
requiresReturnScheme: true, // MyTonWallet requires explicit returnScheme
|
|
28
32
|
},
|
|
29
33
|
{
|
|
30
34
|
name: 'Wallet in Telegram',
|
|
@@ -32,6 +36,8 @@ exports.SUPPORTED_WALLETS = [
|
|
|
32
36
|
universalLink: 'https://wallet.tonapi.io/ton-connect',
|
|
33
37
|
deepLink: 'tg://',
|
|
34
38
|
platforms: ['ios', 'android'],
|
|
39
|
+
preferredReturnStrategy: 'post_redirect',
|
|
40
|
+
requiresReturnScheme: true, // Telegram Wallet requires explicit returnScheme
|
|
35
41
|
},
|
|
36
42
|
{
|
|
37
43
|
name: 'Tonhub',
|
|
@@ -39,6 +45,8 @@ exports.SUPPORTED_WALLETS = [
|
|
|
39
45
|
universalLink: 'https://tonhub.com/ton-connect',
|
|
40
46
|
deepLink: 'tonhub://',
|
|
41
47
|
platforms: ['ios', 'android'],
|
|
48
|
+
preferredReturnStrategy: 'post_redirect',
|
|
49
|
+
requiresReturnScheme: true, // Tonhub requires explicit returnScheme for proper callback
|
|
42
50
|
},
|
|
43
51
|
];
|
|
44
52
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export declare class TonConnectMobile {
|
|
|
38
38
|
private currentWallet;
|
|
39
39
|
private connectionPromise;
|
|
40
40
|
private transactionPromise;
|
|
41
|
+
private signDataPromise;
|
|
41
42
|
constructor(config: TonConnectMobileConfig);
|
|
42
43
|
/**
|
|
43
44
|
* Create platform adapter based on available modules
|
|
@@ -74,6 +75,14 @@ export declare class TonConnectMobile {
|
|
|
74
75
|
boc: string;
|
|
75
76
|
signature: string;
|
|
76
77
|
}>;
|
|
78
|
+
/**
|
|
79
|
+
* Sign data (for authentication, etc.)
|
|
80
|
+
* Note: Not all wallets support signData. This is a TON Connect extension.
|
|
81
|
+
*/
|
|
82
|
+
signData(data: string | Uint8Array, version?: string): Promise<{
|
|
83
|
+
signature: string;
|
|
84
|
+
timestamp: number;
|
|
85
|
+
}>;
|
|
77
86
|
/**
|
|
78
87
|
* Disconnect from wallet
|
|
79
88
|
*/
|
package/dist/index.js
CHANGED
|
@@ -81,6 +81,7 @@ class TonConnectMobile {
|
|
|
81
81
|
this.urlUnsubscribe = null;
|
|
82
82
|
this.connectionPromise = null;
|
|
83
83
|
this.transactionPromise = null;
|
|
84
|
+
this.signDataPromise = null;
|
|
84
85
|
// Validate config
|
|
85
86
|
if (!config.manifestUrl) {
|
|
86
87
|
throw new TonConnectError('manifestUrl is required');
|
|
@@ -188,6 +189,40 @@ class TonConnectMobile {
|
|
|
188
189
|
}
|
|
189
190
|
const parsed = (0, protocol_1.parseCallbackURL)(url, this.config.scheme);
|
|
190
191
|
console.log('[TON Connect] Parsed callback:', parsed.type, parsed.data ? 'has data' : 'no data');
|
|
192
|
+
// CRITICAL FIX: Check for sign data response first (before other handlers)
|
|
193
|
+
if (this.signDataPromise && !this.signDataPromise.timeout) {
|
|
194
|
+
// Sign data request is pending
|
|
195
|
+
if (parsed.type === 'error' && parsed.data) {
|
|
196
|
+
const errorData = parsed.data;
|
|
197
|
+
if (errorData?.error) {
|
|
198
|
+
const promise = this.signDataPromise;
|
|
199
|
+
this.signDataPromise = null;
|
|
200
|
+
if (errorData.error.code === 300) {
|
|
201
|
+
promise.reject(new UserRejectedError());
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
promise.reject(new TonConnectError(errorData.error.message || 'Sign data failed'));
|
|
205
|
+
}
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// Check for sign data response format
|
|
210
|
+
// Note: TON Connect protocol may return sign data in different format
|
|
211
|
+
// We check for signature field in the response
|
|
212
|
+
if (parsed.data && typeof parsed.data === 'object') {
|
|
213
|
+
const data = parsed.data;
|
|
214
|
+
if (data.signature && typeof data.signature === 'string') {
|
|
215
|
+
const promise = this.signDataPromise;
|
|
216
|
+
this.signDataPromise = null;
|
|
217
|
+
promise.resolve({
|
|
218
|
+
signature: data.signature,
|
|
219
|
+
timestamp: data.timestamp || Date.now(),
|
|
220
|
+
});
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Handle connection responses
|
|
191
226
|
if (parsed.type === 'connect' && parsed.data) {
|
|
192
227
|
this.handleConnectionResponse(parsed.data);
|
|
193
228
|
}
|
|
@@ -306,10 +341,24 @@ class TonConnectMobile {
|
|
|
306
341
|
// Build connection request URL (use wallet's universal link)
|
|
307
342
|
console.log('[TON Connect] Building connection request URL for wallet:', this.currentWallet.name);
|
|
308
343
|
console.log('[TON Connect] Using universal link:', this.currentWallet.universalLink);
|
|
309
|
-
|
|
344
|
+
console.log('[TON Connect] Wallet return strategy:', this.currentWallet.preferredReturnStrategy || 'back');
|
|
345
|
+
console.log('[TON Connect] Wallet requires returnScheme:', this.currentWallet.requiresReturnScheme !== false);
|
|
346
|
+
const url = (0, protocol_1.buildConnectionRequest)(this.config.manifestUrl, this.config.scheme, this.currentWallet.universalLink, this.currentWallet.preferredReturnStrategy, this.currentWallet.requiresReturnScheme);
|
|
347
|
+
// DEBUG: Decode and log the payload for debugging
|
|
348
|
+
try {
|
|
349
|
+
const urlParts = url.split('?');
|
|
350
|
+
if (urlParts.length > 1) {
|
|
351
|
+
const payload = urlParts[1];
|
|
352
|
+
const decoded = (0, protocol_1.decodeBase64URL)(payload);
|
|
353
|
+
console.log('[TON Connect] Connection request payload:', JSON.stringify(decoded, null, 2));
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
catch (e) {
|
|
357
|
+
// Ignore decode errors in logging
|
|
358
|
+
console.log('[TON Connect] Could not decode payload for logging:', e);
|
|
359
|
+
}
|
|
310
360
|
console.log('[TON Connect] Built URL:', url.substring(0, 100) + '...');
|
|
311
|
-
|
|
312
|
-
console.log('[TON Connect] Opening URL:', url);
|
|
361
|
+
console.log('[TON Connect] Full URL:', url);
|
|
313
362
|
console.log('[TON Connect] Manifest URL:', this.config.manifestUrl);
|
|
314
363
|
console.log('[TON Connect] Return scheme:', this.config.scheme);
|
|
315
364
|
console.log('[TON Connect] Adapter type:', this.adapter.constructor.name);
|
|
@@ -381,7 +430,7 @@ class TonConnectMobile {
|
|
|
381
430
|
throw new TransactionInProgressError();
|
|
382
431
|
}
|
|
383
432
|
// Build transaction request URL (use universal link for Android compatibility)
|
|
384
|
-
const url = (0, protocol_1.buildTransactionRequest)(this.config.manifestUrl, request, this.config.scheme, this.currentWallet.universalLink);
|
|
433
|
+
const url = (0, protocol_1.buildTransactionRequest)(this.config.manifestUrl, request, this.config.scheme, this.currentWallet.universalLink, this.currentWallet.preferredReturnStrategy, this.currentWallet.requiresReturnScheme);
|
|
385
434
|
// Create promise for transaction
|
|
386
435
|
return new Promise((resolve, reject) => {
|
|
387
436
|
let timeout = null;
|
|
@@ -424,6 +473,140 @@ class TonConnectMobile {
|
|
|
424
473
|
});
|
|
425
474
|
});
|
|
426
475
|
}
|
|
476
|
+
/**
|
|
477
|
+
* Sign data (for authentication, etc.)
|
|
478
|
+
* Note: Not all wallets support signData. This is a TON Connect extension.
|
|
479
|
+
*/
|
|
480
|
+
async signData(data, version = '1.0') {
|
|
481
|
+
// Check if connected
|
|
482
|
+
if (!this.currentStatus.connected || !this.currentStatus.wallet) {
|
|
483
|
+
throw new TonConnectError('Not connected to wallet. Call connect() first.');
|
|
484
|
+
}
|
|
485
|
+
// Helper function to encode bytes to base64
|
|
486
|
+
const base64EncodeBytes = (bytes) => {
|
|
487
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
488
|
+
let result = '';
|
|
489
|
+
let i = 0;
|
|
490
|
+
while (i < bytes.length) {
|
|
491
|
+
const a = bytes[i++];
|
|
492
|
+
const b = i < bytes.length ? bytes[i++] : 0;
|
|
493
|
+
const c = i < bytes.length ? bytes[i++] : 0;
|
|
494
|
+
const bitmap = (a << 16) | (b << 8) | c;
|
|
495
|
+
result += chars.charAt((bitmap >> 18) & 63);
|
|
496
|
+
result += chars.charAt((bitmap >> 12) & 63);
|
|
497
|
+
result += i - 2 < bytes.length ? chars.charAt((bitmap >> 6) & 63) : '=';
|
|
498
|
+
result += i - 1 < bytes.length ? chars.charAt(bitmap & 63) : '=';
|
|
499
|
+
}
|
|
500
|
+
return result;
|
|
501
|
+
};
|
|
502
|
+
// Helper function to get TextEncoder
|
|
503
|
+
const getTextEncoder = () => {
|
|
504
|
+
// eslint-disable-next-line no-undef
|
|
505
|
+
if (typeof globalThis !== 'undefined' && globalThis.TextEncoder) {
|
|
506
|
+
// eslint-disable-next-line no-undef
|
|
507
|
+
return new globalThis.TextEncoder();
|
|
508
|
+
}
|
|
509
|
+
// Fallback: manual encoding
|
|
510
|
+
return {
|
|
511
|
+
encode(input) {
|
|
512
|
+
const bytes = new Uint8Array(input.length);
|
|
513
|
+
for (let i = 0; i < input.length; i++) {
|
|
514
|
+
bytes[i] = input.charCodeAt(i);
|
|
515
|
+
}
|
|
516
|
+
return bytes;
|
|
517
|
+
},
|
|
518
|
+
};
|
|
519
|
+
};
|
|
520
|
+
// Convert data to base64
|
|
521
|
+
let dataBase64;
|
|
522
|
+
if (typeof data === 'string') {
|
|
523
|
+
// Check if it's already base64
|
|
524
|
+
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
525
|
+
if (base64Regex.test(data) && data.length % 4 === 0) {
|
|
526
|
+
// Likely base64, use as-is
|
|
527
|
+
dataBase64 = data;
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
// Not base64, encode it
|
|
531
|
+
const encoder = getTextEncoder();
|
|
532
|
+
const bytes = encoder.encode(data);
|
|
533
|
+
dataBase64 = base64EncodeBytes(bytes);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
// Uint8Array - convert to base64
|
|
538
|
+
dataBase64 = base64EncodeBytes(data);
|
|
539
|
+
}
|
|
540
|
+
// Build sign data request
|
|
541
|
+
const payload = {
|
|
542
|
+
manifestUrl: this.config.manifestUrl,
|
|
543
|
+
data: dataBase64,
|
|
544
|
+
version,
|
|
545
|
+
returnStrategy: this.currentWallet.preferredReturnStrategy || 'back',
|
|
546
|
+
returnScheme: this.currentWallet.requiresReturnScheme !== false ? this.config.scheme : undefined,
|
|
547
|
+
};
|
|
548
|
+
// Encode payload
|
|
549
|
+
const { encodeBase64URL } = require('./core/protocol');
|
|
550
|
+
const encoded = encodeBase64URL(payload);
|
|
551
|
+
// Build URL
|
|
552
|
+
const baseUrl = this.currentWallet.universalLink.endsWith('/ton-connect')
|
|
553
|
+
? this.currentWallet.universalLink
|
|
554
|
+
: `${this.currentWallet.universalLink}/ton-connect`;
|
|
555
|
+
const url = `${baseUrl}/sign-data?${encoded}`;
|
|
556
|
+
// Open wallet app and wait for response
|
|
557
|
+
return new Promise((resolve, reject) => {
|
|
558
|
+
let timeout = null;
|
|
559
|
+
let resolved = false;
|
|
560
|
+
// CRITICAL FIX: Check if sign data is already in progress
|
|
561
|
+
if (this.signDataPromise) {
|
|
562
|
+
throw new TonConnectError('Sign data request already in progress');
|
|
563
|
+
}
|
|
564
|
+
// Create promise for sign data
|
|
565
|
+
const signDataPromise = {
|
|
566
|
+
resolve: (response) => {
|
|
567
|
+
if (timeout !== null) {
|
|
568
|
+
clearTimeout(timeout);
|
|
569
|
+
}
|
|
570
|
+
resolved = true;
|
|
571
|
+
if (this.signDataPromise === signDataPromise) {
|
|
572
|
+
this.signDataPromise = null;
|
|
573
|
+
}
|
|
574
|
+
resolve(response);
|
|
575
|
+
},
|
|
576
|
+
reject: (error) => {
|
|
577
|
+
if (timeout !== null) {
|
|
578
|
+
clearTimeout(timeout);
|
|
579
|
+
}
|
|
580
|
+
resolved = true;
|
|
581
|
+
if (this.signDataPromise === signDataPromise) {
|
|
582
|
+
this.signDataPromise = null;
|
|
583
|
+
}
|
|
584
|
+
reject(error);
|
|
585
|
+
},
|
|
586
|
+
timeout: null,
|
|
587
|
+
};
|
|
588
|
+
// Set timeout
|
|
589
|
+
timeout = setTimeout(() => {
|
|
590
|
+
if (!resolved && this.signDataPromise === signDataPromise) {
|
|
591
|
+
this.signDataPromise = null;
|
|
592
|
+
signDataPromise.reject(new TonConnectError('Sign data request timed out'));
|
|
593
|
+
}
|
|
594
|
+
}, this.config.transactionTimeout);
|
|
595
|
+
signDataPromise.timeout = timeout;
|
|
596
|
+
// Store promise for callback handling
|
|
597
|
+
// CRITICAL FIX: Don't mutate handleCallback method - use a separate tracking mechanism
|
|
598
|
+
this.signDataPromise = signDataPromise;
|
|
599
|
+
// Open URL
|
|
600
|
+
this.adapter.openURL(url, this.config.skipCanOpenURLCheck).then(() => {
|
|
601
|
+
// URL opened, wait for callback
|
|
602
|
+
// Callback will be handled by handleCallback method checking signDataPromise
|
|
603
|
+
}).catch((error) => {
|
|
604
|
+
// Clear promise on error
|
|
605
|
+
this.signDataPromise = null;
|
|
606
|
+
signDataPromise.reject(new TonConnectError(`Failed to open wallet: ${error?.message || String(error)}`));
|
|
607
|
+
});
|
|
608
|
+
});
|
|
609
|
+
}
|
|
427
610
|
/**
|
|
428
611
|
* Disconnect from wallet
|
|
429
612
|
*/
|
|
@@ -601,6 +784,7 @@ class TonConnectMobile {
|
|
|
601
784
|
this.statusChangeCallbacks.clear();
|
|
602
785
|
this.connectionPromise = null;
|
|
603
786
|
this.transactionPromise = null;
|
|
787
|
+
this.signDataPromise = null;
|
|
604
788
|
}
|
|
605
789
|
}
|
|
606
790
|
exports.TonConnectMobile = TonConnectMobile;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TonConnectButton component
|
|
3
|
+
* Compatible with @tonconnect/ui-react TonConnectButton
|
|
4
|
+
*/
|
|
5
|
+
import { ViewStyle, TextStyle } from 'react-native';
|
|
6
|
+
export interface TonConnectButtonProps {
|
|
7
|
+
/** Button text when disconnected */
|
|
8
|
+
text?: string;
|
|
9
|
+
/** Button text when connected */
|
|
10
|
+
connectedText?: string;
|
|
11
|
+
/** Custom styles */
|
|
12
|
+
style?: ViewStyle;
|
|
13
|
+
/** Custom text styles */
|
|
14
|
+
textStyle?: TextStyle;
|
|
15
|
+
/** Callback when button is pressed */
|
|
16
|
+
onPress?: () => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* TonConnectButton - Button component for connecting/disconnecting wallet
|
|
20
|
+
* Compatible with @tonconnect/ui-react TonConnectButton
|
|
21
|
+
*/
|
|
22
|
+
export declare function TonConnectButton({ text, connectedText, style, textStyle, onPress, }: TonConnectButtonProps): JSX.Element;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TonConnectButton component
|
|
4
|
+
* Compatible with @tonconnect/ui-react TonConnectButton
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.TonConnectButton = TonConnectButton;
|
|
41
|
+
const react_1 = __importStar(require("react"));
|
|
42
|
+
const react_native_1 = require("react-native");
|
|
43
|
+
const index_1 = require("./index");
|
|
44
|
+
/**
|
|
45
|
+
* TonConnectButton - Button component for connecting/disconnecting wallet
|
|
46
|
+
* Compatible with @tonconnect/ui-react TonConnectButton
|
|
47
|
+
*/
|
|
48
|
+
function TonConnectButton({ text = 'Connect Wallet', connectedText = 'Disconnect', style, textStyle, onPress, }) {
|
|
49
|
+
const tonConnectUI = (0, index_1.useTonConnectUI)();
|
|
50
|
+
const wallet = (0, index_1.useTonWallet)();
|
|
51
|
+
const isConnected = wallet?.connected || false;
|
|
52
|
+
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
53
|
+
const handlePress = async () => {
|
|
54
|
+
// CRITICAL FIX: Prevent multiple simultaneous presses
|
|
55
|
+
if (isLoading) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (onPress) {
|
|
59
|
+
onPress();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
setIsLoading(true);
|
|
63
|
+
try {
|
|
64
|
+
if (isConnected) {
|
|
65
|
+
await tonConnectUI.disconnect();
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
await tonConnectUI.openModal();
|
|
69
|
+
await tonConnectUI.connectWallet();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
// CRITICAL FIX: Handle errors gracefully
|
|
74
|
+
console.error('TonConnectButton error:', error);
|
|
75
|
+
// Error is already handled by the SDK/UI, just reset loading state
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
setIsLoading(false);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
return (react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.button, style, isLoading && styles.buttonDisabled], onPress: handlePress, disabled: isLoading }, isLoading ? (react_1.default.createElement(react_native_1.ActivityIndicator, { color: "#ffffff" })) : (react_1.default.createElement(react_native_1.Text, { style: [styles.buttonText, textStyle] }, isConnected ? connectedText : text))));
|
|
82
|
+
}
|
|
83
|
+
const styles = react_native_1.StyleSheet.create({
|
|
84
|
+
button: {
|
|
85
|
+
backgroundColor: '#0088cc',
|
|
86
|
+
paddingHorizontal: 24,
|
|
87
|
+
paddingVertical: 12,
|
|
88
|
+
borderRadius: 8,
|
|
89
|
+
alignItems: 'center',
|
|
90
|
+
justifyContent: 'center',
|
|
91
|
+
minHeight: 44,
|
|
92
|
+
},
|
|
93
|
+
buttonDisabled: {
|
|
94
|
+
opacity: 0.6,
|
|
95
|
+
},
|
|
96
|
+
buttonText: {
|
|
97
|
+
color: '#ffffff',
|
|
98
|
+
fontSize: 16,
|
|
99
|
+
fontWeight: '600',
|
|
100
|
+
},
|
|
101
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React integration layer for @tonconnect/ui-react compatibility
|
|
3
|
+
* Provides TonConnectUIProvider, hooks, and components compatible with @tonconnect/ui-react API
|
|
4
|
+
*/
|
|
5
|
+
import { ReactNode } from 'react';
|
|
6
|
+
import { TonConnectMobile, WalletInfo, SendTransactionRequest } from '../index';
|
|
7
|
+
import type { TonConnectMobileConfig } from '../types';
|
|
8
|
+
/**
|
|
9
|
+
* Account information (compatible with @tonconnect/ui-react)
|
|
10
|
+
*/
|
|
11
|
+
export interface Account {
|
|
12
|
+
address: string;
|
|
13
|
+
chain: number;
|
|
14
|
+
publicKey?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Wallet state (compatible with @tonconnect/ui-react)
|
|
18
|
+
*/
|
|
19
|
+
export interface WalletState {
|
|
20
|
+
account: Account | null;
|
|
21
|
+
wallet: WalletInfo | null;
|
|
22
|
+
connected: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Transaction response (compatible with @tonconnect/ui-react)
|
|
26
|
+
*/
|
|
27
|
+
export interface TransactionResponse {
|
|
28
|
+
boc: string;
|
|
29
|
+
signature: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Sign data request
|
|
33
|
+
*/
|
|
34
|
+
export interface SignDataRequest {
|
|
35
|
+
/** Data to sign (will be base64 encoded) */
|
|
36
|
+
data: string | Uint8Array;
|
|
37
|
+
/** Optional version */
|
|
38
|
+
version?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Sign data response
|
|
42
|
+
*/
|
|
43
|
+
export interface SignDataResponse {
|
|
44
|
+
signature: string;
|
|
45
|
+
timestamp: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* TonConnect UI instance interface (compatible with @tonconnect/ui-react)
|
|
49
|
+
*/
|
|
50
|
+
export interface TonConnectUI {
|
|
51
|
+
/** Open connection modal */
|
|
52
|
+
openModal: () => Promise<void>;
|
|
53
|
+
/** Close connection modal */
|
|
54
|
+
closeModal: () => void;
|
|
55
|
+
/** Connect to wallet */
|
|
56
|
+
connectWallet: () => Promise<void>;
|
|
57
|
+
/** Disconnect from wallet */
|
|
58
|
+
disconnect: () => Promise<void>;
|
|
59
|
+
/** Send transaction */
|
|
60
|
+
sendTransaction: (transaction: SendTransactionRequest) => Promise<TransactionResponse>;
|
|
61
|
+
/** Sign data */
|
|
62
|
+
signData: (request: SignDataRequest) => Promise<SignDataResponse>;
|
|
63
|
+
/** Current wallet state */
|
|
64
|
+
wallet: WalletState | null;
|
|
65
|
+
/** Modal open state */
|
|
66
|
+
modalState: {
|
|
67
|
+
open: boolean;
|
|
68
|
+
};
|
|
69
|
+
/** UI kit version */
|
|
70
|
+
uiVersion: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* TonConnectUIProvider props
|
|
74
|
+
*/
|
|
75
|
+
export interface TonConnectUIProviderProps {
|
|
76
|
+
/** SDK configuration */
|
|
77
|
+
config: TonConnectMobileConfig;
|
|
78
|
+
/** Children */
|
|
79
|
+
children: ReactNode;
|
|
80
|
+
/** Optional SDK instance (for testing or custom instances) */
|
|
81
|
+
sdkInstance?: TonConnectMobile;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* TonConnectUIProvider - React context provider for TON Connect
|
|
85
|
+
* Compatible with @tonconnect/ui-react API
|
|
86
|
+
*/
|
|
87
|
+
export declare function TonConnectUIProvider({ config, children, sdkInstance, }: TonConnectUIProviderProps): JSX.Element;
|
|
88
|
+
/**
|
|
89
|
+
* Hook to access TonConnectUI instance
|
|
90
|
+
* Compatible with @tonconnect/ui-react useTonConnectUI hook
|
|
91
|
+
*/
|
|
92
|
+
export declare function useTonConnectUI(): TonConnectUI;
|
|
93
|
+
/**
|
|
94
|
+
* Hook to access wallet state
|
|
95
|
+
* Compatible with @tonconnect/ui-react useTonWallet hook
|
|
96
|
+
*/
|
|
97
|
+
export declare function useTonWallet(): WalletState | null;
|
|
98
|
+
/**
|
|
99
|
+
* Hook to access modal state
|
|
100
|
+
* Compatible with @tonconnect/ui-react useTonConnectModal hook
|
|
101
|
+
*/
|
|
102
|
+
export declare function useTonConnectModal(): {
|
|
103
|
+
open: boolean;
|
|
104
|
+
close: () => void;
|
|
105
|
+
openModal: () => Promise<void>;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Hook to access SDK instance (for advanced usage)
|
|
109
|
+
*/
|
|
110
|
+
export declare function useTonConnectSDK(): TonConnectMobile;
|