@dynamic-labs/ton 4.60.1 → 4.61.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/package.cjs +1 -1
  3. package/package.js +1 -1
  4. package/package.json +8 -8
  5. package/src/TonWalletConnector.cjs +1 -1
  6. package/src/TonWalletConnector.js +1 -1
  7. package/src/connectors/TonConnectConnector/TonConnectConnector.cjs +709 -0
  8. package/src/connectors/TonConnectConnector/TonConnectConnector.d.ts +169 -0
  9. package/src/connectors/TonConnectConnector/TonConnectConnector.js +705 -0
  10. package/src/connectors/TonConnectConnector/index.d.ts +1 -0
  11. package/src/consts.d.ts +4 -0
  12. package/src/index.cjs +11 -5
  13. package/src/index.d.ts +6 -1
  14. package/src/index.js +8 -3
  15. package/src/types.d.ts +61 -1
  16. package/src/utils/debugLog/debugLog.cjs +55 -0
  17. package/src/utils/debugLog/debugLog.d.ts +34 -0
  18. package/src/utils/debugLog/debugLog.js +49 -0
  19. package/src/utils/debugLog/index.d.ts +1 -0
  20. package/src/utils/fetchTonWalletConnectors/fetchTonWalletConnectors.cjs +113 -0
  21. package/src/utils/fetchTonWalletConnectors/fetchTonWalletConnectors.d.ts +41 -0
  22. package/src/utils/fetchTonWalletConnectors/fetchTonWalletConnectors.js +108 -0
  23. package/src/utils/fetchTonWalletConnectors/index.d.ts +1 -0
  24. package/src/utils/index.d.ts +1 -0
  25. package/src/waas/connector/DynamicWaasTonConnector.d.ts +1 -2
  26. package/src/wallet/TonWallet/TonWallet.cjs +140 -0
  27. package/src/wallet/TonWallet/TonWallet.d.ts +65 -0
  28. package/src/wallet/TonWallet/TonWallet.js +136 -0
  29. package/src/wallet/TonWallet/index.d.ts +1 -0
  30. package/src/wallet/WaasTonWallet.cjs +1 -1
  31. package/src/wallet/WaasTonWallet.js +1 -1
  32. package/src/wallet/isTonWallet/isTonWallet.cjs +7 -1
  33. package/src/wallet/isTonWallet/isTonWallet.d.ts +7 -1
  34. package/src/wallet/isTonWallet/isTonWallet.js +7 -1
  35. package/src/TonWalletConnectors.cjs +0 -13
  36. package/src/TonWalletConnectors.d.ts +0 -2
  37. package/src/TonWalletConnectors.js +0 -9
  38. package/src/wallet/TonWallet.cjs +0 -109
  39. package/src/wallet/TonWallet.d.ts +0 -60
  40. package/src/wallet/TonWallet.js +0 -105
