@meshconnect/uwc-core 0.7.4 → 0.7.5-snapshot.3e19fe0
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/README.md +924 -0
- package/dist/events.d.ts +71 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +2 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/managers/event-manager.d.ts +22 -3
- package/dist/managers/event-manager.d.ts.map +1 -1
- package/dist/managers/event-manager.js +63 -7
- package/dist/managers/event-manager.js.map +1 -1
- package/dist/services/connection-service.d.ts +5 -2
- package/dist/services/connection-service.d.ts.map +1 -1
- package/dist/services/connection-service.js +19 -7
- package/dist/services/connection-service.js.map +1 -1
- package/dist/services/network-switch-service.d.ts +2 -1
- package/dist/services/network-switch-service.d.ts.map +1 -1
- package/dist/services/network-switch-service.js +15 -3
- package/dist/services/network-switch-service.js.map +1 -1
- package/dist/services/signature-service.d.ts +3 -1
- package/dist/services/signature-service.d.ts.map +1 -1
- package/dist/services/signature-service.js +10 -5
- package/dist/services/signature-service.js.map +1 -1
- package/dist/services/transaction-service.d.ts +3 -1
- package/dist/services/transaction-service.d.ts.map +1 -1
- package/dist/services/transaction-service.js +10 -5
- package/dist/services/transaction-service.js.map +1 -1
- package/dist/services/wallet-capabilities-service.d.ts +2 -1
- package/dist/services/wallet-capabilities-service.d.ts.map +1 -1
- package/dist/services/wallet-capabilities-service.js +9 -2
- package/dist/services/wallet-capabilities-service.js.map +1 -1
- package/dist/universal-wallet-connector.d.ts +46 -6
- package/dist/universal-wallet-connector.d.ts.map +1 -1
- package/dist/universal-wallet-connector.js +171 -62
- package/dist/universal-wallet-connector.js.map +1 -1
- package/package.json +5 -5
- package/src/events.ts +73 -0
- package/src/index.ts +11 -3
- package/src/managers/event-manager.test.ts +70 -0
- package/src/managers/event-manager.ts +80 -9
- package/src/services/connection-service.test.ts +11 -3
- package/src/services/connection-service.ts +34 -7
- package/src/services/network-switch-service.ts +22 -3
- package/src/services/signature-service.ts +13 -5
- package/src/services/transaction-service.ts +13 -5
- package/src/services/wallet-capabilities-service.ts +14 -2
- package/src/universal-wallet-connector.test.ts +87 -3
- package/src/universal-wallet-connector.ts +254 -66
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
} from '@meshconnect/uwc-types'
|
|
7
7
|
import type { SessionManager } from '../managers/session-manager'
|
|
8
8
|
import type { EventManager } from '../managers/event-manager'
|
|
9
|
+
import type { ServiceOptions } from './connection-service'
|
|
9
10
|
|
|
10
11
|
export class WalletCapabilitiesService {
|
|
11
12
|
constructor(
|
|
@@ -17,8 +18,11 @@ export class WalletCapabilitiesService {
|
|
|
17
18
|
|
|
18
19
|
async getWalletCapabilities(
|
|
19
20
|
address: string,
|
|
20
|
-
activeNetwork?: Network
|
|
21
|
+
activeNetwork?: Network,
|
|
22
|
+
options?: ServiceOptions
|
|
21
23
|
): Promise<void> {
|
|
24
|
+
options?.signal?.throwIfAborted()
|
|
25
|
+
|
|
22
26
|
let activeWalletCapabilities: Record<string, EVMCapabilities> = {}
|
|
23
27
|
let activeNetworkWalletCapabilities: EVMCapabilities = {}
|
|
24
28
|
|
|
@@ -49,6 +53,8 @@ export class WalletCapabilitiesService {
|
|
|
49
53
|
capabilities = {}
|
|
50
54
|
}
|
|
51
55
|
|
|
56
|
+
options?.signal?.throwIfAborted()
|
|
57
|
+
|
|
52
58
|
// keep only supported networks
|
|
53
59
|
activeWalletCapabilities = Object.fromEntries(
|
|
54
60
|
Object.entries(capabilities).filter(([networkId, _]) =>
|
|
@@ -71,7 +77,13 @@ export class WalletCapabilitiesService {
|
|
|
71
77
|
activeNetworkWalletCapabilities: null
|
|
72
78
|
})
|
|
73
79
|
}
|
|
74
|
-
|
|
80
|
+
|
|
81
|
+
this.eventManager.emit('capabilitiesUpdated', {
|
|
82
|
+
capabilities: activeWalletCapabilities
|
|
83
|
+
})
|
|
84
|
+
this.eventManager.emit('sessionChanged', {
|
|
85
|
+
session: this.sessionManager.getSession()
|
|
86
|
+
})
|
|
75
87
|
}
|
|
76
88
|
}
|
|
77
89
|
}
|
|
@@ -29,7 +29,11 @@ const mockSessionManager = {
|
|
|
29
29
|
|
|
30
30
|
const mockEventManager = {
|
|
31
31
|
subscribe: vi.fn().mockReturnValue(() => {}),
|
|
32
|
-
notify: vi.fn()
|
|
32
|
+
notify: vi.fn(),
|
|
33
|
+
emit: vi.fn(),
|
|
34
|
+
on: vi.fn().mockReturnValue(() => {}),
|
|
35
|
+
off: vi.fn(),
|
|
36
|
+
once: vi.fn().mockReturnValue(() => {})
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
const mockConnectionService = {
|
|
@@ -117,8 +121,7 @@ describe('UniversalWalletConnector', () => {
|
|
|
117
121
|
let mockWalletConnectConfig: WalletConnectConfig
|
|
118
122
|
|
|
119
123
|
beforeEach(() => {
|
|
120
|
-
|
|
121
|
-
;(UniversalWalletConnector as any).hasWarnedAboutMultipleInstances = false
|
|
124
|
+
UniversalWalletConnector.resetInstance()
|
|
122
125
|
|
|
123
126
|
mockNetworks = [
|
|
124
127
|
{
|
|
@@ -402,6 +405,87 @@ describe('UniversalWalletConnector', () => {
|
|
|
402
405
|
expect(typeof connector.sendTransaction).toBe('function')
|
|
403
406
|
expect(typeof connector.isConnectionModeAvailable).toBe('function')
|
|
404
407
|
expect(typeof connector.getActiveWalletCapabilities).toBe('function')
|
|
408
|
+
expect(typeof connector.on).toBe('function')
|
|
409
|
+
expect(typeof connector.once).toBe('function')
|
|
410
|
+
expect(typeof connector.off).toBe('function')
|
|
411
|
+
})
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
describe('getInstance singleton factory', () => {
|
|
415
|
+
it('creates an instance on first call and reuses it afterwards', () => {
|
|
416
|
+
const a = UniversalWalletConnector.getInstance({
|
|
417
|
+
networks: mockNetworks,
|
|
418
|
+
wallets: mockWallets
|
|
419
|
+
})
|
|
420
|
+
const b = UniversalWalletConnector.getInstance({
|
|
421
|
+
networks: mockNetworks,
|
|
422
|
+
wallets: mockWallets
|
|
423
|
+
})
|
|
424
|
+
expect(a).toBe(b)
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
it('throws when called before any instance exists and no config is given', () => {
|
|
428
|
+
expect(() => UniversalWalletConnector.getInstance()).toThrow(
|
|
429
|
+
/getInstance.*before an instance existed/
|
|
430
|
+
)
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
it('resetInstance() clears the shared reference', () => {
|
|
434
|
+
const first = UniversalWalletConnector.getInstance({
|
|
435
|
+
networks: mockNetworks,
|
|
436
|
+
wallets: mockWallets
|
|
437
|
+
})
|
|
438
|
+
UniversalWalletConnector.resetInstance()
|
|
439
|
+
const second = UniversalWalletConnector.getInstance({
|
|
440
|
+
networks: mockNetworks,
|
|
441
|
+
wallets: mockWallets
|
|
442
|
+
})
|
|
443
|
+
expect(second).not.toBe(first)
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
it('adopts a `new`-constructed instance as the singleton', () => {
|
|
447
|
+
const created = new UniversalWalletConnector(mockNetworks, mockWallets)
|
|
448
|
+
expect(UniversalWalletConnector.getInstance()).toBe(created)
|
|
449
|
+
})
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
describe('config-object constructor', () => {
|
|
453
|
+
it('accepts the { networks, wallets, ... } form', () => {
|
|
454
|
+
const connector = new UniversalWalletConnector({
|
|
455
|
+
networks: mockNetworks,
|
|
456
|
+
wallets: mockWallets,
|
|
457
|
+
walletConnectConfig: mockWalletConnectConfig
|
|
458
|
+
})
|
|
459
|
+
expect(connector).toBeInstanceOf(UniversalWalletConnector)
|
|
460
|
+
})
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
describe('AbortSignal support', () => {
|
|
464
|
+
it('connect rejects immediately when signal is already aborted', async () => {
|
|
465
|
+
const connector = new UniversalWalletConnector(mockNetworks, mockWallets)
|
|
466
|
+
const controller = new AbortController()
|
|
467
|
+
controller.abort()
|
|
468
|
+
|
|
469
|
+
// ConnectionService.connect is mocked to return undefined by default,
|
|
470
|
+
// so the abort check is what surfaces the error.
|
|
471
|
+
mockConnectionService.connect = vi.fn().mockImplementation(
|
|
472
|
+
async (
|
|
473
|
+
_m: unknown,
|
|
474
|
+
_w: unknown,
|
|
475
|
+
_n: unknown,
|
|
476
|
+
options?: {
|
|
477
|
+
signal?: AbortSignal
|
|
478
|
+
}
|
|
479
|
+
) => {
|
|
480
|
+
options?.signal?.throwIfAborted()
|
|
481
|
+
}
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
await expect(
|
|
485
|
+
connector.connect('injected', 'metamask', undefined, {
|
|
486
|
+
signal: controller.signal
|
|
487
|
+
})
|
|
488
|
+
).rejects.toThrow()
|
|
405
489
|
})
|
|
406
490
|
})
|
|
407
491
|
|
|
@@ -16,8 +16,10 @@ import type {
|
|
|
16
16
|
TransactionResult,
|
|
17
17
|
NetworkRpcMap,
|
|
18
18
|
EVMCapabilities,
|
|
19
|
-
SignatureType
|
|
19
|
+
SignatureType,
|
|
20
|
+
WalletError
|
|
20
21
|
} from '@meshconnect/uwc-types'
|
|
22
|
+
import { WalletConnectorError } from '@meshconnect/uwc-types'
|
|
21
23
|
import { InjectedConnector } from '@meshconnect/uwc-injected-connector'
|
|
22
24
|
import { WalletConnectConnector } from '@meshconnect/uwc-wallet-connect-connector'
|
|
23
25
|
import { TonConnectConnector } from '@meshconnect/uwc-ton-connector'
|
|
@@ -29,8 +31,28 @@ import { SignatureService } from './services/signature-service'
|
|
|
29
31
|
import { TransactionService } from './services/transaction-service'
|
|
30
32
|
import { WalletCapabilitiesService } from './services/wallet-capabilities-service'
|
|
31
33
|
import { createNetworkRpcMap } from './utils/network-rpc-utils'
|
|
34
|
+
import type { UWCEventName, UWCEventListener, UWCOperation } from './events'
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Configuration object form of the UniversalWalletConnector constructor.
|
|
38
|
+
* Prefer this over the positional constructor in new code.
|
|
39
|
+
*/
|
|
40
|
+
export interface UWCConfig {
|
|
41
|
+
networks: Network[]
|
|
42
|
+
wallets?: WalletMetadata[]
|
|
43
|
+
usingIntegratedBrowser?: boolean
|
|
44
|
+
walletConnectConfig?: WalletConnectConfig
|
|
45
|
+
tonConnectConfig?: TonConnectConfig
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Common options for user-initiated async operations. */
|
|
49
|
+
export interface OperationOptions {
|
|
50
|
+
/** Abort the operation if the signal fires. State mutations are skipped after abort. */
|
|
51
|
+
signal?: AbortSignal
|
|
52
|
+
}
|
|
32
53
|
|
|
33
54
|
export class UniversalWalletConnector {
|
|
55
|
+
private static instance: UniversalWalletConnector | null = null
|
|
34
56
|
private static instanceCount = 0
|
|
35
57
|
private static hasWarnedAboutMultipleInstances = false
|
|
36
58
|
|
|
@@ -48,17 +70,78 @@ export class UniversalWalletConnector {
|
|
|
48
70
|
private detectionComplete = false
|
|
49
71
|
private networkRpcMap: NetworkRpcMap
|
|
50
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Recommended entry point: returns the shared instance, creating it on the
|
|
75
|
+
* first call. Subsequent calls ignore the `config` argument — use
|
|
76
|
+
* `resetInstance()` first if you need to reinitialise (e.g. in tests).
|
|
77
|
+
*/
|
|
78
|
+
static getInstance(config?: UWCConfig): UniversalWalletConnector {
|
|
79
|
+
if (UniversalWalletConnector.instance) {
|
|
80
|
+
return UniversalWalletConnector.instance
|
|
81
|
+
}
|
|
82
|
+
if (!config) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
'UniversalWalletConnector.getInstance() was called before an instance existed. Pass a config on the first call.'
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
return new UniversalWalletConnector(config)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Clear the shared instance reference. Primarily for tests and full-logout flows. */
|
|
91
|
+
static resetInstance(): void {
|
|
92
|
+
UniversalWalletConnector.instance = null
|
|
93
|
+
UniversalWalletConnector.instanceCount = 0
|
|
94
|
+
UniversalWalletConnector.hasWarnedAboutMultipleInstances = false
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
constructor(config: UWCConfig)
|
|
51
98
|
constructor(
|
|
52
99
|
networks: Network[],
|
|
100
|
+
wallets?: WalletMetadata[],
|
|
101
|
+
usingIntegratedBrowser?: boolean,
|
|
102
|
+
walletConnectConfig?: WalletConnectConfig,
|
|
103
|
+
tonConnectConfig?: TonConnectConfig
|
|
104
|
+
)
|
|
105
|
+
constructor(
|
|
106
|
+
networksOrConfig: Network[] | UWCConfig,
|
|
53
107
|
wallets: WalletMetadata[] = [],
|
|
54
108
|
usingIntegratedBrowser = false,
|
|
55
109
|
walletConnectConfig?: WalletConnectConfig,
|
|
56
110
|
tonConnectConfig?: TonConnectConfig
|
|
57
111
|
) {
|
|
58
|
-
|
|
59
|
-
|
|
112
|
+
if (!networksOrConfig) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
'Universal Wallet Connector must be initialized with at least one network'
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let config: UWCConfig
|
|
119
|
+
if (Array.isArray(networksOrConfig)) {
|
|
120
|
+
config = {
|
|
121
|
+
networks: networksOrConfig,
|
|
122
|
+
wallets,
|
|
123
|
+
usingIntegratedBrowser
|
|
124
|
+
}
|
|
125
|
+
if (walletConnectConfig) {
|
|
126
|
+
config.walletConnectConfig = walletConnectConfig
|
|
127
|
+
}
|
|
128
|
+
if (tonConnectConfig) {
|
|
129
|
+
config.tonConnectConfig = tonConnectConfig
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
config = networksOrConfig
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const {
|
|
136
|
+
networks,
|
|
137
|
+
wallets: configuredWallets = [],
|
|
138
|
+
usingIntegratedBrowser: configuredUsingIntegratedBrowser = false,
|
|
139
|
+
walletConnectConfig: configuredWalletConnectConfig,
|
|
140
|
+
tonConnectConfig: configuredTonConnectConfig
|
|
141
|
+
} = config
|
|
60
142
|
|
|
61
|
-
//
|
|
143
|
+
// Track instance creation and warn on duplicates
|
|
144
|
+
UniversalWalletConnector.instanceCount++
|
|
62
145
|
if (
|
|
63
146
|
UniversalWalletConnector.instanceCount > 1 &&
|
|
64
147
|
!UniversalWalletConnector.hasWarnedAboutMultipleInstances
|
|
@@ -68,7 +151,7 @@ export class UniversalWalletConnector {
|
|
|
68
151
|
`⚠️ WARNING: Multiple instances of UniversalWalletConnector detected (${UniversalWalletConnector.instanceCount} instances). ` +
|
|
69
152
|
'This can lead to state inconsistencies and unexpected behavior. ' +
|
|
70
153
|
'Please ensure you create only one instance and reuse it throughout your application. ' +
|
|
71
|
-
'
|
|
154
|
+
'Use UniversalWalletConnector.getInstance(config) instead of `new` to guarantee a single instance. ' +
|
|
72
155
|
'You can ignore this warning if you are using React Strict Mode, which intentionally mounts components twice in development to help identify side effects.'
|
|
73
156
|
)
|
|
74
157
|
UniversalWalletConnector.hasWarnedAboutMultipleInstances = true
|
|
@@ -79,14 +162,14 @@ export class UniversalWalletConnector {
|
|
|
79
162
|
'Universal Wallet Connector must be initialized with at least one network'
|
|
80
163
|
)
|
|
81
164
|
}
|
|
82
|
-
if (!
|
|
165
|
+
if (!configuredWallets) {
|
|
83
166
|
throw new Error(
|
|
84
167
|
'Universal Wallet Connector must be initialized with at least one wallet'
|
|
85
168
|
)
|
|
86
169
|
}
|
|
87
170
|
|
|
88
|
-
this.wallets =
|
|
89
|
-
this.usingIntegratedBrowser =
|
|
171
|
+
this.wallets = configuredWallets
|
|
172
|
+
this.usingIntegratedBrowser = configuredUsingIntegratedBrowser
|
|
90
173
|
|
|
91
174
|
// Create RPC map from networks
|
|
92
175
|
this.networkRpcMap = createNetworkRpcMap(networks)
|
|
@@ -96,22 +179,25 @@ export class UniversalWalletConnector {
|
|
|
96
179
|
this.injectedConnector = new InjectedConnector(
|
|
97
180
|
this.networkRpcMap,
|
|
98
181
|
this.wallets,
|
|
99
|
-
|
|
182
|
+
configuredTonConnectConfig
|
|
100
183
|
)
|
|
101
184
|
this.connectors.set('injected', this.injectedConnector)
|
|
102
185
|
|
|
103
|
-
if (
|
|
186
|
+
if (configuredTonConnectConfig) {
|
|
104
187
|
this.connectors.set(
|
|
105
188
|
'tonConnect',
|
|
106
|
-
new TonConnectConnector(
|
|
189
|
+
new TonConnectConnector(configuredTonConnectConfig)
|
|
107
190
|
)
|
|
108
191
|
}
|
|
109
192
|
|
|
110
193
|
// Only add WalletConnect connector if config is provided
|
|
111
|
-
if (
|
|
194
|
+
if (configuredWalletConnectConfig) {
|
|
112
195
|
this.connectors.set(
|
|
113
196
|
'walletConnect',
|
|
114
|
-
new WalletConnectConnector(
|
|
197
|
+
new WalletConnectConnector(
|
|
198
|
+
configuredWalletConnectConfig,
|
|
199
|
+
this.networkRpcMap
|
|
200
|
+
)
|
|
115
201
|
)
|
|
116
202
|
}
|
|
117
203
|
|
|
@@ -122,14 +208,14 @@ export class UniversalWalletConnector {
|
|
|
122
208
|
this.wallets,
|
|
123
209
|
this.sessionManager,
|
|
124
210
|
this.connectors,
|
|
125
|
-
|
|
211
|
+
configuredUsingIntegratedBrowser,
|
|
126
212
|
this.eventManager
|
|
127
213
|
)
|
|
128
214
|
this.networkSwitchService = new NetworkSwitchService(
|
|
129
215
|
networks,
|
|
130
216
|
this.sessionManager,
|
|
131
217
|
this.connectors,
|
|
132
|
-
|
|
218
|
+
configuredUsingIntegratedBrowser,
|
|
133
219
|
this.eventManager
|
|
134
220
|
)
|
|
135
221
|
this.signatureService = new SignatureService(
|
|
@@ -147,6 +233,12 @@ export class UniversalWalletConnector {
|
|
|
147
233
|
this.eventManager
|
|
148
234
|
)
|
|
149
235
|
|
|
236
|
+
// Register as the shared instance so getInstance() works
|
|
237
|
+
// (only set if no instance exists, to avoid overwriting an earlier one)
|
|
238
|
+
if (!UniversalWalletConnector.instance) {
|
|
239
|
+
UniversalWalletConnector.instance = this
|
|
240
|
+
}
|
|
241
|
+
|
|
150
242
|
// Initialize detected wallets after services are created
|
|
151
243
|
this.initializeDetectedWallets()
|
|
152
244
|
}
|
|
@@ -323,12 +415,12 @@ export class UniversalWalletConnector {
|
|
|
323
415
|
// Mark detection as complete
|
|
324
416
|
this.detectionComplete = true
|
|
325
417
|
|
|
326
|
-
|
|
327
|
-
this.eventManager.
|
|
328
|
-
} catch {
|
|
329
|
-
// Silently handle error during initialization
|
|
418
|
+
this.eventManager.emit('walletsDetected', { wallets: this.wallets })
|
|
419
|
+
this.eventManager.emit('ready', undefined)
|
|
420
|
+
} catch (error) {
|
|
330
421
|
this.detectionComplete = true
|
|
331
|
-
this.
|
|
422
|
+
this.emitError(error, 'initialize')
|
|
423
|
+
this.eventManager.emit('ready', undefined)
|
|
332
424
|
}
|
|
333
425
|
}
|
|
334
426
|
|
|
@@ -340,6 +432,32 @@ export class UniversalWalletConnector {
|
|
|
340
432
|
return this.detectionComplete
|
|
341
433
|
}
|
|
342
434
|
|
|
435
|
+
// ---- Event subscription ----
|
|
436
|
+
|
|
437
|
+
/** Subscribe to a typed event. Returns an unsubscribe function. */
|
|
438
|
+
on<K extends UWCEventName>(
|
|
439
|
+
event: K,
|
|
440
|
+
listener: UWCEventListener<K>
|
|
441
|
+
): () => void {
|
|
442
|
+
return this.eventManager.on(event, listener)
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/** Subscribe once; the listener is removed after the first dispatch. */
|
|
446
|
+
once<K extends UWCEventName>(
|
|
447
|
+
event: K,
|
|
448
|
+
listener: UWCEventListener<K>
|
|
449
|
+
): () => void {
|
|
450
|
+
return this.eventManager.once(event, listener)
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
off<K extends UWCEventName>(event: K, listener: UWCEventListener<K>): void {
|
|
454
|
+
this.eventManager.off(event, listener)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* @deprecated Prefer `on(eventName, listener)` for targeted updates.
|
|
459
|
+
* Subscribes to the catch-all `change` event.
|
|
460
|
+
*/
|
|
343
461
|
subscribe(listener: () => void): () => void {
|
|
344
462
|
return this.eventManager.subscribe(listener)
|
|
345
463
|
}
|
|
@@ -361,24 +479,45 @@ export class UniversalWalletConnector {
|
|
|
361
479
|
async connect(
|
|
362
480
|
connectionMode: ConnectionMode,
|
|
363
481
|
walletId: string,
|
|
364
|
-
networkId?: NetworkId
|
|
482
|
+
networkId?: NetworkId,
|
|
483
|
+
options?: OperationOptions
|
|
365
484
|
): Promise<void> {
|
|
366
|
-
|
|
367
|
-
|
|
485
|
+
try {
|
|
486
|
+
await this.connectionService.connect(
|
|
487
|
+
connectionMode,
|
|
488
|
+
walletId,
|
|
489
|
+
networkId,
|
|
490
|
+
options
|
|
491
|
+
)
|
|
492
|
+
} catch (error) {
|
|
493
|
+
this.emitError(error, 'connect')
|
|
494
|
+
throw error
|
|
495
|
+
}
|
|
368
496
|
}
|
|
369
497
|
|
|
370
498
|
getConnectionURI(): string | undefined {
|
|
371
499
|
return this.connectionService.getConnectionURI()
|
|
372
500
|
}
|
|
373
501
|
|
|
374
|
-
async disconnect(): Promise<void> {
|
|
375
|
-
|
|
376
|
-
|
|
502
|
+
async disconnect(options?: OperationOptions): Promise<void> {
|
|
503
|
+
try {
|
|
504
|
+
await this.connectionService.disconnect(options)
|
|
505
|
+
} catch (error) {
|
|
506
|
+
this.emitError(error, 'disconnect')
|
|
507
|
+
throw error
|
|
508
|
+
}
|
|
377
509
|
}
|
|
378
510
|
|
|
379
|
-
async switchNetwork(
|
|
380
|
-
|
|
381
|
-
|
|
511
|
+
async switchNetwork(
|
|
512
|
+
networkId: NetworkId,
|
|
513
|
+
options?: OperationOptions
|
|
514
|
+
): Promise<void> {
|
|
515
|
+
try {
|
|
516
|
+
await this.networkSwitchService.switchNetwork(networkId, options)
|
|
517
|
+
} catch (error) {
|
|
518
|
+
this.emitError(error, 'switchNetwork')
|
|
519
|
+
throw error
|
|
520
|
+
}
|
|
382
521
|
}
|
|
383
522
|
|
|
384
523
|
getNetworkSwitchLoadingState() {
|
|
@@ -388,9 +527,13 @@ export class UniversalWalletConnector {
|
|
|
388
527
|
/**
|
|
389
528
|
* Sign a message with the connected wallet
|
|
390
529
|
* @param message The message to sign
|
|
530
|
+
* @param options Optional cancellation signal
|
|
391
531
|
* @returns A promise that resolves to the signature
|
|
392
532
|
*/
|
|
393
|
-
async signMessage(
|
|
533
|
+
async signMessage(
|
|
534
|
+
message: string,
|
|
535
|
+
options?: OperationOptions
|
|
536
|
+
): Promise<SignatureType> {
|
|
394
537
|
const session = this.sessionManager.getSession()
|
|
395
538
|
|
|
396
539
|
if (!session.activeWallet) {
|
|
@@ -401,32 +544,43 @@ export class UniversalWalletConnector {
|
|
|
401
544
|
throw new Error('No active connection')
|
|
402
545
|
}
|
|
403
546
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
547
|
+
try {
|
|
548
|
+
// Get the provider from the active wallet based on connection mode
|
|
549
|
+
let provider
|
|
550
|
+
if (session.connectionMode === 'injected') {
|
|
551
|
+
provider = this.usingIntegratedBrowser
|
|
552
|
+
? session.activeWallet.integratedBrowserInjectedProvider
|
|
553
|
+
: session.activeWallet.extensionInjectedProvider
|
|
554
|
+
} else if (session.connectionMode === 'walletConnect') {
|
|
555
|
+
provider = session.activeWallet.walletConnectProvider
|
|
556
|
+
} else if (session.connectionMode === 'tonConnect') {
|
|
557
|
+
return await this.signatureService.signMessage(
|
|
558
|
+
message,
|
|
559
|
+
undefined,
|
|
560
|
+
options
|
|
561
|
+
)
|
|
562
|
+
}
|
|
415
563
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
564
|
+
if (!provider) {
|
|
565
|
+
throw new Error('No provider available for the active wallet')
|
|
566
|
+
}
|
|
419
567
|
|
|
420
|
-
|
|
568
|
+
return await this.signatureService.signMessage(message, provider, options)
|
|
569
|
+
} catch (error) {
|
|
570
|
+
this.emitError(error, 'signMessage')
|
|
571
|
+
throw error
|
|
572
|
+
}
|
|
421
573
|
}
|
|
422
574
|
|
|
423
575
|
/**
|
|
424
576
|
* Send a transaction with the connected wallet
|
|
425
577
|
* @param request The transaction request parameters
|
|
578
|
+
* @param options Optional cancellation signal
|
|
426
579
|
* @returns A promise that resolves to the transaction result
|
|
427
580
|
*/
|
|
428
581
|
async sendTransaction(
|
|
429
|
-
request: TransactionRequest
|
|
582
|
+
request: TransactionRequest,
|
|
583
|
+
options?: OperationOptions
|
|
430
584
|
): Promise<TransactionResult> {
|
|
431
585
|
const session = this.sessionManager.getSession()
|
|
432
586
|
|
|
@@ -438,39 +592,60 @@ export class UniversalWalletConnector {
|
|
|
438
592
|
throw new Error('No active connection')
|
|
439
593
|
}
|
|
440
594
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
595
|
+
try {
|
|
596
|
+
// Get the provider from the active wallet based on connection mode
|
|
597
|
+
let provider
|
|
598
|
+
if (session.connectionMode === 'injected') {
|
|
599
|
+
provider = this.usingIntegratedBrowser
|
|
600
|
+
? session.activeWallet.integratedBrowserInjectedProvider
|
|
601
|
+
: session.activeWallet.extensionInjectedProvider
|
|
602
|
+
} else if (session.connectionMode === 'walletConnect') {
|
|
603
|
+
provider = session.activeWallet.walletConnectProvider
|
|
604
|
+
} else if (session.connectionMode === 'tonConnect') {
|
|
605
|
+
return await this.transactionService.sendTransaction(
|
|
606
|
+
request,
|
|
607
|
+
undefined,
|
|
608
|
+
options
|
|
609
|
+
)
|
|
610
|
+
}
|
|
452
611
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
612
|
+
if (!provider) {
|
|
613
|
+
throw new Error('No provider available for the active wallet')
|
|
614
|
+
}
|
|
456
615
|
|
|
457
|
-
|
|
616
|
+
return await this.transactionService.sendTransaction(
|
|
617
|
+
request,
|
|
618
|
+
provider,
|
|
619
|
+
options
|
|
620
|
+
)
|
|
621
|
+
} catch (error) {
|
|
622
|
+
this.emitError(error, 'sendTransaction')
|
|
623
|
+
throw error
|
|
624
|
+
}
|
|
458
625
|
}
|
|
459
626
|
|
|
460
627
|
/**
|
|
461
628
|
* Fetch wallet capabilities for the connected wallet
|
|
462
629
|
* @param address The wallet address to fetch capabilities for
|
|
463
630
|
* @param activeNetwork Optional network to set as the active network for capabilities
|
|
631
|
+
* @param options Optional cancellation signal
|
|
464
632
|
* @returns A promise that resolves when capabilities are fetched and updated
|
|
465
633
|
*/
|
|
466
634
|
async getWalletCapabilities(
|
|
467
635
|
address: string,
|
|
468
|
-
activeNetwork?: Network
|
|
636
|
+
activeNetwork?: Network,
|
|
637
|
+
options?: OperationOptions
|
|
469
638
|
): Promise<void> {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
639
|
+
try {
|
|
640
|
+
return await this.walletCapabilitiesService.getWalletCapabilities(
|
|
641
|
+
address,
|
|
642
|
+
activeNetwork,
|
|
643
|
+
options
|
|
644
|
+
)
|
|
645
|
+
} catch (error) {
|
|
646
|
+
this.emitError(error, 'getWalletCapabilities')
|
|
647
|
+
throw error
|
|
648
|
+
}
|
|
474
649
|
}
|
|
475
650
|
|
|
476
651
|
/**
|
|
@@ -532,4 +707,17 @@ export class UniversalWalletConnector {
|
|
|
532
707
|
const session = this.sessionManager.getSession()
|
|
533
708
|
return session.activeWalletCapabilities
|
|
534
709
|
}
|
|
710
|
+
|
|
711
|
+
// ---- private helpers ----
|
|
712
|
+
|
|
713
|
+
private emitError(error: unknown, operation: UWCOperation): void {
|
|
714
|
+
const walletError: WalletError =
|
|
715
|
+
error instanceof WalletConnectorError
|
|
716
|
+
? { type: error.type, message: error.message }
|
|
717
|
+
: {
|
|
718
|
+
type: 'unknown',
|
|
719
|
+
message: error instanceof Error ? error.message : String(error)
|
|
720
|
+
}
|
|
721
|
+
this.eventManager.emit('error', { error: walletError, operation })
|
|
722
|
+
}
|
|
535
723
|
}
|