@meshconnect/uwc-bridge-parent 1.1.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BaseWalletAdapter.d.ts +27 -0
- package/dist/BaseWalletAdapter.d.ts.map +1 -0
- package/dist/BaseWalletAdapter.js +205 -0
- package/dist/BaseWalletAdapter.js.map +1 -0
- package/dist/BaseWalletAdapter.test.d.ts +2 -0
- package/dist/BaseWalletAdapter.test.d.ts.map +1 -0
- package/dist/BaseWalletAdapter.test.js +299 -0
- package/dist/BaseWalletAdapter.test.js.map +1 -0
- package/dist/BridgeParent.d.ts +12 -0
- package/dist/BridgeParent.d.ts.map +1 -1
- package/dist/BridgeParent.js +196 -1
- package/dist/BridgeParent.js.map +1 -1
- package/dist/BridgeParent.test.js +118 -1
- package/dist/BridgeParent.test.js.map +1 -1
- package/package.json +1 -1
- package/src/BaseWalletAdapter.test.ts +371 -0
- package/src/BaseWalletAdapter.ts +295 -0
- package/src/BridgeParent.test.ts +152 -1
- package/src/BridgeParent.ts +249 -1
package/src/BridgeParent.test.ts
CHANGED
|
@@ -14,7 +14,13 @@ vi.mock('@wallet-standard/app', () => ({
|
|
|
14
14
|
|
|
15
15
|
// Mock @solana/wallet-adapter-base
|
|
16
16
|
vi.mock('@solana/wallet-adapter-base', () => ({
|
|
17
|
-
isWalletAdapterCompatibleStandardWallet: vi.fn().mockReturnValue(false)
|
|
17
|
+
isWalletAdapterCompatibleStandardWallet: vi.fn().mockReturnValue(false),
|
|
18
|
+
WalletReadyState: {
|
|
19
|
+
Installed: 'Installed',
|
|
20
|
+
NotDetected: 'NotDetected',
|
|
21
|
+
Loadable: 'Loadable',
|
|
22
|
+
Unsupported: 'Unsupported'
|
|
23
|
+
}
|
|
18
24
|
}))
|
|
19
25
|
|
|
20
26
|
// Mock @solana/wallet-standard-wallet-adapter-base
|
|
@@ -29,6 +35,20 @@ vi.mock('@solana/web3.js', () => ({
|
|
|
29
35
|
VersionedTransaction: { deserialize: vi.fn() }
|
|
30
36
|
}))
|
|
31
37
|
|
|
38
|
+
// Hoisted mock for BaseWalletAdapter - direct reference avoids restoreAllMocks issues
|
|
39
|
+
const baseAdapterMock = vi.hoisted(() => ({
|
|
40
|
+
readyState: 'NotDetected' as string,
|
|
41
|
+
shouldThrow: false,
|
|
42
|
+
fn: null as ReturnType<typeof vi.fn> | null
|
|
43
|
+
}))
|
|
44
|
+
|
|
45
|
+
baseAdapterMock.fn = vi.fn()
|
|
46
|
+
|
|
47
|
+
// Mock ./BaseWalletAdapter
|
|
48
|
+
vi.mock('./BaseWalletAdapter', () => ({
|
|
49
|
+
BaseWalletAdapter: baseAdapterMock.fn
|
|
50
|
+
}))
|
|
51
|
+
|
|
32
52
|
describe('BridgeParent', () => {
|
|
33
53
|
let mockIframe: HTMLIFrameElement
|
|
34
54
|
|
|
@@ -394,6 +414,137 @@ describe('BridgeParent', () => {
|
|
|
394
414
|
})
|
|
395
415
|
})
|
|
396
416
|
|
|
417
|
+
describe('Base Wallet detection', () => {
|
|
418
|
+
beforeEach(async () => {
|
|
419
|
+
baseAdapterMock.readyState = 'NotDetected'
|
|
420
|
+
baseAdapterMock.shouldThrow = false
|
|
421
|
+
|
|
422
|
+
// Re-set mocks that vi.restoreAllMocks() may have cleared
|
|
423
|
+
const { getWallets } = await import('@wallet-standard/app')
|
|
424
|
+
vi.mocked(getWallets).mockReturnValue({
|
|
425
|
+
get: () => [],
|
|
426
|
+
on: vi.fn(),
|
|
427
|
+
register: vi.fn()
|
|
428
|
+
} as any)
|
|
429
|
+
|
|
430
|
+
// Re-set BaseWalletAdapter mock - must use 'function' (not arrow) for 'new' compatibility
|
|
431
|
+
baseAdapterMock.fn!.mockImplementation(function () {
|
|
432
|
+
if (baseAdapterMock.shouldThrow) throw new Error('init failed')
|
|
433
|
+
return {
|
|
434
|
+
readyState: baseAdapterMock.readyState,
|
|
435
|
+
name: 'Base Wallet',
|
|
436
|
+
icon: 'data:image/svg+xml;base64,test',
|
|
437
|
+
url: 'https://example.com',
|
|
438
|
+
publicKey: null,
|
|
439
|
+
connecting: false,
|
|
440
|
+
connected: false,
|
|
441
|
+
supportedTransactionVersions: new Set(['legacy', 0]),
|
|
442
|
+
connect: vi.fn(),
|
|
443
|
+
disconnect: vi.fn(),
|
|
444
|
+
sendTransaction: vi.fn(),
|
|
445
|
+
signTransaction: vi.fn(),
|
|
446
|
+
signAllTransactions: vi.fn(),
|
|
447
|
+
signMessage: vi.fn()
|
|
448
|
+
}
|
|
449
|
+
})
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
it('should include Base Wallet when detected as Installed', async () => {
|
|
453
|
+
const Comlink = await import('comlink')
|
|
454
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
455
|
+
|
|
456
|
+
baseAdapterMock.readyState = 'Installed'
|
|
457
|
+
|
|
458
|
+
new BridgeParent(mockIframe)
|
|
459
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
460
|
+
|
|
461
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
462
|
+
const baseWallet = exposedAPI.walletStandardWallets.find(
|
|
463
|
+
(w: any) => w.name === 'Base Wallet'
|
|
464
|
+
)
|
|
465
|
+
expect(baseWallet).toBeDefined()
|
|
466
|
+
expect(baseWallet.uuid).toBe('base-wallet-traditional')
|
|
467
|
+
expect(baseWallet.chains).toEqual(['solana:mainnet'])
|
|
468
|
+
expect(baseWallet.features).toEqual(['traditional-adapter'])
|
|
469
|
+
expect(baseWallet.adapter).toBeDefined()
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
it('should include Base Wallet when detected as Loadable', async () => {
|
|
473
|
+
const Comlink = await import('comlink')
|
|
474
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
475
|
+
|
|
476
|
+
baseAdapterMock.readyState = 'Loadable'
|
|
477
|
+
|
|
478
|
+
new BridgeParent(mockIframe)
|
|
479
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
480
|
+
|
|
481
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
482
|
+
const baseWallet = exposedAPI.walletStandardWallets.find(
|
|
483
|
+
(w: any) => w.name === 'Base Wallet'
|
|
484
|
+
)
|
|
485
|
+
expect(baseWallet).toBeDefined()
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
it('should not include Base Wallet when not detected', async () => {
|
|
489
|
+
const Comlink = await import('comlink')
|
|
490
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
491
|
+
|
|
492
|
+
new BridgeParent(mockIframe)
|
|
493
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
494
|
+
|
|
495
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
496
|
+
const baseWallet = exposedAPI.walletStandardWallets.find(
|
|
497
|
+
(w: any) => w.name === 'Base Wallet'
|
|
498
|
+
)
|
|
499
|
+
expect(baseWallet).toBeUndefined()
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
it('should skip Base Wallet if name already in Wallet Standard wallets', async () => {
|
|
503
|
+
const { getWallets } = await import('@wallet-standard/app')
|
|
504
|
+
const Comlink = await import('comlink')
|
|
505
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
506
|
+
|
|
507
|
+
const existingWallet = {
|
|
508
|
+
name: 'Base Wallet',
|
|
509
|
+
chains: ['solana:mainnet'],
|
|
510
|
+
features: { 'standard:connect': {} },
|
|
511
|
+
accounts: []
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
vi.mocked(getWallets).mockReturnValue({
|
|
515
|
+
get: () => [existingWallet] as any,
|
|
516
|
+
on: vi.fn(),
|
|
517
|
+
register: vi.fn()
|
|
518
|
+
} as any)
|
|
519
|
+
|
|
520
|
+
baseAdapterMock.readyState = 'Installed'
|
|
521
|
+
|
|
522
|
+
new BridgeParent(mockIframe)
|
|
523
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
524
|
+
|
|
525
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
526
|
+
const baseWallets = exposedAPI.walletStandardWallets.filter(
|
|
527
|
+
(w: any) => w.name === 'Base Wallet'
|
|
528
|
+
)
|
|
529
|
+
expect(baseWallets).toHaveLength(1)
|
|
530
|
+
expect(baseWallets[0].features).not.toContain('traditional-adapter')
|
|
531
|
+
})
|
|
532
|
+
|
|
533
|
+
it('should handle BaseWalletAdapter constructor errors gracefully', async () => {
|
|
534
|
+
const Comlink = await import('comlink')
|
|
535
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
536
|
+
|
|
537
|
+
baseAdapterMock.shouldThrow = true
|
|
538
|
+
|
|
539
|
+
new BridgeParent(mockIframe)
|
|
540
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
541
|
+
|
|
542
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
543
|
+
expect(exposedAPI).toBeDefined()
|
|
544
|
+
expect(exposedAPI.walletStandardWallets).toEqual([])
|
|
545
|
+
})
|
|
546
|
+
})
|
|
547
|
+
|
|
397
548
|
describe('destroy', () => {
|
|
398
549
|
it('should clear all state', async () => {
|
|
399
550
|
const { BridgeParent } = await import('./BridgeParent')
|
package/src/BridgeParent.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import * as Comlink from 'comlink'
|
|
2
2
|
import type { Wallet } from '@wallet-standard/base'
|
|
3
3
|
import { getWallets } from '@wallet-standard/app'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
isWalletAdapterCompatibleStandardWallet,
|
|
6
|
+
WalletReadyState
|
|
7
|
+
} from '@solana/wallet-adapter-base'
|
|
5
8
|
import { Connection, Transaction, VersionedTransaction } from '@solana/web3.js'
|
|
6
9
|
import { StandardWalletAdapter } from '@solana/wallet-standard-wallet-adapter-base'
|
|
10
|
+
import { BaseWalletAdapter } from './BaseWalletAdapter'
|
|
7
11
|
|
|
8
12
|
export interface EthereumProvider {
|
|
9
13
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -73,6 +77,15 @@ export interface TronWalletInfo {
|
|
|
73
77
|
provider: any
|
|
74
78
|
}
|
|
75
79
|
|
|
80
|
+
export interface TonWalletInfo {
|
|
81
|
+
uuid: string
|
|
82
|
+
name: string
|
|
83
|
+
icon: string
|
|
84
|
+
jsBridgeKey: string
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
86
|
+
provider: any
|
|
87
|
+
}
|
|
88
|
+
|
|
76
89
|
export interface ParentAPI {
|
|
77
90
|
eip6963Wallets: DetectedWallet[]
|
|
78
91
|
eip6963WalletsReady: boolean
|
|
@@ -83,7 +96,11 @@ export interface ParentAPI {
|
|
|
83
96
|
tronWallets: TronWalletInfo[]
|
|
84
97
|
tronWalletsReady: boolean
|
|
85
98
|
|
|
99
|
+
tonWallets: TonWalletInfo[]
|
|
100
|
+
tonWalletsReady: boolean
|
|
101
|
+
|
|
86
102
|
discoverTronWallets: (injectedIds: string[]) => void
|
|
103
|
+
discoverTonWallets: (jsBridgeKeys: string[]) => void
|
|
87
104
|
}
|
|
88
105
|
|
|
89
106
|
export class BridgeParent {
|
|
@@ -118,12 +135,23 @@ export class BridgeParent {
|
|
|
118
135
|
tronWallets: [],
|
|
119
136
|
tronWalletsReady: false,
|
|
120
137
|
|
|
138
|
+
tonWallets: [],
|
|
139
|
+
tonWalletsReady: false,
|
|
140
|
+
|
|
121
141
|
// Called by BridgeChild to trigger Tron wallet discovery with injectedIds
|
|
122
142
|
discoverTronWallets: (injectedIds: string[]) => {
|
|
123
143
|
if (this.parentAPI) {
|
|
124
144
|
this.parentAPI.tronWallets = this.getTronWallets(injectedIds)
|
|
125
145
|
this.parentAPI.tronWalletsReady = true
|
|
126
146
|
}
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
// Called by BridgeChild to trigger TON wallet discovery with jsBridgeKeys
|
|
150
|
+
discoverTonWallets: (jsBridgeKeys: string[]) => {
|
|
151
|
+
if (this.parentAPI) {
|
|
152
|
+
this.parentAPI.tonWallets = this.getTonWallets(jsBridgeKeys)
|
|
153
|
+
this.parentAPI.tonWalletsReady = true
|
|
154
|
+
}
|
|
127
155
|
}
|
|
128
156
|
}
|
|
129
157
|
|
|
@@ -375,6 +403,170 @@ export class BridgeParent {
|
|
|
375
403
|
walletNames.add(wallet.name)
|
|
376
404
|
}
|
|
377
405
|
}
|
|
406
|
+
|
|
407
|
+
// Add Base Wallet via traditional adapter (detects window.coinbaseSolana)
|
|
408
|
+
try {
|
|
409
|
+
const baseAdapter = new BaseWalletAdapter()
|
|
410
|
+
const isDetected =
|
|
411
|
+
baseAdapter.readyState === WalletReadyState.Installed ||
|
|
412
|
+
baseAdapter.readyState === WalletReadyState.Loadable
|
|
413
|
+
|
|
414
|
+
if (isDetected && !walletNames.has(baseAdapter.name)) {
|
|
415
|
+
solanaWallets.push({
|
|
416
|
+
uuid: `${baseAdapter.name}-traditional`
|
|
417
|
+
.toLowerCase()
|
|
418
|
+
.replace(/\s+/g, '-'),
|
|
419
|
+
name: baseAdapter.name,
|
|
420
|
+
chains: ['solana:mainnet'],
|
|
421
|
+
features: ['traditional-adapter'],
|
|
422
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
423
|
+
// @ts-ignore
|
|
424
|
+
adapter: {
|
|
425
|
+
name: baseAdapter.name,
|
|
426
|
+
url: baseAdapter.url,
|
|
427
|
+
// @ts-expect-error icon is string but type expects template literal
|
|
428
|
+
icon: baseAdapter.icon,
|
|
429
|
+
readyState: baseAdapter.readyState,
|
|
430
|
+
// @ts-expect-error publicKey is a Comlink proxy, not a real PublicKey
|
|
431
|
+
publicKey: Comlink.proxy({
|
|
432
|
+
get value() {
|
|
433
|
+
return baseAdapter.publicKey
|
|
434
|
+
},
|
|
435
|
+
toBase58: async () => {
|
|
436
|
+
return baseAdapter.publicKey?.toBase58()
|
|
437
|
+
},
|
|
438
|
+
toJSON: async () => {
|
|
439
|
+
return baseAdapter.publicKey?.toJSON()
|
|
440
|
+
},
|
|
441
|
+
toBytes: async () => {
|
|
442
|
+
return baseAdapter.publicKey?.toBytes()
|
|
443
|
+
},
|
|
444
|
+
toBuffer: async () => {
|
|
445
|
+
return baseAdapter.publicKey?.toBuffer()
|
|
446
|
+
},
|
|
447
|
+
toString: async () => {
|
|
448
|
+
return baseAdapter.publicKey?.toString()
|
|
449
|
+
}
|
|
450
|
+
}),
|
|
451
|
+
connecting: baseAdapter.connecting,
|
|
452
|
+
connected: baseAdapter.connected,
|
|
453
|
+
supportedTransactionVersions:
|
|
454
|
+
baseAdapter.supportedTransactionVersions,
|
|
455
|
+
connect: async () => await baseAdapter.connect(),
|
|
456
|
+
disconnect: async () => await baseAdapter.disconnect(),
|
|
457
|
+
sendTransaction: async (transaction, connection, options) => {
|
|
458
|
+
try {
|
|
459
|
+
return await baseAdapter.sendTransaction(
|
|
460
|
+
transaction,
|
|
461
|
+
connection,
|
|
462
|
+
options
|
|
463
|
+
)
|
|
464
|
+
} catch {
|
|
465
|
+
throw new Error('Failed to send transaction')
|
|
466
|
+
}
|
|
467
|
+
},
|
|
468
|
+
signTransaction: async transaction => {
|
|
469
|
+
return await baseAdapter.signTransaction(transaction)
|
|
470
|
+
},
|
|
471
|
+
signAllTransactions: async transactions => {
|
|
472
|
+
return await baseAdapter.signAllTransactions(transactions)
|
|
473
|
+
},
|
|
474
|
+
signMessage: async message => {
|
|
475
|
+
return await baseAdapter.signMessage(message)
|
|
476
|
+
},
|
|
477
|
+
customFunctions: [
|
|
478
|
+
'sendSerializedTransaction',
|
|
479
|
+
'signAllSerializedTransactions',
|
|
480
|
+
'signSerializedTransaction'
|
|
481
|
+
],
|
|
482
|
+
sendSerializedTransaction: async (
|
|
483
|
+
transaction: ArrayBufferLike,
|
|
484
|
+
rpcUrl: string
|
|
485
|
+
) => {
|
|
486
|
+
const connection = new Connection(rpcUrl)
|
|
487
|
+
const uint8Array = new Uint8Array(transaction)
|
|
488
|
+
|
|
489
|
+
let deserializedTx: Transaction | VersionedTransaction
|
|
490
|
+
try {
|
|
491
|
+
deserializedTx = VersionedTransaction.deserialize(uint8Array)
|
|
492
|
+
} catch {
|
|
493
|
+
try {
|
|
494
|
+
deserializedTx = Transaction.from(uint8Array)
|
|
495
|
+
} catch {
|
|
496
|
+
throw new Error(
|
|
497
|
+
'Failed to deserialize transaction as either versioned or legacy format'
|
|
498
|
+
)
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
try {
|
|
502
|
+
const txHash = await baseAdapter.sendTransaction(
|
|
503
|
+
deserializedTx,
|
|
504
|
+
connection
|
|
505
|
+
)
|
|
506
|
+
return txHash
|
|
507
|
+
} catch {
|
|
508
|
+
throw new Error('Failed to send serialized transaction')
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
// @ts-expect-error return type includes VersionedTransaction
|
|
512
|
+
signSerializedTransaction: async (transaction: ArrayBufferLike) => {
|
|
513
|
+
const uint8Array = new Uint8Array(transaction)
|
|
514
|
+
|
|
515
|
+
let deserializedTx: Transaction | VersionedTransaction
|
|
516
|
+
try {
|
|
517
|
+
deserializedTx = VersionedTransaction.deserialize(uint8Array)
|
|
518
|
+
} catch {
|
|
519
|
+
try {
|
|
520
|
+
deserializedTx = Transaction.from(uint8Array)
|
|
521
|
+
} catch {
|
|
522
|
+
throw new Error(
|
|
523
|
+
'Failed to deserialize transaction as either versioned or legacy format'
|
|
524
|
+
)
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return await baseAdapter.signTransaction(deserializedTx)
|
|
529
|
+
},
|
|
530
|
+
// @ts-expect-error return type includes VersionedTransaction
|
|
531
|
+
signAllSerializedTransactions: async (
|
|
532
|
+
transactions: ArrayBufferLike[]
|
|
533
|
+
) => {
|
|
534
|
+
const deserializedTransactions: (
|
|
535
|
+
| Transaction
|
|
536
|
+
| VersionedTransaction
|
|
537
|
+
)[] = []
|
|
538
|
+
|
|
539
|
+
for (const transaction of transactions) {
|
|
540
|
+
const uint8Array = new Uint8Array(transaction)
|
|
541
|
+
|
|
542
|
+
let deserializedTx: Transaction | VersionedTransaction
|
|
543
|
+
try {
|
|
544
|
+
deserializedTx = VersionedTransaction.deserialize(uint8Array)
|
|
545
|
+
} catch {
|
|
546
|
+
try {
|
|
547
|
+
deserializedTx = Transaction.from(uint8Array)
|
|
548
|
+
} catch {
|
|
549
|
+
throw new Error(
|
|
550
|
+
'Failed to deserialize one or more transactions'
|
|
551
|
+
)
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
deserializedTransactions.push(deserializedTx)
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return await baseAdapter.signAllTransactions(
|
|
559
|
+
deserializedTransactions
|
|
560
|
+
)
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
})
|
|
564
|
+
walletNames.add(baseAdapter.name)
|
|
565
|
+
}
|
|
566
|
+
} catch {
|
|
567
|
+
// Silently handle if Base Wallet adapter fails to initialize
|
|
568
|
+
}
|
|
569
|
+
|
|
378
570
|
return solanaWallets
|
|
379
571
|
}
|
|
380
572
|
|
|
@@ -485,11 +677,67 @@ export class BridgeParent {
|
|
|
485
677
|
return wallets
|
|
486
678
|
}
|
|
487
679
|
|
|
680
|
+
private isTonConnectBridge(value: unknown): boolean {
|
|
681
|
+
if (!value || typeof value !== 'object') return false
|
|
682
|
+
const bridge = value as Record<string, unknown>
|
|
683
|
+
return (
|
|
684
|
+
typeof bridge['connect'] === 'function' &&
|
|
685
|
+
typeof bridge['send'] === 'function' &&
|
|
686
|
+
typeof bridge['listen'] === 'function'
|
|
687
|
+
)
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
private getTonWallets(jsBridgeKeys: string[]): TonWalletInfo[] {
|
|
691
|
+
if (typeof window === 'undefined' || jsBridgeKeys.length === 0) {
|
|
692
|
+
return []
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
const wallets: TonWalletInfo[] = []
|
|
696
|
+
const seen = new Set<string>()
|
|
697
|
+
|
|
698
|
+
for (const key of jsBridgeKeys) {
|
|
699
|
+
if (seen.has(key)) continue
|
|
700
|
+
|
|
701
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
702
|
+
const root = (window as any)[key]
|
|
703
|
+
if (!root || typeof root !== 'object') continue
|
|
704
|
+
|
|
705
|
+
const bridge = root['tonconnect']
|
|
706
|
+
if (!this.isTonConnectBridge(bridge)) continue
|
|
707
|
+
|
|
708
|
+
seen.add(key)
|
|
709
|
+
|
|
710
|
+
// Explicitly whitelist bridge methods to bound cross-origin surface
|
|
711
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
712
|
+
const actualBridge = bridge as any
|
|
713
|
+
wallets.push({
|
|
714
|
+
uuid: `ton-${key}`.toLowerCase(),
|
|
715
|
+
name: actualBridge.deviceInfo?.appName || key,
|
|
716
|
+
icon: '',
|
|
717
|
+
jsBridgeKey: key,
|
|
718
|
+
provider: Comlink.proxy({
|
|
719
|
+
deviceInfo: actualBridge.deviceInfo,
|
|
720
|
+
connect: async (protocolVersion: number, message: string) =>
|
|
721
|
+
await actualBridge.connect(protocolVersion, message),
|
|
722
|
+
send: async (message: string) => await actualBridge.send(message),
|
|
723
|
+
listen: (callback: (event: string) => void) =>
|
|
724
|
+
actualBridge.listen(callback),
|
|
725
|
+
disconnect: actualBridge.disconnect
|
|
726
|
+
? async () => await actualBridge.disconnect()
|
|
727
|
+
: undefined
|
|
728
|
+
})
|
|
729
|
+
})
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
return wallets
|
|
733
|
+
}
|
|
734
|
+
|
|
488
735
|
public destroy(): void {
|
|
489
736
|
if (this.parentAPI) {
|
|
490
737
|
this.parentAPI.eip6963Wallets = []
|
|
491
738
|
this.parentAPI.walletStandardWallets = []
|
|
492
739
|
this.parentAPI.tronWallets = []
|
|
740
|
+
this.parentAPI.tonWallets = []
|
|
493
741
|
this.parentAPI = null
|
|
494
742
|
}
|
|
495
743
|
this.endpoint = null
|