@@ -0,0 +1,709 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var _tslib = require('../../../_virtual/_tslib.cjs');
7
+ var sdk = require('@tonconnect/sdk');
8
+ var core = require('@ton/core');
9
+ var ton = require('@ton/ton');
10
+ var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
11
+ var utils = require('@dynamic-labs/utils');
12
+ var TonWallet = require('../../wallet/TonWallet/TonWallet.cjs');
13
+ var debugLog = require('../../utils/debugLog/debugLog.cjs');
14
+ var TonUiTransaction = require('../../utils/TonUiTransaction/TonUiTransaction.cjs');
15
+ var prepareTonTransfer = require('../../utils/prepareTonTransfer/prepareTonTransfer.cjs');
16
+ var prepareJettonTransfer = require('../../utils/prepareJettonTransfer/prepareJettonTransfer.cjs');
17
+
18
+ /**
19
+ * TON Connect connector implementation
20
+ *
21
+ * Uses the TON Connect SDK to connect with TON wallets that support
22
+ * the TON Connect protocol (Tonkeeper, MyTonWallet, etc.)
23
+ */
24
+ class TonConnectConnector extends walletConnectorCore.WalletConnectorBase {
25
+ /**
26
+ * Get the TonConnect instance (for discovering wallets and advanced usage)
27
+ */
28
+ getTonConnect() {
29
+ if (!this.tonConnect) {
30
+ const manifestUrl = typeof window !== 'undefined'
31
+ ? `${window.location.origin}/tonconnect-manifest.json`
32
+ : 'https://dynamic.xyz/tonconnect-manifest.json';
33
+ // Debug logging
34
+ debugLog.debugLogMultiline([
35
+ '[TON Connect] Initializing TonConnect with manifest URL:',
36
+ manifestUrl,
37
+ ], [
38
+ '[TON Connect] Current origin:',
39
+ typeof window !== 'undefined' ? window.location.origin : 'SSR',
40
+ ]);
41
+ this.tonConnect = new sdk.TonConnect({
42
+ manifestUrl,
43
+ });
44
+ }
45
+ return this.tonConnect;
46
+ }
47
+ /**
48
+ * Creates a new TON Connect connector
49
+ *
50
+ * @param opts - Configuration options
51
+ */
52
+ constructor(opts) {
53
+ super(opts);
54
+ this.ChainWallet = TonWallet.TonWallet;
55
+ this.name = 'TON Connect';
56
+ this.overrideKey = 'tonconnect';
57
+ this.connectedChain = 'TON';
58
+ this.supportedChains = ['TON'];
59
+ this.canConnectViaQrCode = true;
60
+ this.connectedWallet = null;
61
+ this.pendingProofPayload = null;
62
+ this.tonNetworks = opts.tonNetworks || [];
63
+ this.overrideKey = opts.overrideKey || 'tonconnect';
64
+ // Only initialize TonConnect in browser environment
65
+ // This prevents SSR errors and allows the connector to be created
66
+ if (typeof window !== 'undefined') {
67
+ try {
68
+ const manifestUrl = opts.manifestUrl ||
69
+ `${window.location.origin}/tonconnect-manifest.json`;
70
+ // Debug logging
71
+ debugLog.debugLogMultiline(['[TON Connect] Constructor - manifest URL:', manifestUrl], [
72
+ '[TON Connect] Constructor - window.location:',
73
+ { href: window.location.href, origin: window.location.origin },
74
+ ]);
75
+ this.tonConnect = new sdk.TonConnect({
76
+ manifestUrl,
77
+ });
78
+ }
79
+ catch (error) {
80
+ // If TonConnect fails to initialize, set to null and initialize lazily
81
+ walletConnectorCore.logger.error('[TON Connect] Failed to initialize TonConnect:', error);
82
+ debugLog.debugLogWithLevel('error', '[TON Connect] Constructor - Error initializing:', error);
83
+ this.tonConnect = null;
84
+ }
85
+ }
86
+ else {
87
+ // For SSR, tonConnect will be null and initialized lazily in getTonConnect()
88
+ this.tonConnect = null;
89
+ }
90
+ }
91
+ /**
92
+ * Setup event listeners for TON Connect
93
+ */
94
+ setupEventListeners() {
95
+ if (typeof window === 'undefined') {
96
+ return;
97
+ }
98
+ const tonConnect = this.getTonConnect();
99
+ tonConnect.onStatusChange((wallet) => {
100
+ if (wallet) {
101
+ this.connectedWallet = wallet;
102
+ const userFriendlyAddress = this.convertAddressToUserFriendly(wallet.account.address);
103
+ this.emit('accountChange', { accounts: [userFriendlyAddress] });
104
+ }
105
+ else {
106
+ this.connectedWallet = null;
107
+ this.emit('disconnect');
108
+ }
109
+ });
110
+ }
111
+ /**
112
+ * Check if TON Connect is available
113
+ */
114
+ isInstalledOnBrowser() {
115
+ // TON Connect wallets are mobile apps, not browser extensions
116
+ // Return false so they show as QR code/deep link wallets
117
+ return false;
118
+ }
119
+ /**
120
+ * Connect to a TON wallet
121
+ * @param tonProofPayload - Optional payload for tonProof authentication
122
+ */
123
+ connect(tonProofPayload) {
124
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
125
+ try {
126
+ const tonConnect = this.getTonConnect();
127
+ // If already connected, return early
128
+ if (tonConnect.connected) {
129
+ return;
130
+ }
131
+ // Get available wallets
132
+ const wallets = yield tonConnect.getWallets();
133
+ if (wallets.length === 0) {
134
+ throw new utils.DynamicError('No TON wallets available');
135
+ }
136
+ const matchingWallet = this.findMatchingWallet(wallets);
137
+ if (!matchingWallet) {
138
+ throw new utils.DynamicError(`TON wallet "${this.overrideKey}" not found in available wallets`);
139
+ }
140
+ try {
141
+ // Use provided payload or pending payload for tonProof
142
+ const proofPayload = tonProofPayload || this.pendingProofPayload;
143
+ const connectOptions = proofPayload
144
+ ? { request: { tonProof: proofPayload } }
145
+ : undefined;
146
+ tonConnect.connect(matchingWallet, connectOptions);
147
+ }
148
+ catch (error) {
149
+ debugLog.debugLogWithLevel('error', '[TON Connect] Error during connect:', error);
150
+ throw error;
151
+ }
152
+ }
153
+ catch (error) {
154
+ if (this.isUserRejectionError(error)) {
155
+ throw new utils.DynamicError('User rejected connection');
156
+ }
157
+ walletConnectorCore.logger.error('[TON Connect] Connection failed:', error);
158
+ throw new utils.DynamicError(`Failed to connect to TON wallet: ${error instanceof Error ? error.message : String(error)}`);
159
+ }
160
+ });
161
+ }
162
+ /**
163
+ * Find a wallet matching this connector's overrideKey
164
+ */
165
+ findMatchingWallet(wallets) {
166
+ const overrideKeyLower = this.overrideKey.toLowerCase();
167
+ return (wallets.find((wallet) => wallet.appName.toLowerCase() === overrideKeyLower ||
168
+ wallet.name.toLowerCase() === overrideKeyLower) ||
169
+ wallets.find((wallet) => wallet.appName.toLowerCase().startsWith(overrideKeyLower) ||
170
+ wallet.name.toLowerCase().startsWith(overrideKeyLower)) ||
171
+ wallets.find((wallet) => wallet.appName.toLowerCase().includes(overrideKeyLower) ||
172
+ wallet.name.toLowerCase().includes(overrideKeyLower)));
173
+ }
174
+ /**
175
+ * Get the current wallet address in user-friendly format (EQ... or UQ...)
176
+ */
177
+ getAddress() {
178
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
179
+ var _a, _b, _c;
180
+ const tonConnect = this.getTonConnect();
181
+ // If already connected, return the address immediately
182
+ if (tonConnect.connected && ((_a = tonConnect.account) === null || _a === void 0 ? void 0 : _a.address)) {
183
+ return this.convertAddressToUserFriendly(tonConnect.account.address);
184
+ }
185
+ // If not connected, initiate connection and wait for it to complete
186
+ try {
187
+ // Start the connection process (shows QR code/deep link)
188
+ yield this.connect();
189
+ // After connect() returns, the QR code is shown but connection is not yet established
190
+ // Wait for the connection to be established by polling or waiting for status change
191
+ // TON Connect SDK doesn't provide a clean way to wait, so we poll
192
+ const maxWaitTime = 300000; // 5 minutes
193
+ const pollInterval = 500; // Check every 500ms
194
+ const startTime = Date.now();
195
+ while (!tonConnect.connected && Date.now() - startTime < maxWaitTime) {
196
+ yield new Promise((resolve) => setTimeout(resolve, pollInterval));
197
+ // Check if connected after the delay
198
+ if (tonConnect.connected && ((_b = tonConnect.account) === null || _b === void 0 ? void 0 : _b.address)) {
199
+ const userFriendlyAddress = this.convertAddressToUserFriendly(tonConnect.account.address);
200
+ return userFriendlyAddress;
201
+ }
202
+ }
203
+ // If we get here, either timeout or still not connected
204
+ if (!tonConnect.connected) {
205
+ throw new utils.DynamicError('Connection timeout - user did not approve the connection');
206
+ }
207
+ const rawAddress = (_c = tonConnect.account) === null || _c === void 0 ? void 0 : _c.address;
208
+ return rawAddress
209
+ ? this.convertAddressToUserFriendly(rawAddress)
210
+ : undefined;
211
+ }
212
+ catch (error) {
213
+ walletConnectorCore.logger.error('[TON Connect] Failed to get address:', error);
214
+ throw error;
215
+ }
216
+ });
217
+ }
218
+ /**
219
+ * Get connected accounts
220
+ */
221
+ getConnectedAccounts() {
222
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
223
+ var _a;
224
+ const tonConnect = this.getTonConnect();
225
+ if (!tonConnect.connected || !((_a = tonConnect.account) === null || _a === void 0 ? void 0 : _a.address)) {
226
+ return [];
227
+ }
228
+ return [this.convertAddressToUserFriendly(tonConnect.account.address)];
229
+ });
230
+ }
231
+ /**
232
+ * Get the current network
233
+ */
234
+ getNetwork() {
235
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
236
+ var _a;
237
+ const tonConnect = this.getTonConnect();
238
+ if (!tonConnect.connected) {
239
+ return '-239'; // Mainnet default (chain ID -239)
240
+ }
241
+ const { account } = tonConnect;
242
+ // TON mainnet chain ID is -239, testnet is -3
243
+ return ((_a = account === null || account === void 0 ? void 0 : account.chain) === null || _a === void 0 ? void 0 : _a.toString()) || '-239';
244
+ });
245
+ }
246
+ /**
247
+ * Check if current network is testnet
248
+ */
249
+ isTestnet() {
250
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
251
+ const network = yield this.getNetwork();
252
+ // TON testnet chain ID is -3
253
+ return network === '-3';
254
+ });
255
+ }
256
+ /**
257
+ * Sign a message
258
+ */
259
+ signMessage(messageToSign) {
260
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
261
+ const tonConnect = this.getTonConnect();
262
+ if (!tonConnect.connected) {
263
+ throw new utils.DynamicError('Wallet not connected');
264
+ }
265
+ try {
266
+ const result = yield tonConnect.signData({
267
+ text: messageToSign,
268
+ type: 'text',
269
+ });
270
+ return result.signature;
271
+ }
272
+ catch (error) {
273
+ if (this.isUserRejectionError(error)) {
274
+ throw new utils.DynamicError('User rejected message signing');
275
+ }
276
+ walletConnectorCore.logger.error('[TON Connect] Sign message failed:', error);
277
+ throw new utils.DynamicError(`Failed to sign message: ${error instanceof Error ? error.message : String(error)}`);
278
+ }
279
+ });
280
+ }
281
+ /**
282
+ * Send a transaction
283
+ */
284
+ sendTransaction(request) {
285
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
286
+ const tonConnect = this.getTonConnect();
287
+ if (!tonConnect.connected) {
288
+ throw new utils.DynamicError('Wallet not connected');
289
+ }
290
+ try {
291
+ // Convert addresses from raw format (0:hex) to user-friendly format (EQ...)
292
+ // TON Connect SDK expects user-friendly format for message addresses
293
+ const messages = request.messages.map((message) => (Object.assign(Object.assign({}, message), { address: this.convertAddressToUserFriendly(message.address) })));
294
+ // 'from' is omitted as TonConnect uses the connected wallet's address
295
+ const transactionRequest = {
296
+ messages,
297
+ network: request.network,
298
+ validUntil: request.validUntil || Math.floor(Date.now() / 1000) + 300, // 5 minutes from now
299
+ };
300
+ const result = yield tonConnect.sendTransaction(transactionRequest);
301
+ return {
302
+ boc: result.boc,
303
+ hash: result.boc, // TON Connect returns boc as the transaction identifier
304
+ };
305
+ }
306
+ catch (error) {
307
+ if (this.isUserRejectionError(error)) {
308
+ throw new utils.DynamicError('User rejected transaction');
309
+ }
310
+ walletConnectorCore.logger.error('[TON Connect] Send transaction failed:', error);
311
+ throw new utils.DynamicError(`Failed to send transaction: ${error instanceof Error ? error.message : String(error)}`);
312
+ }
313
+ });
314
+ }
315
+ /**
316
+ * Send Jetton transaction
317
+ */
318
+ sendJettonTransaction(
319
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
320
+ _options) {
321
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
322
+ // Jetton transfers require constructing a specific message
323
+ // This is a simplified version - full implementation would need
324
+ // to construct the proper Jetton transfer message
325
+ throw new utils.DynamicError('Jetton transfers not yet implemented');
326
+ });
327
+ }
328
+ /**
329
+ * Get TonClient for the current or specified network.
330
+ */
331
+ getTonClient(chainId) {
332
+ var _a, _b, _c, _d, _e;
333
+ const targetChainId = chainId || ((_b = (_a = this.tonNetworks) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.chainId);
334
+ const network = (_c = this.tonNetworks) === null || _c === void 0 ? void 0 : _c.find((net) => net.chainId === targetChainId);
335
+ if (!network) {
336
+ throw new utils.DynamicError(`Network configuration not found for chainId: ${targetChainId}`);
337
+ }
338
+ const endpoint = ((_d = network.privateCustomerRpcUrls) === null || _d === void 0 ? void 0 : _d[0]) || ((_e = network.rpcUrls) === null || _e === void 0 ? void 0 : _e[0]);
339
+ if (!endpoint) {
340
+ throw new utils.DynamicError(`No RPC endpoint found for chainId: ${targetChainId}`);
341
+ }
342
+ return new ton.TonClient({ endpoint });
343
+ }
344
+ /**
345
+ * Get balance of an address
346
+ */
347
+ getBalance(address) {
348
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
349
+ try {
350
+ const client = this.getTonClient();
351
+ const tonAddress = core.Address.parse(address);
352
+ const balanceNano = yield client.getBalance(tonAddress);
353
+ const balance = ton.fromNano(balanceNano);
354
+ return balance;
355
+ }
356
+ catch (error) {
357
+ walletConnectorCore.logger.error('[TON Connect] Failed to get balance:', error);
358
+ return undefined;
359
+ }
360
+ });
361
+ }
362
+ /**
363
+ * Get enabled networks
364
+ */
365
+ getEnabledNetworks() {
366
+ return this.tonNetworks;
367
+ }
368
+ /**
369
+ * Switch network (TON Connect handles this automatically)
370
+ */
371
+ switchNetwork() {
372
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
373
+ // TON Connect manages network switching through the wallet UI
374
+ throw new utils.DynamicError('Network switching must be done manually in the TON wallet');
375
+ });
376
+ }
377
+ /**
378
+ * Disconnect and cleanup
379
+ */
380
+ endSession() {
381
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
382
+ try {
383
+ const tonConnect = this.getTonConnect();
384
+ if (tonConnect.connected) {
385
+ yield tonConnect.disconnect();
386
+ }
387
+ }
388
+ catch (error) {
389
+ walletConnectorCore.logger.debug('[TON Connect] Error during disconnect:', error);
390
+ }
391
+ });
392
+ }
393
+ /**
394
+ * Create a UI transaction for the send balance flow
395
+ */
396
+ createUiTransaction(from) {
397
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
398
+ yield this.validateActiveWallet(from);
399
+ const client = this.getTonClient();
400
+ return new TonUiTransaction.TonUiTransaction({
401
+ client,
402
+ from,
403
+ onSubmit: (transaction) => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSendUiTransaction(transaction); }),
404
+ });
405
+ });
406
+ }
407
+ /**
408
+ * Internal handler for UI transaction submission
409
+ */
410
+ internalSendUiTransaction(transaction) {
411
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
412
+ var _a;
413
+ if (!transaction.to) {
414
+ throw new utils.DynamicError('Destination address is required');
415
+ }
416
+ const tonConnect = this.getTonConnect();
417
+ if (!tonConnect.connected || !((_a = tonConnect.account) === null || _a === void 0 ? void 0 : _a.address)) {
418
+ throw new utils.DynamicError('Wallet not connected');
419
+ }
420
+ const walletAddress = this.convertAddressToUserFriendly(tonConnect.account.address);
421
+ const client = this.getTonClient();
422
+ const network = tonConnect.account.chain;
423
+ // Jetton (non-native token) transfers
424
+ // TODO: Test it when token balances are implemented
425
+ if (transaction.nonNativeAddress && transaction.nonNativeValue) {
426
+ const request = yield prepareJettonTransfer.prepareJettonTransfer({
427
+ client,
428
+ forwardTonAmount: BigInt(0),
429
+ jettonAmount: transaction.nonNativeValue,
430
+ jettonMasterAddress: transaction.nonNativeAddress,
431
+ network,
432
+ recipientAddress: transaction.to,
433
+ timeout: 60,
434
+ walletAddress,
435
+ });
436
+ const result = yield this.sendTransaction(request);
437
+ return result.boc || result.hash || '';
438
+ }
439
+ // Native TON transfers
440
+ if (transaction.value) {
441
+ const tonAmount = Number(transaction.value) / TonUiTransaction.NANOTON_PER_TON;
442
+ const request = yield prepareTonTransfer.prepareTonTransfer({
443
+ amount: tonAmount,
444
+ client,
445
+ network,
446
+ recipient: transaction.to,
447
+ timeout: 60,
448
+ walletAddress,
449
+ });
450
+ const result = yield this.sendTransaction(request);
451
+ return result.boc || result.hash || '';
452
+ }
453
+ throw new utils.DynamicError('Invalid transaction parameters');
454
+ });
455
+ }
456
+ /**
457
+ * Convert TON address from raw format (0:hex) to user-friendly format (UQ...)
458
+ * TON Connect SDK expects user-friendly format for message addresses
459
+ */
460
+ convertAddressToUserFriendly(address) {
461
+ var _a;
462
+ try {
463
+ if (address.startsWith('EQ') || address.startsWith('UQ')) {
464
+ return address;
465
+ }
466
+ // Detect if testnet from connected wallet
467
+ const tonConnect = this.getTonConnect();
468
+ const isTestnet = ((_a = tonConnect.account) === null || _a === void 0 ? void 0 : _a.chain) === '-3';
469
+ // Convert from raw format (0:hex) to user-friendly format
470
+ return core.Address.parse(address).toString({
471
+ bounceable: false,
472
+ testOnly: isTestnet,
473
+ urlSafe: true,
474
+ });
475
+ }
476
+ catch (error) {
477
+ // If parsing fails, return original address
478
+ walletConnectorCore.logger.debug('[TON Connect] Failed to convert address format:', error);
479
+ return address;
480
+ }
481
+ }
482
+ /**
483
+ * Encode a comment as TON message payload
484
+ *
485
+ * TON comments are encoded as a Cell with:
486
+ * - First 32 bits (4 bytes): 0x00000000 (comment opcode)
487
+ * - Then the UTF-8 bytes of the comment
488
+ *
489
+ * For long messages, the comment is split across multiple cells using references.
490
+ * The Cell is then serialized to base64 BOC format for TON Connect SDK
491
+ */
492
+ encodeComment(comment) {
493
+ const encoder = new TextEncoder();
494
+ const commentBytes = encoder.encode(comment);
495
+ // TON Cell can hold max 1023 bits
496
+ // We use 32 bits for the opcode, leaving ~991 bits (~123 bytes) for data
497
+ // For longer messages, we split into multiple cells using references
498
+ const maxBytesPerCell = 123; // Conservative estimate to avoid overflow
499
+ if (commentBytes.length <= maxBytesPerCell) {
500
+ // Short message fits in one cell
501
+ const cell = core.beginCell()
502
+ .storeUint(0, 32) // Comment opcode
503
+ .storeBuffer(Buffer.from(commentBytes))
504
+ .endCell();
505
+ return cell.toBoc().toString('base64');
506
+ }
507
+ // Long message: split across multiple cells
508
+ // First cell: opcode + first chunk
509
+ // Remaining chunks go in reference cells
510
+ const firstChunk = commentBytes.slice(0, maxBytesPerCell);
511
+ const remainingBytes = commentBytes.slice(maxBytesPerCell);
512
+ // Build reference cells for remaining data
513
+ let remainingData = remainingBytes;
514
+ // Create cells for remaining data (each can hold ~127 bytes)
515
+ const referenceCells = [];
516
+ while (remainingData.length > 0) {
517
+ const chunk = remainingData.slice(0, 127);
518
+ remainingData = remainingData.slice(127);
519
+ referenceCells.push(core.beginCell().storeBuffer(Buffer.from(chunk)).endCell());
520
+ }
521
+ // Build the main cell with opcode, first chunk, and references
522
+ let mainCellBuilder = core.beginCell()
523
+ .storeUint(0, 32) // Comment opcode
524
+ .storeBuffer(Buffer.from(firstChunk));
525
+ // Add reference cells
526
+ for (const refCell of referenceCells) {
527
+ mainCellBuilder = mainCellBuilder.storeRef(refCell);
528
+ }
529
+ const mainCell = mainCellBuilder.endCell();
530
+ // Serialize to base64 BOC (Bag of Cells) format
531
+ return mainCell.toBoc().toString('base64');
532
+ }
533
+ /**
534
+ * Check if error is a user rejection
535
+ */
536
+ isUserRejectionError(error) {
537
+ return (error !== null &&
538
+ typeof error === 'object' &&
539
+ 'name' in error &&
540
+ error.name === 'UserRejectsError');
541
+ }
542
+ /**
543
+ * Generate a TON Connect proof for authentication
544
+ * @param payload - The payload string to include in the proof
545
+ * @returns TON Connect proof object
546
+ */
547
+ generateTonConnectProof(payload) {
548
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
549
+ var _a, _b, _c, _d, _e, _f;
550
+ const tonConnect = this.getTonConnect();
551
+ // If already connected with a proof, return it
552
+ if ((_b = (_a = this.connectedWallet) === null || _a === void 0 ? void 0 : _a.connectItems) === null || _b === void 0 ? void 0 : _b.tonProof) {
553
+ const { tonProof } = this.connectedWallet.connectItems;
554
+ if ('proof' in tonProof) {
555
+ debugLog.debugLog('[TON Connect] Returning existing proof from connection');
556
+ return {
557
+ address: this.connectedWallet.account.address,
558
+ domain: tonProof.proof.domain,
559
+ payload: tonProof.proof.payload,
560
+ signature: tonProof.proof.signature,
561
+ timestamp: tonProof.proof.timestamp,
562
+ };
563
+ }
564
+ }
565
+ // If connected but no proof, disconnect and reconnect with proof
566
+ if (tonConnect.connected) {
567
+ debugLog.debugLog('[TON Connect] Already connected without proof, disconnecting to reconnect with tonProof');
568
+ yield tonConnect.disconnect();
569
+ this.connectedWallet = null;
570
+ }
571
+ // Store the payload for the connect call
572
+ this.pendingProofPayload = payload;
573
+ // Connect with tonProof
574
+ yield this.connect(payload);
575
+ // Wait for the connection to be established with the proof
576
+ const maxWaitTime = 300000; // 5 minutes
577
+ const pollInterval = 500;
578
+ const startTime = Date.now();
579
+ while (Date.now() - startTime < maxWaitTime) {
580
+ yield new Promise((resolve) => setTimeout(resolve, pollInterval));
581
+ if (tonConnect.connected &&
582
+ ((_d = (_c = tonConnect.wallet) === null || _c === void 0 ? void 0 : _c.connectItems) === null || _d === void 0 ? void 0 : _d.tonProof) &&
583
+ 'proof' in tonConnect.wallet.connectItems.tonProof) {
584
+ this.connectedWallet = tonConnect.wallet;
585
+ const { tonProof } = tonConnect.wallet.connectItems;
586
+ // Clear the pending payload
587
+ this.pendingProofPayload = null;
588
+ return {
589
+ address: tonConnect.wallet.account.address,
590
+ domain: tonProof.proof.domain,
591
+ payload: tonProof.proof.payload,
592
+ signature: tonProof.proof.signature,
593
+ timestamp: tonProof.proof.timestamp,
594
+ };
595
+ }
596
+ // Check if connected but proof was rejected or not supported
597
+ if (tonConnect.connected && !((_f = (_e = tonConnect.wallet) === null || _e === void 0 ? void 0 : _e.connectItems) === null || _f === void 0 ? void 0 : _f.tonProof)) {
598
+ this.pendingProofPayload = null;
599
+ throw new utils.DynamicError('Wallet connected but did not provide proof. The wallet may not support tonProof.');
600
+ }
601
+ }
602
+ this.pendingProofPayload = null;
603
+ throw new utils.DynamicError('Connection timeout - user did not approve the connection');
604
+ });
605
+ }
606
+ /**
607
+ * Override proveOwnership to use tonProof for wallet verification
608
+ *
609
+ * For TON wallets, we use the tonProof mechanism during connection
610
+ * which is the standard way to prove wallet ownership in TON Connect.
611
+ * The backend expects a specific format with state_init and public_key.
612
+ */
613
+ proveOwnership(address, messageToSign) {
614
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
615
+ yield this.validateActiveWallet(address);
616
+ return this.proveOwnershipWithTonProof(messageToSign);
617
+ });
618
+ }
619
+ /**
620
+ * proveOwnership using tonProof
621
+ *
622
+ * Returns the proof in the format expected by the backend:
623
+ * {
624
+ * address: string,
625
+ * proof: { domain, payload, signature, state_init, timestamp },
626
+ * public_key: string
627
+ * }
628
+ */
629
+ proveOwnershipWithTonProof(messageToSign) {
630
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
631
+ var _a, _b;
632
+ // Extract the nonce from the SIWE message to use as tonProof payload
633
+ // The tonProof payload has a 128 byte limit, so we can't use the full message
634
+ const payload = this.extractNonceFromMessage(messageToSign);
635
+ // Use tonProof for authentication - this ensures we have connectedWallet set
636
+ const proof = yield this.generateTonConnectProof(payload);
637
+ // Get state_init from the connected wallet account
638
+ const stateInit = (_a = this.connectedWallet) === null || _a === void 0 ? void 0 : _a.account.walletStateInit;
639
+ if (!stateInit) {
640
+ throw new utils.DynamicError('Wallet did not provide state_init required for verification');
641
+ }
642
+ // Get public key from wallet - this is the key that signed the proof
643
+ // The wallet provides this in account.publicKey (hex without 0x prefix)
644
+ const walletProvidedKey = (_b = this.connectedWallet) === null || _b === void 0 ? void 0 : _b.account.publicKey;
645
+ const publicKey = walletProvidedKey || this.extractPublicKeyFromStateInit(stateInit);
646
+ return JSON.stringify({
647
+ address: proof.address,
648
+ proof: {
649
+ domain: proof.domain,
650
+ payload: proof.payload,
651
+ signature: proof.signature,
652
+ state_init: stateInit,
653
+ timestamp: proof.timestamp,
654
+ },
655
+ public_key: publicKey,
656
+ });
657
+ });
658
+ }
659
+ /**
660
+ * Extract public key from state_init cell
661
+ *
662
+ * For standard TON wallets, the public key is stored in the data cell:
663
+ * - First 32 bits: seqno (skipped)
664
+ * - Next 256 bits (32 bytes): public key
665
+ *
666
+ * This matches the extraction logic in the backend.
667
+ */
668
+ extractPublicKeyFromStateInit(stateInitBase64) {
669
+ try {
670
+ const cell = core.Cell.fromBase64(stateInitBase64);
671
+ const stateInit = core.loadStateInit(cell.beginParse());
672
+ const dataCell = stateInit.data;
673
+ if (!dataCell) {
674
+ throw new Error('No data cell in state_init');
675
+ }
676
+ const dataSlice = dataCell.beginParse();
677
+ // Skip first 32 bits (seqno for most wallets)
678
+ dataSlice.loadUint(32);
679
+ // Next 256 bits (32 bytes) is the public key
680
+ const publicKeyBuffer = dataSlice.loadBuffer(32);
681
+ // Convert to hex string (no 0x prefix, as expected by backend)
682
+ const hexKey = Buffer.from(publicKeyBuffer).toString('hex');
683
+ return hexKey;
684
+ }
685
+ catch (error) {
686
+ walletConnectorCore.logger.error('[TON Connect] Failed to extract public key from state_init:', error);
687
+ debugLog.debugLog('[TON Connect] state_init that failed:', stateInitBase64);
688
+ throw new utils.DynamicError('Failed to extract public key from wallet state_init');
689
+ }
690
+ }
691
+ /**
692
+ * Extract the nonce from a SIWE-style message
693
+ *
694
+ * @param message - The full message to extract nonce from
695
+ * @returns A short payload suitable for tonProof
696
+ */
697
+ extractNonceFromMessage(message) {
698
+ const nonceMatch = message.match(/Nonce:\s*([^\n\r]+)/i);
699
+ if (nonceMatch === null || nonceMatch === void 0 ? void 0 : nonceMatch[1]) {
700
+ const nonce = nonceMatch[1].trim();
701
+ if (nonce.length <= 128) {
702
+ return nonce;
703
+ }
704
+ }
705
+ return message.slice(0, 64);
706
+ }
707
+ }
708
+
709
+ exports.TonConnectConnector = TonConnectConnector;