@meshconnect/uwc-bridge-parent 1.0.1 → 1.1.0
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/BridgeParent.d.ts +11 -6
- package/dist/BridgeParent.d.ts.map +1 -1
- package/dist/BridgeParent.js +75 -12
- package/dist/BridgeParent.js.map +1 -1
- package/dist/BridgeParent.test.d.ts +2 -0
- package/dist/BridgeParent.test.d.ts.map +1 -0
- package/dist/BridgeParent.test.js +314 -0
- package/dist/BridgeParent.test.js.map +1 -0
- package/package.json +2 -2
- package/src/BridgeParent.test.ts +408 -0
- package/src/BridgeParent.ts +126 -19
- package/dist/bridge-parent.d.ts +0 -27
- package/dist/bridge-parent.d.ts.map +0 -1
- package/dist/bridge-parent.js +0 -148
- package/dist/bridge-parent.js.map +0 -1
- package/dist/comlink-bridge.d.ts +0 -26
- package/dist/comlink-bridge.d.ts.map +0 -1
- package/dist/comlink-bridge.js +0 -126
- package/dist/comlink-bridge.js.map +0 -1
- package/dist/postmate-bridge.d.ts +0 -37
- package/dist/postmate-bridge.d.ts.map +0 -1
- package/dist/postmate-bridge.js +0 -631
- package/dist/postmate-bridge.js.map +0 -1
- package/dist/standard-wallet-adapter.d.ts +0 -17
- package/dist/standard-wallet-adapter.d.ts.map +0 -1
- package/dist/standard-wallet-adapter.js +0 -53
- package/dist/standard-wallet-adapter.js.map +0 -1
- package/dist/types.d.ts +0 -30
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/wallet-bridge-parent.d.ts +0 -41
- package/dist/wallet-bridge-parent.d.ts.map +0 -1
- package/dist/wallet-bridge-parent.js +0 -224
- package/dist/wallet-bridge-parent.js.map +0 -1
- package/dist/wallet-bridge.d.ts +0 -38
- package/dist/wallet-bridge.d.ts.map +0 -1
- package/dist/wallet-bridge.js +0 -71
- package/dist/wallet-bridge.js.map +0 -1
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
// Mock Comlink
|
|
4
|
+
vi.mock('comlink', () => ({
|
|
5
|
+
expose: vi.fn(),
|
|
6
|
+
windowEndpoint: vi.fn().mockReturnValue({}),
|
|
7
|
+
proxy: vi.fn((obj: unknown) => obj)
|
|
8
|
+
}))
|
|
9
|
+
|
|
10
|
+
// Mock @wallet-standard/app
|
|
11
|
+
vi.mock('@wallet-standard/app', () => ({
|
|
12
|
+
getWallets: vi.fn().mockReturnValue({ get: () => [] })
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
// Mock @solana/wallet-adapter-base
|
|
16
|
+
vi.mock('@solana/wallet-adapter-base', () => ({
|
|
17
|
+
isWalletAdapterCompatibleStandardWallet: vi.fn().mockReturnValue(false)
|
|
18
|
+
}))
|
|
19
|
+
|
|
20
|
+
// Mock @solana/wallet-standard-wallet-adapter-base
|
|
21
|
+
vi.mock('@solana/wallet-standard-wallet-adapter-base', () => ({
|
|
22
|
+
StandardWalletAdapter: vi.fn()
|
|
23
|
+
}))
|
|
24
|
+
|
|
25
|
+
// Mock @solana/web3.js
|
|
26
|
+
vi.mock('@solana/web3.js', () => ({
|
|
27
|
+
Connection: vi.fn(),
|
|
28
|
+
Transaction: { from: vi.fn() },
|
|
29
|
+
VersionedTransaction: { deserialize: vi.fn() }
|
|
30
|
+
}))
|
|
31
|
+
|
|
32
|
+
describe('BridgeParent', () => {
|
|
33
|
+
let mockIframe: HTMLIFrameElement
|
|
34
|
+
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
vi.clearAllMocks()
|
|
37
|
+
vi.useFakeTimers()
|
|
38
|
+
|
|
39
|
+
mockIframe = {
|
|
40
|
+
contentWindow: {},
|
|
41
|
+
src: 'https://child.example.com/page'
|
|
42
|
+
} as any
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
vi.useRealTimers()
|
|
47
|
+
vi.restoreAllMocks()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('constructor', () => {
|
|
51
|
+
it('should throw if no iframe provided', async () => {
|
|
52
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
53
|
+
|
|
54
|
+
expect(() => new BridgeParent(null as any)).toThrow(
|
|
55
|
+
'BridgeParent requires an iframe element'
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('should accept a valid iframe', async () => {
|
|
60
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
61
|
+
|
|
62
|
+
const bridge = new BridgeParent(mockIframe)
|
|
63
|
+
|
|
64
|
+
expect(bridge).toBeDefined()
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('should call Comlink.expose after initialization', async () => {
|
|
68
|
+
const Comlink = await import('comlink')
|
|
69
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
70
|
+
|
|
71
|
+
new BridgeParent(mockIframe)
|
|
72
|
+
|
|
73
|
+
// Allow the async initializeConnection to run
|
|
74
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
75
|
+
|
|
76
|
+
expect(Comlink.expose).toHaveBeenCalled()
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('should call Comlink.windowEndpoint with iframe contentWindow', async () => {
|
|
80
|
+
const Comlink = await import('comlink')
|
|
81
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
82
|
+
|
|
83
|
+
new BridgeParent(mockIframe)
|
|
84
|
+
|
|
85
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
86
|
+
|
|
87
|
+
expect(Comlink.windowEndpoint).toHaveBeenCalledWith(
|
|
88
|
+
mockIframe.contentWindow,
|
|
89
|
+
window,
|
|
90
|
+
'https://child.example.com'
|
|
91
|
+
)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('should not initialize if iframe has no contentWindow', async () => {
|
|
95
|
+
const Comlink = await import('comlink')
|
|
96
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
97
|
+
|
|
98
|
+
const iframeNoContent = { src: 'https://example.com' } as any
|
|
99
|
+
new BridgeParent(iframeNoContent)
|
|
100
|
+
|
|
101
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
102
|
+
|
|
103
|
+
expect(Comlink.expose).not.toHaveBeenCalled()
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
describe('EIP6963 wallet discovery', () => {
|
|
108
|
+
it('should dispatch eip6963:requestProvider event', async () => {
|
|
109
|
+
const dispatchSpy = vi.spyOn(window, 'dispatchEvent')
|
|
110
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
111
|
+
|
|
112
|
+
new BridgeParent(mockIframe)
|
|
113
|
+
|
|
114
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
115
|
+
|
|
116
|
+
expect(dispatchSpy).toHaveBeenCalledWith(
|
|
117
|
+
expect.objectContaining({ type: 'eip6963:requestProvider' })
|
|
118
|
+
)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('should collect announced wallets', async () => {
|
|
122
|
+
const Comlink = await import('comlink')
|
|
123
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
124
|
+
|
|
125
|
+
// Set up a listener that announces a wallet when requestProvider fires
|
|
126
|
+
const mockProvider = { request: vi.fn() }
|
|
127
|
+
window.addEventListener('eip6963:requestProvider', () => {
|
|
128
|
+
window.dispatchEvent(
|
|
129
|
+
new CustomEvent('eip6963:announceProvider', {
|
|
130
|
+
detail: {
|
|
131
|
+
info: {
|
|
132
|
+
uuid: 'wallet-1',
|
|
133
|
+
name: 'TestWallet',
|
|
134
|
+
icon: 'test-icon',
|
|
135
|
+
rdns: 'com.test.wallet'
|
|
136
|
+
},
|
|
137
|
+
provider: mockProvider
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
new BridgeParent(mockIframe)
|
|
144
|
+
|
|
145
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
146
|
+
|
|
147
|
+
// The exposed parentAPI should contain the discovered wallet
|
|
148
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
149
|
+
expect(exposedAPI).toBeDefined()
|
|
150
|
+
expect(exposedAPI.eip6963Wallets).toHaveLength(1)
|
|
151
|
+
expect(exposedAPI.eip6963Wallets[0].uuid).toBe('wallet-1')
|
|
152
|
+
expect(exposedAPI.eip6963Wallets[0].name).toBe('TestWallet')
|
|
153
|
+
expect(exposedAPI.eip6963WalletsReady).toBe(true)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('should deduplicate wallets by uuid', async () => {
|
|
157
|
+
const Comlink = await import('comlink')
|
|
158
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
159
|
+
|
|
160
|
+
const mockProvider = { request: vi.fn() }
|
|
161
|
+
window.addEventListener('eip6963:requestProvider', () => {
|
|
162
|
+
// Announce same wallet twice
|
|
163
|
+
const event = new CustomEvent('eip6963:announceProvider', {
|
|
164
|
+
detail: {
|
|
165
|
+
info: {
|
|
166
|
+
uuid: 'wallet-1',
|
|
167
|
+
name: 'TestWallet',
|
|
168
|
+
icon: 'icon',
|
|
169
|
+
rdns: 'com.test'
|
|
170
|
+
},
|
|
171
|
+
provider: mockProvider
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
window.dispatchEvent(event)
|
|
175
|
+
window.dispatchEvent(event)
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
new BridgeParent(mockIframe)
|
|
179
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
180
|
+
|
|
181
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
182
|
+
expect(exposedAPI.eip6963Wallets).toHaveLength(1)
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
describe('Solana wallet discovery', () => {
|
|
187
|
+
it('should call getWallets and filter Solana wallets', async () => {
|
|
188
|
+
const { getWallets } = await import('@wallet-standard/app')
|
|
189
|
+
const Comlink = await import('comlink')
|
|
190
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
191
|
+
|
|
192
|
+
const mockSolanaWallet = {
|
|
193
|
+
name: 'Phantom',
|
|
194
|
+
chains: ['solana:mainnet'],
|
|
195
|
+
features: { 'standard:connect': {} },
|
|
196
|
+
accounts: []
|
|
197
|
+
}
|
|
198
|
+
const mockNonSolanaWallet = {
|
|
199
|
+
name: 'SomeWallet',
|
|
200
|
+
chains: ['ethereum:1'],
|
|
201
|
+
features: {},
|
|
202
|
+
accounts: []
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
vi.mocked(getWallets).mockReturnValue({
|
|
206
|
+
get: () => [mockSolanaWallet, mockNonSolanaWallet] as any,
|
|
207
|
+
on: vi.fn(),
|
|
208
|
+
register: vi.fn()
|
|
209
|
+
} as any)
|
|
210
|
+
|
|
211
|
+
new BridgeParent(mockIframe)
|
|
212
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
213
|
+
|
|
214
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
215
|
+
expect(exposedAPI.walletStandardWallets).toHaveLength(1)
|
|
216
|
+
expect(exposedAPI.walletStandardWallets[0].name).toBe('Phantom')
|
|
217
|
+
expect(exposedAPI.walletStandardWalletsReady).toBe(true)
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
it('should return empty array when no Solana wallets found', async () => {
|
|
221
|
+
const { getWallets } = await import('@wallet-standard/app')
|
|
222
|
+
const Comlink = await import('comlink')
|
|
223
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
224
|
+
|
|
225
|
+
vi.mocked(getWallets).mockReturnValue({
|
|
226
|
+
get: () => [],
|
|
227
|
+
on: vi.fn(),
|
|
228
|
+
register: vi.fn()
|
|
229
|
+
} as any)
|
|
230
|
+
|
|
231
|
+
new BridgeParent(mockIframe)
|
|
232
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
233
|
+
|
|
234
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
235
|
+
expect(exposedAPI.walletStandardWallets).toEqual([])
|
|
236
|
+
})
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
describe('Tron wallet discovery', () => {
|
|
240
|
+
it('should start with empty tron wallets and not ready', async () => {
|
|
241
|
+
const Comlink = await import('comlink')
|
|
242
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
243
|
+
|
|
244
|
+
new BridgeParent(mockIframe)
|
|
245
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
246
|
+
|
|
247
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
248
|
+
expect(exposedAPI.tronWallets).toEqual([])
|
|
249
|
+
expect(exposedAPI.tronWalletsReady).toBe(false)
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
it('should discover tron wallets when discoverTronWallets is called', async () => {
|
|
253
|
+
const Comlink = await import('comlink')
|
|
254
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
255
|
+
|
|
256
|
+
// Set up a tron provider on window
|
|
257
|
+
;(window as any).tronLink = {
|
|
258
|
+
ready: true,
|
|
259
|
+
request: vi.fn(),
|
|
260
|
+
tronWeb: {
|
|
261
|
+
defaultAddress: { base58: 'TAddr1', hex: '0x1' },
|
|
262
|
+
trx: {
|
|
263
|
+
sign: vi.fn(),
|
|
264
|
+
signMessageV2: vi.fn(),
|
|
265
|
+
sendRawTransaction: vi.fn()
|
|
266
|
+
},
|
|
267
|
+
transactionBuilder: {
|
|
268
|
+
sendTrx: vi.fn(),
|
|
269
|
+
triggerSmartContract: vi.fn()
|
|
270
|
+
},
|
|
271
|
+
toHex: vi.fn()
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
new BridgeParent(mockIframe)
|
|
276
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
277
|
+
|
|
278
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
279
|
+
|
|
280
|
+
// Simulate child calling discoverTronWallets
|
|
281
|
+
exposedAPI.discoverTronWallets(['tronLink'])
|
|
282
|
+
|
|
283
|
+
expect(exposedAPI.tronWalletsReady).toBe(true)
|
|
284
|
+
expect(exposedAPI.tronWallets).toHaveLength(1)
|
|
285
|
+
expect(exposedAPI.tronWallets[0].uuid).toBe('tron-tronlink')
|
|
286
|
+
expect(exposedAPI.tronWallets[0].name).toBe('tronLink')
|
|
287
|
+
expect(exposedAPI.tronWallets[0].injectedId).toBe('tronLink')
|
|
288
|
+
|
|
289
|
+
// Cleanup
|
|
290
|
+
delete (window as any).tronLink
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
it('should handle nested tron provider paths', async () => {
|
|
294
|
+
const Comlink = await import('comlink')
|
|
295
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
296
|
+
|
|
297
|
+
;(window as any).tokenpocket = {
|
|
298
|
+
tron: {
|
|
299
|
+
ready: true,
|
|
300
|
+
tronWeb: {
|
|
301
|
+
defaultAddress: { base58: 'TAddr2' },
|
|
302
|
+
trx: {
|
|
303
|
+
sign: vi.fn(),
|
|
304
|
+
signMessageV2: vi.fn(),
|
|
305
|
+
sendRawTransaction: vi.fn()
|
|
306
|
+
},
|
|
307
|
+
transactionBuilder: {
|
|
308
|
+
sendTrx: vi.fn(),
|
|
309
|
+
triggerSmartContract: vi.fn()
|
|
310
|
+
},
|
|
311
|
+
toHex: vi.fn()
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
new BridgeParent(mockIframe)
|
|
317
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
318
|
+
|
|
319
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
320
|
+
exposedAPI.discoverTronWallets(['tokenpocket.tron'])
|
|
321
|
+
|
|
322
|
+
expect(exposedAPI.tronWallets).toHaveLength(1)
|
|
323
|
+
expect(exposedAPI.tronWallets[0].uuid).toBe('tron-tokenpocket-tron')
|
|
324
|
+
|
|
325
|
+
delete (window as any).tokenpocket
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
it('should return empty when injectedIds is empty', async () => {
|
|
329
|
+
const Comlink = await import('comlink')
|
|
330
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
331
|
+
|
|
332
|
+
new BridgeParent(mockIframe)
|
|
333
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
334
|
+
|
|
335
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
336
|
+
exposedAPI.discoverTronWallets([])
|
|
337
|
+
|
|
338
|
+
expect(exposedAPI.tronWallets).toEqual([])
|
|
339
|
+
expect(exposedAPI.tronWalletsReady).toBe(true)
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
it('should skip providers without valid tronWeb.trx', async () => {
|
|
343
|
+
const Comlink = await import('comlink')
|
|
344
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
345
|
+
|
|
346
|
+
;(window as any).badWallet = {
|
|
347
|
+
ready: true,
|
|
348
|
+
tronWeb: { notTrx: true }
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
new BridgeParent(mockIframe)
|
|
352
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
353
|
+
|
|
354
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
355
|
+
exposedAPI.discoverTronWallets(['badWallet'])
|
|
356
|
+
|
|
357
|
+
expect(exposedAPI.tronWallets).toEqual([])
|
|
358
|
+
|
|
359
|
+
delete (window as any).badWallet
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
it('should deduplicate tron wallets by injectedId', async () => {
|
|
363
|
+
const Comlink = await import('comlink')
|
|
364
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
365
|
+
|
|
366
|
+
;(window as any).tronLink = {
|
|
367
|
+
ready: true,
|
|
368
|
+
tronWeb: {
|
|
369
|
+
defaultAddress: { base58: 'TAddr1' },
|
|
370
|
+
trx: {
|
|
371
|
+
sign: vi.fn(),
|
|
372
|
+
signMessageV2: vi.fn(),
|
|
373
|
+
sendRawTransaction: vi.fn()
|
|
374
|
+
},
|
|
375
|
+
transactionBuilder: {
|
|
376
|
+
sendTrx: vi.fn(),
|
|
377
|
+
triggerSmartContract: vi.fn()
|
|
378
|
+
},
|
|
379
|
+
toHex: vi.fn()
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
new BridgeParent(mockIframe)
|
|
384
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
385
|
+
|
|
386
|
+
const exposedAPI = vi.mocked(Comlink.expose).mock.calls[0]?.[0] as any
|
|
387
|
+
exposedAPI.discoverTronWallets(['tronLink', 'tronLink'])
|
|
388
|
+
|
|
389
|
+
expect(exposedAPI.tronWallets).toHaveLength(1)
|
|
390
|
+
|
|
391
|
+
delete (window as any).tronLink
|
|
392
|
+
})
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
describe('destroy', () => {
|
|
396
|
+
it('should clear all state', async () => {
|
|
397
|
+
const { BridgeParent } = await import('./BridgeParent')
|
|
398
|
+
|
|
399
|
+
const bridge = new BridgeParent(mockIframe)
|
|
400
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
401
|
+
|
|
402
|
+
bridge.destroy()
|
|
403
|
+
|
|
404
|
+
// After destroy, creating another should work without errors
|
|
405
|
+
expect(() => bridge.destroy()).not.toThrow()
|
|
406
|
+
})
|
|
407
|
+
})
|
|
408
|
+
})
|
package/src/BridgeParent.ts
CHANGED
|
@@ -57,10 +57,6 @@ export interface EIP6963AnnounceProviderEvent extends CustomEvent {
|
|
|
57
57
|
detail: EIP6963ProviderDetail
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export interface EIP6963RequestProviderEvent extends Event {
|
|
61
|
-
type: 'eip6963:requestProvider'
|
|
62
|
-
}
|
|
63
|
-
|
|
64
60
|
export interface DetectedWallet {
|
|
65
61
|
uuid: string
|
|
66
62
|
name: string
|
|
@@ -69,16 +65,29 @@ export interface DetectedWallet {
|
|
|
69
65
|
provider: EthereumProvider
|
|
70
66
|
}
|
|
71
67
|
|
|
68
|
+
export interface TronWalletInfo {
|
|
69
|
+
uuid: string
|
|
70
|
+
name: string
|
|
71
|
+
injectedId: string
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
+
provider: any
|
|
74
|
+
}
|
|
75
|
+
|
|
72
76
|
export interface ParentAPI {
|
|
73
77
|
eip6963Wallets: DetectedWallet[]
|
|
74
78
|
eip6963WalletsReady: boolean
|
|
79
|
+
|
|
75
80
|
walletStandardWallets: WalletStandardInfo[]
|
|
76
81
|
walletStandardWalletsReady: boolean
|
|
82
|
+
|
|
83
|
+
tronWallets: TronWalletInfo[]
|
|
84
|
+
tronWalletsReady: boolean
|
|
85
|
+
|
|
86
|
+
discoverTronWallets: (injectedIds: string[]) => void
|
|
77
87
|
}
|
|
78
88
|
|
|
79
89
|
export class BridgeParent {
|
|
80
90
|
private iframe: HTMLIFrameElement | null
|
|
81
|
-
private handshakeComplete = false
|
|
82
91
|
private parentAPI: ParentAPI | null = null
|
|
83
92
|
private endpoint: Comlink.Endpoint | null = null
|
|
84
93
|
|
|
@@ -97,35 +106,43 @@ export class BridgeParent {
|
|
|
97
106
|
return
|
|
98
107
|
}
|
|
99
108
|
|
|
100
|
-
|
|
109
|
+
// For eip6963 and solana wallets we can start discovery as soon as the iframe loads, but for tron we need to look for specific IDs that we get from the child iframe
|
|
110
|
+
const eip6963Wallets = await this.discovereip6963Wallets()
|
|
101
111
|
const walletStandardWallets = this.getSolanaWallets()
|
|
112
|
+
|
|
102
113
|
this.parentAPI = {
|
|
103
114
|
eip6963Wallets: eip6963Wallets,
|
|
104
115
|
eip6963WalletsReady: true,
|
|
105
116
|
walletStandardWallets: walletStandardWallets,
|
|
106
|
-
walletStandardWalletsReady: true
|
|
117
|
+
walletStandardWalletsReady: true,
|
|
118
|
+
tronWallets: [],
|
|
119
|
+
tronWalletsReady: false,
|
|
120
|
+
|
|
121
|
+
// Called by BridgeChild to trigger Tron wallet discovery with injectedIds
|
|
122
|
+
discoverTronWallets: (injectedIds: string[]) => {
|
|
123
|
+
if (this.parentAPI) {
|
|
124
|
+
this.parentAPI.tronWallets = this.getTronWallets(injectedIds)
|
|
125
|
+
this.parentAPI.tronWalletsReady = true
|
|
126
|
+
}
|
|
127
|
+
}
|
|
107
128
|
}
|
|
108
129
|
|
|
109
130
|
// Use Comlink's windowEndpoint with proper cross-origin support
|
|
110
131
|
// For cross-origin, we need to listen on the parent window, not access the iframe's window
|
|
132
|
+
const iframeOrigin = new URL(this.iframe.src, window.location.href).origin
|
|
111
133
|
this.endpoint = Comlink.windowEndpoint(
|
|
112
134
|
this.iframe.contentWindow,
|
|
113
135
|
window,
|
|
114
|
-
|
|
136
|
+
iframeOrigin
|
|
115
137
|
)
|
|
116
|
-
Comlink.expose(this.parentAPI, this.endpoint)
|
|
117
138
|
|
|
118
|
-
this.
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
isConnected(): boolean {
|
|
122
|
-
return this.handshakeComplete
|
|
139
|
+
Comlink.expose(this.parentAPI, this.endpoint)
|
|
123
140
|
}
|
|
124
141
|
|
|
125
|
-
private async
|
|
142
|
+
private async discovereip6963Wallets(): Promise<DetectedWallet[]> {
|
|
126
143
|
return new Promise(resolve => {
|
|
127
144
|
const detectedWallets: DetectedWallet[] = []
|
|
128
|
-
const timeout =
|
|
145
|
+
const timeout = 100 // Wait 100ms for wallets to announce
|
|
129
146
|
|
|
130
147
|
// Set up listener for wallet announcements
|
|
131
148
|
const handleAnnouncement = (event: Event) => {
|
|
@@ -143,7 +160,7 @@ export class BridgeParent {
|
|
|
143
160
|
name: info.name,
|
|
144
161
|
icon: info.icon,
|
|
145
162
|
rdns: info.rdns,
|
|
146
|
-
provider
|
|
163
|
+
provider: provider
|
|
147
164
|
})
|
|
148
165
|
}
|
|
149
166
|
}
|
|
@@ -373,12 +390,102 @@ export class BridgeParent {
|
|
|
373
390
|
return `${wallet.name}-${chain}`.toLowerCase().replace(/\s+/g, '-')
|
|
374
391
|
}
|
|
375
392
|
|
|
376
|
-
|
|
377
|
-
|
|
393
|
+
private getTronWallets(injectedIds: string[]): TronWalletInfo[] {
|
|
394
|
+
if (typeof window === 'undefined' || injectedIds.length === 0) {
|
|
395
|
+
return []
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const wallets: TronWalletInfo[] = []
|
|
399
|
+
const seen = new Set<string>()
|
|
400
|
+
|
|
401
|
+
for (const injectedId of injectedIds) {
|
|
402
|
+
// Resolve nested window path (e.g. 'tokenpocket.tron' -> window.tokenpocket.tron)
|
|
403
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
404
|
+
const provider = injectedId.split('.').reduce<any>(
|
|
405
|
+
(acc, part) => acc?.[part],
|
|
406
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
407
|
+
window as any
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
// Check if it looks like a TronProvider (has tronWeb.trx)
|
|
411
|
+
if (
|
|
412
|
+
provider?.tronWeb &&
|
|
413
|
+
typeof provider.tronWeb.trx === 'object' &&
|
|
414
|
+
provider.tronWeb.trx !== null &&
|
|
415
|
+
!seen.has(injectedId)
|
|
416
|
+
) {
|
|
417
|
+
seen.add(injectedId)
|
|
418
|
+
|
|
419
|
+
const name = injectedId.split('.')[0] || injectedId
|
|
420
|
+
const uuid = `tron-${injectedId}`.toLowerCase().replace(/\./g, '-')
|
|
421
|
+
|
|
422
|
+
// Create proxied provider with all TronWeb methods
|
|
423
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
424
|
+
const actualProvider = provider as any
|
|
425
|
+
const proxiedProvider = Comlink.proxy({
|
|
426
|
+
ready: actualProvider.ready ?? false,
|
|
427
|
+
request: actualProvider.request
|
|
428
|
+
? async (params: { method: string; params?: unknown }) =>
|
|
429
|
+
await actualProvider.request(params)
|
|
430
|
+
: undefined,
|
|
431
|
+
tronWeb: Comlink.proxy({
|
|
432
|
+
getDefaultAddress: async () => ({
|
|
433
|
+
base58: actualProvider.tronWeb.defaultAddress?.base58 || false,
|
|
434
|
+
hex: actualProvider.tronWeb.defaultAddress?.hex || false
|
|
435
|
+
}),
|
|
436
|
+
trx: Comlink.proxy({
|
|
437
|
+
sign: async (transaction: unknown) =>
|
|
438
|
+
await actualProvider.tronWeb.trx.sign(transaction),
|
|
439
|
+
signMessageV2: async (message: string) =>
|
|
440
|
+
await actualProvider.tronWeb.trx.signMessageV2(message),
|
|
441
|
+
sendRawTransaction: async (signedTransaction: unknown) =>
|
|
442
|
+
await actualProvider.tronWeb.trx.sendRawTransaction(
|
|
443
|
+
signedTransaction
|
|
444
|
+
)
|
|
445
|
+
}),
|
|
446
|
+
transactionBuilder: Comlink.proxy({
|
|
447
|
+
sendTrx: async (to: string, amount: number, from: string) =>
|
|
448
|
+
await actualProvider.tronWeb.transactionBuilder.sendTrx(
|
|
449
|
+
to,
|
|
450
|
+
amount,
|
|
451
|
+
from
|
|
452
|
+
),
|
|
453
|
+
triggerSmartContract: async (
|
|
454
|
+
contractAddress: string,
|
|
455
|
+
functionSelector: string,
|
|
456
|
+
options: Record<string, unknown>,
|
|
457
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
458
|
+
parameter: Array<{ type: string; value: any }>,
|
|
459
|
+
issuerAddress: string
|
|
460
|
+
) =>
|
|
461
|
+
await actualProvider.tronWeb.transactionBuilder.triggerSmartContract(
|
|
462
|
+
contractAddress,
|
|
463
|
+
functionSelector,
|
|
464
|
+
options,
|
|
465
|
+
parameter,
|
|
466
|
+
issuerAddress
|
|
467
|
+
)
|
|
468
|
+
}),
|
|
469
|
+
toHex: (message: string) => actualProvider.tronWeb.toHex(message)
|
|
470
|
+
})
|
|
471
|
+
})
|
|
378
472
|
|
|
473
|
+
wallets.push({
|
|
474
|
+
uuid,
|
|
475
|
+
name,
|
|
476
|
+
injectedId,
|
|
477
|
+
provider: proxiedProvider
|
|
478
|
+
})
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return wallets
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
public destroy(): void {
|
|
379
485
|
if (this.parentAPI) {
|
|
380
486
|
this.parentAPI.eip6963Wallets = []
|
|
381
487
|
this.parentAPI.walletStandardWallets = []
|
|
488
|
+
this.parentAPI.tronWallets = []
|
|
382
489
|
this.parentAPI = null
|
|
383
490
|
}
|
|
384
491
|
this.endpoint = null
|
package/dist/bridge-parent.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { Wallet } from '@wallet-standard/base';
|
|
2
|
-
import type { DetectedEip6963Wallet, DetectedWalletStandardWallet, EIP6963AnnounceProviderEvent, EIP6963ProviderDetail } from './types';
|
|
3
|
-
import { StandardWalletAdapter } from './standard-wallet-adapter';
|
|
4
|
-
declare global {
|
|
5
|
-
interface WindowEventMap {
|
|
6
|
-
'eip6963:announceProvider': EIP6963AnnounceProviderEvent;
|
|
7
|
-
'eip6963:requestProvider': Event;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
export declare class BridgeParent {
|
|
11
|
-
private detectedEip6963Wallets;
|
|
12
|
-
private detectedWalletStandardWallets;
|
|
13
|
-
private walletStandardUnsubscribe?;
|
|
14
|
-
constructor();
|
|
15
|
-
private initialize;
|
|
16
|
-
private detectEIP6963Wallets;
|
|
17
|
-
private detectWalletStandardWallets;
|
|
18
|
-
private logAllWallets;
|
|
19
|
-
getDetectedEip6963Wallets(): Map<string, DetectedEip6963Wallet>;
|
|
20
|
-
getDetectedWalletStandardWallets(): Map<string, DetectedWalletStandardWallet>;
|
|
21
|
-
getEIP6963Providers(): Map<string, EIP6963ProviderDetail>;
|
|
22
|
-
getWalletStandardWallets(): Map<string, Wallet>;
|
|
23
|
-
getWalletStandardAdapters(): Map<string, StandardWalletAdapter>;
|
|
24
|
-
getWalletStandardAdapter(walletName: string): StandardWalletAdapter | undefined;
|
|
25
|
-
refreshDetection(): void;
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=bridge-parent.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bridge-parent.d.ts","sourceRoot":"","sources":["../src/bridge-parent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,KAAK,EACV,qBAAqB,EACrB,4BAA4B,EAC5B,4BAA4B,EAC5B,qBAAqB,EACtB,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAEjE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,cAAc;QACtB,0BAA0B,EAAE,4BAA4B,CAAA;QACxD,yBAAyB,EAAE,KAAK,CAAA;KACjC;CACF;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,sBAAsB,CAAgD;IAC9E,OAAO,CAAC,6BAA6B,CAGxB;IACb,OAAO,CAAC,yBAAyB,CAAC,CAAY;;IAM9C,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,oBAAoB;IA8B5B,OAAO,CAAC,2BAA2B;IA8DnC,OAAO,CAAC,aAAa;IAkCd,yBAAyB,IAAI,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAI/D,gCAAgC,IAAI,GAAG,CAC5C,MAAM,EACN,4BAA4B,CAC7B;IAKM,mBAAmB,IAAI,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAQzD,wBAAwB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAQ/C,yBAAyB,IAAI,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAQ/D,wBAAwB,CAC7B,UAAU,EAAE,MAAM,GACjB,qBAAqB,GAAG,SAAS;IAK7B,gBAAgB,IAAI,IAAI;CAUhC"}
|