@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
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
// Mock @solana/wallet-adapter-base with a proper base class
|
|
4
|
+
vi.mock('@solana/wallet-adapter-base', () => {
|
|
5
|
+
class MockBaseMessageSignerWalletAdapter {
|
|
6
|
+
_evtListeners: Record<string, ((...args: any[]) => void)[]> = {}
|
|
7
|
+
|
|
8
|
+
get connected() {
|
|
9
|
+
return !!(this as any)._publicKey
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
emit(event: string, ...args: any[]) {
|
|
13
|
+
for (const fn of this._evtListeners[event] || []) fn(...args)
|
|
14
|
+
return true
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
on(event: string, fn: (...args: any[]) => void) {
|
|
18
|
+
if (!this._evtListeners[event]) this._evtListeners[event] = []
|
|
19
|
+
this._evtListeners[event].push(fn)
|
|
20
|
+
return this
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
off(event: string, fn: (...args: any[]) => void) {
|
|
24
|
+
if (this._evtListeners[event]) {
|
|
25
|
+
this._evtListeners[event] = this._evtListeners[event].filter(
|
|
26
|
+
f => f !== fn
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
return this
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async prepareTransaction(tx: any) {
|
|
33
|
+
return tx
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
BaseMessageSignerWalletAdapter: MockBaseMessageSignerWalletAdapter,
|
|
39
|
+
isVersionedTransaction: vi.fn(() => false),
|
|
40
|
+
scopePollingDetectionStrategy: vi.fn(),
|
|
41
|
+
WalletAccountError: class extends Error {
|
|
42
|
+
override name = 'WalletAccountError'
|
|
43
|
+
},
|
|
44
|
+
WalletConnectionError: class extends Error {
|
|
45
|
+
override name = 'WalletConnectionError'
|
|
46
|
+
constructor(msg?: string) {
|
|
47
|
+
super(msg || 'WalletConnectionError')
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
WalletDisconnectedError: class extends Error {
|
|
51
|
+
override name = 'WalletDisconnectedError'
|
|
52
|
+
},
|
|
53
|
+
WalletDisconnectionError: class extends Error {
|
|
54
|
+
override name = 'WalletDisconnectionError'
|
|
55
|
+
constructor(msg?: string) {
|
|
56
|
+
super(msg || 'WalletDisconnectionError')
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
WalletError: class extends Error {},
|
|
60
|
+
WalletNotConnectedError: class extends Error {
|
|
61
|
+
override name = 'WalletNotConnectedError'
|
|
62
|
+
},
|
|
63
|
+
WalletNotReadyError: class extends Error {
|
|
64
|
+
override name = 'WalletNotReadyError'
|
|
65
|
+
},
|
|
66
|
+
WalletPublicKeyError: class extends Error {
|
|
67
|
+
override name = 'WalletPublicKeyError'
|
|
68
|
+
constructor(msg?: string) {
|
|
69
|
+
super(msg || 'WalletPublicKeyError')
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
WalletReadyState: {
|
|
73
|
+
Installed: 'Installed',
|
|
74
|
+
NotDetected: 'NotDetected',
|
|
75
|
+
Loadable: 'Loadable',
|
|
76
|
+
Unsupported: 'Unsupported'
|
|
77
|
+
},
|
|
78
|
+
WalletSendTransactionError: class extends Error {
|
|
79
|
+
override name = 'WalletSendTransactionError'
|
|
80
|
+
constructor(msg?: string) {
|
|
81
|
+
super(msg || 'WalletSendTransactionError')
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
WalletSignTransactionError: class extends Error {
|
|
85
|
+
override name = 'WalletSignTransactionError'
|
|
86
|
+
constructor(msg?: string) {
|
|
87
|
+
super(msg || 'WalletSignTransactionError')
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
vi.mock('@solana/web3.js', () => ({
|
|
94
|
+
PublicKey: class {
|
|
95
|
+
constructor(public _bytes: any) {}
|
|
96
|
+
toBase58() {
|
|
97
|
+
return 'mockBase58'
|
|
98
|
+
}
|
|
99
|
+
toBytes() {
|
|
100
|
+
return this._bytes
|
|
101
|
+
}
|
|
102
|
+
toJSON() {
|
|
103
|
+
return 'mockJSON'
|
|
104
|
+
}
|
|
105
|
+
toBuffer() {
|
|
106
|
+
return new Uint8Array([])
|
|
107
|
+
}
|
|
108
|
+
toString() {
|
|
109
|
+
return 'mockString'
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}))
|
|
113
|
+
|
|
114
|
+
describe('BaseWalletAdapter', () => {
|
|
115
|
+
let mockWallet: any
|
|
116
|
+
|
|
117
|
+
beforeEach(() => {
|
|
118
|
+
vi.clearAllMocks()
|
|
119
|
+
|
|
120
|
+
mockWallet = {
|
|
121
|
+
publicKey: { toBytes: () => new Uint8Array([1, 2, 3]) },
|
|
122
|
+
connect: vi.fn().mockResolvedValue(undefined),
|
|
123
|
+
disconnect: vi.fn().mockResolvedValue(undefined),
|
|
124
|
+
signTransaction: vi.fn(async (tx: any) => tx),
|
|
125
|
+
signAllTransactions: vi.fn(async (txs: any) => txs),
|
|
126
|
+
signAndSendTransaction: vi
|
|
127
|
+
.fn()
|
|
128
|
+
.mockResolvedValue({ signature: 'mockSig' }),
|
|
129
|
+
signMessage: vi
|
|
130
|
+
.fn()
|
|
131
|
+
.mockResolvedValue({ signature: new Uint8Array([4, 5, 6]) }),
|
|
132
|
+
on: vi.fn(),
|
|
133
|
+
off: vi.fn()
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
afterEach(() => {
|
|
138
|
+
delete (window as any).coinbaseSolana
|
|
139
|
+
vi.restoreAllMocks()
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
async function createInstalledAdapter() {
|
|
143
|
+
const { scopePollingDetectionStrategy } =
|
|
144
|
+
await import('@solana/wallet-adapter-base')
|
|
145
|
+
const { BaseWalletAdapter } = await import('./BaseWalletAdapter')
|
|
146
|
+
|
|
147
|
+
;(window as any).coinbaseSolana = mockWallet
|
|
148
|
+
const adapter = new BaseWalletAdapter()
|
|
149
|
+
const calls = vi.mocked(scopePollingDetectionStrategy).mock.calls
|
|
150
|
+
const callback = calls[calls.length - 1]![0] as () => boolean
|
|
151
|
+
callback()
|
|
152
|
+
return adapter
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
describe('constructor', () => {
|
|
156
|
+
it('should set correct name and properties', async () => {
|
|
157
|
+
const { BaseWalletAdapter } = await import('./BaseWalletAdapter')
|
|
158
|
+
const adapter = new BaseWalletAdapter()
|
|
159
|
+
|
|
160
|
+
expect(adapter.name).toBe('Base Wallet')
|
|
161
|
+
expect(adapter.url).toContain('chrome.google.com')
|
|
162
|
+
expect(adapter.icon).toContain('data:image/svg+xml;base64,')
|
|
163
|
+
expect(adapter.publicKey).toBeNull()
|
|
164
|
+
expect(adapter.connecting).toBe(false)
|
|
165
|
+
expect(adapter.readyState).toBe('NotDetected')
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('should call scopePollingDetectionStrategy', async () => {
|
|
169
|
+
const { scopePollingDetectionStrategy } =
|
|
170
|
+
await import('@solana/wallet-adapter-base')
|
|
171
|
+
const { BaseWalletAdapter } = await import('./BaseWalletAdapter')
|
|
172
|
+
|
|
173
|
+
new BaseWalletAdapter()
|
|
174
|
+
|
|
175
|
+
expect(scopePollingDetectionStrategy).toHaveBeenCalledWith(
|
|
176
|
+
expect.any(Function)
|
|
177
|
+
)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('should detect wallet when window.coinbaseSolana exists', async () => {
|
|
181
|
+
const { scopePollingDetectionStrategy } =
|
|
182
|
+
await import('@solana/wallet-adapter-base')
|
|
183
|
+
const { BaseWalletAdapter } = await import('./BaseWalletAdapter')
|
|
184
|
+
|
|
185
|
+
const adapter = new BaseWalletAdapter()
|
|
186
|
+
const mock = vi.mocked(scopePollingDetectionStrategy).mock
|
|
187
|
+
const callback = mock.calls[mock.calls.length - 1]![0] as () => boolean
|
|
188
|
+
|
|
189
|
+
expect(callback()).toBe(false)
|
|
190
|
+
;(window as any).coinbaseSolana = mockWallet
|
|
191
|
+
expect(callback()).toBe(true)
|
|
192
|
+
expect(adapter.readyState).toBe('Installed')
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
describe('connect', () => {
|
|
197
|
+
it('should throw WalletNotReadyError when not installed', async () => {
|
|
198
|
+
const { BaseWalletAdapter } = await import('./BaseWalletAdapter')
|
|
199
|
+
const adapter = new BaseWalletAdapter()
|
|
200
|
+
|
|
201
|
+
await expect(adapter.connect()).rejects.toThrow()
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('should connect successfully when installed', async () => {
|
|
205
|
+
const adapter = await createInstalledAdapter()
|
|
206
|
+
|
|
207
|
+
await adapter.connect()
|
|
208
|
+
|
|
209
|
+
expect(mockWallet.connect).toHaveBeenCalled()
|
|
210
|
+
expect(adapter.publicKey).toBeDefined()
|
|
211
|
+
expect(adapter.connecting).toBe(false)
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it('should emit connect event on success', async () => {
|
|
215
|
+
const adapter = await createInstalledAdapter()
|
|
216
|
+
const connectHandler = vi.fn()
|
|
217
|
+
adapter.on('connect', connectHandler)
|
|
218
|
+
|
|
219
|
+
await adapter.connect()
|
|
220
|
+
|
|
221
|
+
expect(connectHandler).toHaveBeenCalled()
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it('should throw when wallet.connect fails', async () => {
|
|
225
|
+
mockWallet.connect.mockRejectedValue(new Error('Connection failed'))
|
|
226
|
+
const adapter = await createInstalledAdapter()
|
|
227
|
+
|
|
228
|
+
await expect(adapter.connect()).rejects.toThrow()
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it('should throw when no publicKey after connect', async () => {
|
|
232
|
+
mockWallet.publicKey = null
|
|
233
|
+
const adapter = await createInstalledAdapter()
|
|
234
|
+
|
|
235
|
+
await expect(adapter.connect()).rejects.toThrow()
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
it('should return early if already connected', async () => {
|
|
239
|
+
const adapter = await createInstalledAdapter()
|
|
240
|
+
|
|
241
|
+
await adapter.connect()
|
|
242
|
+
await adapter.connect()
|
|
243
|
+
|
|
244
|
+
expect(mockWallet.connect).toHaveBeenCalledTimes(1)
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
describe('disconnect', () => {
|
|
249
|
+
it('should clear state on disconnect', async () => {
|
|
250
|
+
const adapter = await createInstalledAdapter()
|
|
251
|
+
await adapter.connect()
|
|
252
|
+
|
|
253
|
+
await adapter.disconnect()
|
|
254
|
+
|
|
255
|
+
expect(adapter.publicKey).toBeNull()
|
|
256
|
+
expect(mockWallet.disconnect).toHaveBeenCalled()
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('should emit disconnect event', async () => {
|
|
260
|
+
const adapter = await createInstalledAdapter()
|
|
261
|
+
await adapter.connect()
|
|
262
|
+
|
|
263
|
+
const handler = vi.fn()
|
|
264
|
+
adapter.on('disconnect', handler)
|
|
265
|
+
|
|
266
|
+
await adapter.disconnect()
|
|
267
|
+
|
|
268
|
+
expect(handler).toHaveBeenCalled()
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
it('should handle wallet.disconnect error gracefully', async () => {
|
|
272
|
+
mockWallet.disconnect.mockRejectedValue(new Error('fail'))
|
|
273
|
+
const adapter = await createInstalledAdapter()
|
|
274
|
+
await adapter.connect()
|
|
275
|
+
|
|
276
|
+
await expect(adapter.disconnect()).resolves.toBeUndefined()
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it('should emit disconnect even when no wallet connected', async () => {
|
|
280
|
+
const { BaseWalletAdapter } = await import('./BaseWalletAdapter')
|
|
281
|
+
const adapter = new BaseWalletAdapter()
|
|
282
|
+
|
|
283
|
+
const handler = vi.fn()
|
|
284
|
+
adapter.on('disconnect', handler)
|
|
285
|
+
|
|
286
|
+
await adapter.disconnect()
|
|
287
|
+
|
|
288
|
+
expect(handler).toHaveBeenCalled()
|
|
289
|
+
})
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
describe('signTransaction', () => {
|
|
293
|
+
it('should throw when not connected', async () => {
|
|
294
|
+
const { BaseWalletAdapter } = await import('./BaseWalletAdapter')
|
|
295
|
+
const adapter = new BaseWalletAdapter()
|
|
296
|
+
|
|
297
|
+
await expect(adapter.signTransaction({} as any)).rejects.toThrow()
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
it('should call wallet.signTransaction when connected', async () => {
|
|
301
|
+
const adapter = await createInstalledAdapter()
|
|
302
|
+
await adapter.connect()
|
|
303
|
+
|
|
304
|
+
const mockTx = { mock: true } as any
|
|
305
|
+
await adapter.signTransaction(mockTx)
|
|
306
|
+
|
|
307
|
+
expect(mockWallet.signTransaction).toHaveBeenCalledWith(mockTx)
|
|
308
|
+
})
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
describe('signAllTransactions', () => {
|
|
312
|
+
it('should throw when not connected', async () => {
|
|
313
|
+
const { BaseWalletAdapter } = await import('./BaseWalletAdapter')
|
|
314
|
+
const adapter = new BaseWalletAdapter()
|
|
315
|
+
|
|
316
|
+
await expect(adapter.signAllTransactions([{} as any])).rejects.toThrow()
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
it('should call wallet.signAllTransactions when connected', async () => {
|
|
320
|
+
const adapter = await createInstalledAdapter()
|
|
321
|
+
await adapter.connect()
|
|
322
|
+
|
|
323
|
+
const mockTxs = [{ mock: 1 }, { mock: 2 }] as any[]
|
|
324
|
+
await adapter.signAllTransactions(mockTxs)
|
|
325
|
+
|
|
326
|
+
expect(mockWallet.signAllTransactions).toHaveBeenCalledWith(mockTxs)
|
|
327
|
+
})
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
describe('signMessage', () => {
|
|
331
|
+
it('should throw when not connected', async () => {
|
|
332
|
+
const { BaseWalletAdapter } = await import('./BaseWalletAdapter')
|
|
333
|
+
const adapter = new BaseWalletAdapter()
|
|
334
|
+
|
|
335
|
+
await expect(adapter.signMessage(new Uint8Array([1]))).rejects.toThrow()
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
it('should return signature when connected', async () => {
|
|
339
|
+
const adapter = await createInstalledAdapter()
|
|
340
|
+
await adapter.connect()
|
|
341
|
+
|
|
342
|
+
const result = await adapter.signMessage(new Uint8Array([1, 2, 3]))
|
|
343
|
+
|
|
344
|
+
expect(mockWallet.signMessage).toHaveBeenCalled()
|
|
345
|
+
expect(result).toEqual(new Uint8Array([4, 5, 6]))
|
|
346
|
+
})
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
describe('sendTransaction', () => {
|
|
350
|
+
it('should throw when not connected', async () => {
|
|
351
|
+
const { BaseWalletAdapter } = await import('./BaseWalletAdapter')
|
|
352
|
+
const adapter = new BaseWalletAdapter()
|
|
353
|
+
|
|
354
|
+
await expect(
|
|
355
|
+
adapter.sendTransaction({} as any, {} as any)
|
|
356
|
+
).rejects.toThrow()
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
it('should return signature when connected', async () => {
|
|
360
|
+
const adapter = await createInstalledAdapter()
|
|
361
|
+
await adapter.connect()
|
|
362
|
+
|
|
363
|
+
const mockTx = {} as any
|
|
364
|
+
const mockConnection = { commitment: 'confirmed' } as any
|
|
365
|
+
const result = await adapter.sendTransaction(mockTx, mockConnection)
|
|
366
|
+
|
|
367
|
+
expect(mockWallet.signAndSendTransaction).toHaveBeenCalled()
|
|
368
|
+
expect(result).toBe('mockSig')
|
|
369
|
+
})
|
|
370
|
+
})
|
|
371
|
+
})
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EventEmitter,
|
|
3
|
+
SendTransactionOptions,
|
|
4
|
+
WalletName
|
|
5
|
+
} from '@solana/wallet-adapter-base'
|
|
6
|
+
import {
|
|
7
|
+
BaseMessageSignerWalletAdapter,
|
|
8
|
+
isVersionedTransaction,
|
|
9
|
+
scopePollingDetectionStrategy,
|
|
10
|
+
WalletAccountError,
|
|
11
|
+
WalletConnectionError,
|
|
12
|
+
WalletDisconnectedError,
|
|
13
|
+
WalletDisconnectionError,
|
|
14
|
+
WalletError,
|
|
15
|
+
WalletNotConnectedError,
|
|
16
|
+
WalletNotReadyError,
|
|
17
|
+
WalletPublicKeyError,
|
|
18
|
+
WalletReadyState,
|
|
19
|
+
WalletSendTransactionError,
|
|
20
|
+
WalletSignTransactionError,
|
|
21
|
+
WalletSignMessageError
|
|
22
|
+
} from '@solana/wallet-adapter-base'
|
|
23
|
+
import type {
|
|
24
|
+
Connection,
|
|
25
|
+
SendOptions,
|
|
26
|
+
Transaction,
|
|
27
|
+
VersionedTransaction,
|
|
28
|
+
TransactionSignature,
|
|
29
|
+
TransactionVersion
|
|
30
|
+
} from '@solana/web3.js'
|
|
31
|
+
import { PublicKey } from '@solana/web3.js'
|
|
32
|
+
|
|
33
|
+
interface CoinbaseWalletEvents {
|
|
34
|
+
connect(...args: unknown[]): unknown
|
|
35
|
+
disconnect(...args: unknown[]): unknown
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface CoinbaseWallet extends EventEmitter<CoinbaseWalletEvents> {
|
|
39
|
+
publicKey?: PublicKey
|
|
40
|
+
signTransaction<T extends Transaction | VersionedTransaction>(
|
|
41
|
+
transaction: T
|
|
42
|
+
): Promise<T>
|
|
43
|
+
signAllTransactions<T extends Transaction | VersionedTransaction>(
|
|
44
|
+
transactions: T[]
|
|
45
|
+
): Promise<T[]>
|
|
46
|
+
signAndSendTransaction<T extends Transaction | VersionedTransaction>(
|
|
47
|
+
transaction: T,
|
|
48
|
+
options?: SendOptions
|
|
49
|
+
): Promise<{ signature: TransactionSignature }>
|
|
50
|
+
signMessage(message: Uint8Array): Promise<{ signature: Uint8Array }>
|
|
51
|
+
connect(): Promise<void>
|
|
52
|
+
disconnect(): Promise<void>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface CoinbaseWindow extends Window {
|
|
56
|
+
coinbaseSolana?: CoinbaseWallet
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
declare const window: CoinbaseWindow
|
|
60
|
+
|
|
61
|
+
export const BaseWalletName = 'Base Wallet' as WalletName<'Base Wallet'>
|
|
62
|
+
|
|
63
|
+
export class BaseWalletAdapter extends BaseMessageSignerWalletAdapter {
|
|
64
|
+
name = BaseWalletName
|
|
65
|
+
url =
|
|
66
|
+
'https://chrome.google.com/webstore/detail/coinbase-wallet-extension/hnfanknocfeofbddgcijnmhnfnkdnaad'
|
|
67
|
+
icon =
|
|
68
|
+
'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAyNCIgaGVpZ2h0PSIxMDI0IiB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8Y2lyY2xlIGN4PSI1MTIiIGN5PSI1MTIiIHI9IjUxMiIgZmlsbD0iIzAwNTJGRiIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTE1MiA1MTJDMTUyIDcxMC44MjMgMzEzLjE3NyA4NzIgNTEyIDg3MkM3MTAuODIzIDg3MiA4NzIgNzEwLjgyMyA4NzIgNTEyQzg3MiAzMTMuMTc3IDcxMC44MjMgMTUyIDUxMiAxNTJDMzEzLjE3NyAxNTIgMTUyIDMxMy4xNzcgMTUyIDUxMlpNNDIwIDM5NkM0MDYuNzQ1IDM5NiAzOTYgNDA2Ljc0NSAzOTYgNDIwVjYwNEMzOTYgNjE3LjI1NSA0MDYuNzQ1IDYyOCA0MjAgNjI4SDYwNEM2MTcuMjU1IDYyOCA2MjggNjE3LjI1NSA2MjggNjA0VjQyMEM2MjggNDA2Ljc0NSA2MTcuMjU1IDM5NiA2MDQgMzk2SDQyMFoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo='
|
|
69
|
+
supportedTransactionVersions: ReadonlySet<TransactionVersion> = new Set([
|
|
70
|
+
'legacy',
|
|
71
|
+
0
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
private _connecting: boolean
|
|
75
|
+
private _wallet: CoinbaseWallet | null
|
|
76
|
+
private _publicKey: PublicKey | null
|
|
77
|
+
private _readyState: WalletReadyState =
|
|
78
|
+
typeof window === 'undefined' || typeof document === 'undefined'
|
|
79
|
+
? WalletReadyState.Unsupported
|
|
80
|
+
: WalletReadyState.NotDetected
|
|
81
|
+
|
|
82
|
+
constructor() {
|
|
83
|
+
super()
|
|
84
|
+
this._connecting = false
|
|
85
|
+
this._wallet = null
|
|
86
|
+
this._publicKey = null
|
|
87
|
+
|
|
88
|
+
if (this._readyState !== WalletReadyState.Unsupported) {
|
|
89
|
+
scopePollingDetectionStrategy(() => {
|
|
90
|
+
if (window?.coinbaseSolana) {
|
|
91
|
+
this._readyState = WalletReadyState.Installed
|
|
92
|
+
this.emit('readyStateChange', this._readyState)
|
|
93
|
+
return true
|
|
94
|
+
}
|
|
95
|
+
return false
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get publicKey() {
|
|
101
|
+
return this._publicKey
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get connecting() {
|
|
105
|
+
return this._connecting
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get readyState() {
|
|
109
|
+
return this._readyState
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async connect(): Promise<void> {
|
|
113
|
+
try {
|
|
114
|
+
if (this.connected || this.connecting) return
|
|
115
|
+
if (this._readyState !== WalletReadyState.Installed)
|
|
116
|
+
throw new WalletNotReadyError()
|
|
117
|
+
|
|
118
|
+
this._connecting = true
|
|
119
|
+
|
|
120
|
+
const wallet = window.coinbaseSolana!
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
await wallet.connect()
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
125
|
+
} catch (error: any) {
|
|
126
|
+
throw new WalletConnectionError(error?.message, error)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!wallet.publicKey) throw new WalletAccountError()
|
|
130
|
+
|
|
131
|
+
let publicKey: PublicKey
|
|
132
|
+
try {
|
|
133
|
+
publicKey = new PublicKey(wallet.publicKey.toBytes())
|
|
134
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
135
|
+
} catch (error: any) {
|
|
136
|
+
throw new WalletPublicKeyError(error?.message, error)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
wallet.on('disconnect', this._disconnected)
|
|
140
|
+
|
|
141
|
+
this._wallet = wallet
|
|
142
|
+
this._publicKey = publicKey
|
|
143
|
+
|
|
144
|
+
this.emit('connect', publicKey)
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
146
|
+
} catch (error: any) {
|
|
147
|
+
this.emit('error', error)
|
|
148
|
+
throw error
|
|
149
|
+
} finally {
|
|
150
|
+
this._connecting = false
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async disconnect(): Promise<void> {
|
|
155
|
+
const wallet = this._wallet
|
|
156
|
+
if (wallet) {
|
|
157
|
+
wallet.off('disconnect', this._disconnected)
|
|
158
|
+
|
|
159
|
+
this._wallet = null
|
|
160
|
+
this._publicKey = null
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
await wallet.disconnect()
|
|
164
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
165
|
+
} catch (error: any) {
|
|
166
|
+
this.emit('error', new WalletDisconnectionError(error?.message, error))
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this.emit('disconnect')
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
override async sendTransaction<T extends Transaction | VersionedTransaction>(
|
|
174
|
+
transaction: T,
|
|
175
|
+
connection: Connection,
|
|
176
|
+
options: SendTransactionOptions = {}
|
|
177
|
+
): Promise<TransactionSignature> {
|
|
178
|
+
try {
|
|
179
|
+
const wallet = this._wallet
|
|
180
|
+
if (!wallet) throw new WalletNotConnectedError()
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
const { signers, ...sendOptions } = options
|
|
184
|
+
|
|
185
|
+
if (isVersionedTransaction(transaction)) {
|
|
186
|
+
if (signers?.length) transaction.sign(signers)
|
|
187
|
+
} else {
|
|
188
|
+
if (!(transaction as Transaction).recentBlockhash) {
|
|
189
|
+
transaction = (await this.prepareTransaction(
|
|
190
|
+
transaction,
|
|
191
|
+
connection,
|
|
192
|
+
sendOptions
|
|
193
|
+
)) as T
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (signers?.length)
|
|
197
|
+
(transaction as Transaction).partialSign(...signers)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!sendOptions.preflightCommitment && connection.commitment) {
|
|
201
|
+
sendOptions.preflightCommitment = connection.commitment
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const { signature } = await wallet.signAndSendTransaction(
|
|
205
|
+
transaction,
|
|
206
|
+
sendOptions
|
|
207
|
+
)
|
|
208
|
+
return signature
|
|
209
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
210
|
+
} catch (error: any) {
|
|
211
|
+
if (error instanceof WalletError) throw error
|
|
212
|
+
throw new WalletSendTransactionError(error?.message, error)
|
|
213
|
+
}
|
|
214
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
215
|
+
} catch (error: any) {
|
|
216
|
+
this.emit('error', error)
|
|
217
|
+
throw error
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async signTransaction<T extends Transaction | VersionedTransaction>(
|
|
222
|
+
transaction: T
|
|
223
|
+
): Promise<T> {
|
|
224
|
+
try {
|
|
225
|
+
const wallet = this._wallet
|
|
226
|
+
if (!wallet) throw new WalletNotConnectedError()
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
return ((await wallet.signTransaction(transaction)) as T) || transaction
|
|
230
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
231
|
+
} catch (error: any) {
|
|
232
|
+
throw new WalletSignTransactionError(error?.message, error)
|
|
233
|
+
}
|
|
234
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
235
|
+
} catch (error: any) {
|
|
236
|
+
this.emit('error', error)
|
|
237
|
+
throw error
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
override async signAllTransactions<
|
|
242
|
+
T extends Transaction | VersionedTransaction
|
|
243
|
+
>(transactions: T[]): Promise<T[]> {
|
|
244
|
+
try {
|
|
245
|
+
const wallet = this._wallet
|
|
246
|
+
if (!wallet) throw new WalletNotConnectedError()
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
return (
|
|
250
|
+
((await wallet.signAllTransactions(transactions)) as T[]) ||
|
|
251
|
+
transactions
|
|
252
|
+
)
|
|
253
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
254
|
+
} catch (error: any) {
|
|
255
|
+
throw new WalletSignTransactionError(error?.message, error)
|
|
256
|
+
}
|
|
257
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
258
|
+
} catch (error: any) {
|
|
259
|
+
this.emit('error', error)
|
|
260
|
+
throw error
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async signMessage(message: Uint8Array): Promise<Uint8Array> {
|
|
265
|
+
try {
|
|
266
|
+
const wallet = this._wallet
|
|
267
|
+
if (!wallet) throw new WalletNotConnectedError()
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
const { signature } = await wallet.signMessage(message)
|
|
271
|
+
return signature
|
|
272
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
273
|
+
} catch (error: any) {
|
|
274
|
+
throw new WalletSignMessageError(error?.message, error)
|
|
275
|
+
}
|
|
276
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
277
|
+
} catch (error: any) {
|
|
278
|
+
this.emit('error', error)
|
|
279
|
+
throw error
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private _disconnected = () => {
|
|
284
|
+
const wallet = this._wallet
|
|
285
|
+
if (wallet) {
|
|
286
|
+
wallet.off('disconnect', this._disconnected)
|
|
287
|
+
|
|
288
|
+
this._wallet = null
|
|
289
|
+
this._publicKey = null
|
|
290
|
+
|
|
291
|
+
this.emit('error', new WalletDisconnectedError())
|
|
292
|
+
this.emit('disconnect')
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|