@meshconnect/uwc-core 0.7.5-snapshot.c90b3e8 → 0.7.6
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/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/managers/event-manager.d.ts +3 -22
- package/dist/managers/event-manager.d.ts.map +1 -1
- package/dist/managers/event-manager.js +7 -63
- package/dist/managers/event-manager.js.map +1 -1
- package/dist/services/connection-service.d.ts +2 -5
- package/dist/services/connection-service.d.ts.map +1 -1
- package/dist/services/connection-service.js +7 -19
- package/dist/services/connection-service.js.map +1 -1
- package/dist/services/network-switch-service.d.ts +1 -2
- package/dist/services/network-switch-service.d.ts.map +1 -1
- package/dist/services/network-switch-service.js +3 -15
- package/dist/services/network-switch-service.js.map +1 -1
- package/dist/services/signature-service.d.ts +1 -3
- package/dist/services/signature-service.d.ts.map +1 -1
- package/dist/services/signature-service.js +5 -10
- package/dist/services/signature-service.js.map +1 -1
- package/dist/services/transaction-service.d.ts +1 -3
- package/dist/services/transaction-service.d.ts.map +1 -1
- package/dist/services/transaction-service.js +5 -10
- package/dist/services/transaction-service.js.map +1 -1
- package/dist/services/wallet-capabilities-service.d.ts +1 -2
- package/dist/services/wallet-capabilities-service.d.ts.map +1 -1
- package/dist/services/wallet-capabilities-service.js +2 -9
- package/dist/services/wallet-capabilities-service.js.map +1 -1
- package/dist/universal-wallet-connector.d.ts +6 -52
- package/dist/universal-wallet-connector.d.ts.map +1 -1
- package/dist/universal-wallet-connector.js +177 -271
- package/dist/universal-wallet-connector.js.map +1 -1
- package/package.json +5 -5
- package/src/index.ts +3 -11
- package/src/managers/event-manager.test.ts +0 -70
- package/src/managers/event-manager.ts +9 -80
- package/src/services/connection-service.test.ts +3 -11
- package/src/services/connection-service.ts +7 -34
- package/src/services/network-switch-service.ts +3 -22
- package/src/services/signature-service.ts +5 -13
- package/src/services/transaction-service.ts +5 -13
- package/src/services/wallet-capabilities-service.ts +2 -14
- package/src/universal-wallet-connector.test.ts +3 -87
- package/src/universal-wallet-connector.ts +204 -395
- package/README.md +0 -924
- package/dist/events.d.ts +0 -71
- package/dist/events.d.ts.map +0 -1
- package/dist/events.js +0 -2
- package/dist/events.js.map +0 -1
- package/src/events.ts +0 -73
|
@@ -16,10 +16,8 @@ import type {
|
|
|
16
16
|
TransactionResult,
|
|
17
17
|
NetworkRpcMap,
|
|
18
18
|
EVMCapabilities,
|
|
19
|
-
SignatureType
|
|
20
|
-
WalletError
|
|
19
|
+
SignatureType
|
|
21
20
|
} from '@meshconnect/uwc-types'
|
|
22
|
-
import { WalletConnectorError } from '@meshconnect/uwc-types'
|
|
23
21
|
import { InjectedConnector } from '@meshconnect/uwc-injected-connector'
|
|
24
22
|
import { WalletConnectConnector } from '@meshconnect/uwc-wallet-connect-connector'
|
|
25
23
|
import { TonConnectConnector } from '@meshconnect/uwc-ton-connector'
|
|
@@ -31,28 +29,8 @@ import { SignatureService } from './services/signature-service'
|
|
|
31
29
|
import { TransactionService } from './services/transaction-service'
|
|
32
30
|
import { WalletCapabilitiesService } from './services/wallet-capabilities-service'
|
|
33
31
|
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
|
-
}
|
|
53
32
|
|
|
54
33
|
export class UniversalWalletConnector {
|
|
55
|
-
private static instance: UniversalWalletConnector | null = null
|
|
56
34
|
private static instanceCount = 0
|
|
57
35
|
private static hasWarnedAboutMultipleInstances = false
|
|
58
36
|
|
|
@@ -70,78 +48,17 @@ export class UniversalWalletConnector {
|
|
|
70
48
|
private detectionComplete = false
|
|
71
49
|
private networkRpcMap: NetworkRpcMap
|
|
72
50
|
|
|
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)
|
|
98
51
|
constructor(
|
|
99
52
|
networks: Network[],
|
|
100
|
-
wallets?: WalletMetadata[],
|
|
101
|
-
usingIntegratedBrowser?: boolean,
|
|
102
|
-
walletConnectConfig?: WalletConnectConfig,
|
|
103
|
-
tonConnectConfig?: TonConnectConfig
|
|
104
|
-
)
|
|
105
|
-
constructor(
|
|
106
|
-
networksOrConfig: Network[] | UWCConfig,
|
|
107
53
|
wallets: WalletMetadata[] = [],
|
|
108
54
|
usingIntegratedBrowser = false,
|
|
109
55
|
walletConnectConfig?: WalletConnectConfig,
|
|
110
56
|
tonConnectConfig?: TonConnectConfig
|
|
111
57
|
) {
|
|
112
|
-
|
|
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
|
|
142
|
-
|
|
143
|
-
// Track instance creation and warn on duplicates
|
|
58
|
+
// Track instance creation
|
|
144
59
|
UniversalWalletConnector.instanceCount++
|
|
60
|
+
|
|
61
|
+
// Warn about multiple instances
|
|
145
62
|
if (
|
|
146
63
|
UniversalWalletConnector.instanceCount > 1 &&
|
|
147
64
|
!UniversalWalletConnector.hasWarnedAboutMultipleInstances
|
|
@@ -151,7 +68,7 @@ export class UniversalWalletConnector {
|
|
|
151
68
|
`⚠️ WARNING: Multiple instances of UniversalWalletConnector detected (${UniversalWalletConnector.instanceCount} instances). ` +
|
|
152
69
|
'This can lead to state inconsistencies and unexpected behavior. ' +
|
|
153
70
|
'Please ensure you create only one instance and reuse it throughout your application. ' +
|
|
154
|
-
'
|
|
71
|
+
'Consider using a singleton pattern or a context provider. ' +
|
|
155
72
|
'You can ignore this warning if you are using React Strict Mode, which intentionally mounts components twice in development to help identify side effects.'
|
|
156
73
|
)
|
|
157
74
|
UniversalWalletConnector.hasWarnedAboutMultipleInstances = true
|
|
@@ -162,14 +79,14 @@ export class UniversalWalletConnector {
|
|
|
162
79
|
'Universal Wallet Connector must be initialized with at least one network'
|
|
163
80
|
)
|
|
164
81
|
}
|
|
165
|
-
if (!
|
|
82
|
+
if (!wallets) {
|
|
166
83
|
throw new Error(
|
|
167
84
|
'Universal Wallet Connector must be initialized with at least one wallet'
|
|
168
85
|
)
|
|
169
86
|
}
|
|
170
87
|
|
|
171
|
-
this.wallets =
|
|
172
|
-
this.usingIntegratedBrowser =
|
|
88
|
+
this.wallets = wallets
|
|
89
|
+
this.usingIntegratedBrowser = usingIntegratedBrowser
|
|
173
90
|
|
|
174
91
|
// Create RPC map from networks
|
|
175
92
|
this.networkRpcMap = createNetworkRpcMap(networks)
|
|
@@ -179,25 +96,22 @@ export class UniversalWalletConnector {
|
|
|
179
96
|
this.injectedConnector = new InjectedConnector(
|
|
180
97
|
this.networkRpcMap,
|
|
181
98
|
this.wallets,
|
|
182
|
-
|
|
99
|
+
tonConnectConfig
|
|
183
100
|
)
|
|
184
101
|
this.connectors.set('injected', this.injectedConnector)
|
|
185
102
|
|
|
186
|
-
if (
|
|
103
|
+
if (tonConnectConfig) {
|
|
187
104
|
this.connectors.set(
|
|
188
105
|
'tonConnect',
|
|
189
|
-
new TonConnectConnector(
|
|
106
|
+
new TonConnectConnector(tonConnectConfig)
|
|
190
107
|
)
|
|
191
108
|
}
|
|
192
109
|
|
|
193
110
|
// Only add WalletConnect connector if config is provided
|
|
194
|
-
if (
|
|
111
|
+
if (walletConnectConfig) {
|
|
195
112
|
this.connectors.set(
|
|
196
113
|
'walletConnect',
|
|
197
|
-
new WalletConnectConnector(
|
|
198
|
-
configuredWalletConnectConfig,
|
|
199
|
-
this.networkRpcMap
|
|
200
|
-
)
|
|
114
|
+
new WalletConnectConnector(walletConnectConfig, this.networkRpcMap)
|
|
201
115
|
)
|
|
202
116
|
}
|
|
203
117
|
|
|
@@ -208,14 +122,14 @@ export class UniversalWalletConnector {
|
|
|
208
122
|
this.wallets,
|
|
209
123
|
this.sessionManager,
|
|
210
124
|
this.connectors,
|
|
211
|
-
|
|
125
|
+
usingIntegratedBrowser,
|
|
212
126
|
this.eventManager
|
|
213
127
|
)
|
|
214
128
|
this.networkSwitchService = new NetworkSwitchService(
|
|
215
129
|
networks,
|
|
216
130
|
this.sessionManager,
|
|
217
131
|
this.connectors,
|
|
218
|
-
|
|
132
|
+
usingIntegratedBrowser,
|
|
219
133
|
this.eventManager
|
|
220
134
|
)
|
|
221
135
|
this.signatureService = new SignatureService(
|
|
@@ -233,12 +147,6 @@ export class UniversalWalletConnector {
|
|
|
233
147
|
this.eventManager
|
|
234
148
|
)
|
|
235
149
|
|
|
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
|
-
|
|
242
150
|
// Initialize detected wallets after services are created
|
|
243
151
|
this.initializeDetectedWallets()
|
|
244
152
|
}
|
|
@@ -263,35 +171,151 @@ export class UniversalWalletConnector {
|
|
|
263
171
|
}
|
|
264
172
|
})
|
|
265
173
|
|
|
266
|
-
//
|
|
267
|
-
// The namespace loop used to be sequential and `await`-ed each call,
|
|
268
|
-
// which meant a 100ms EIP-6963 native timeout + any bridge polling
|
|
269
|
-
// added up. With Promise.all the total time is the slowest single
|
|
270
|
-
// call, not the sum.
|
|
271
|
-
const detectionTasks: Promise<void>[] = []
|
|
174
|
+
// Check available wallets for each namespace across all connectors
|
|
272
175
|
for (const namespace of namespaces) {
|
|
273
176
|
for (const [, connector] of this.connectors) {
|
|
274
|
-
if
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
.
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
this.wallets
|
|
281
|
-
)
|
|
177
|
+
// Check if connector supports getAvailableWallets
|
|
178
|
+
if (typeof connector.getAvailableWallets === 'function') {
|
|
179
|
+
try {
|
|
180
|
+
const detectedWallets = await connector.getAvailableWallets(
|
|
181
|
+
namespace as Namespace,
|
|
182
|
+
this.wallets
|
|
282
183
|
)
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
184
|
+
|
|
185
|
+
// Update wallets with detected information
|
|
186
|
+
detectedWallets.forEach(detected => {
|
|
187
|
+
// Find matching wallet based on namespace-specific naming
|
|
188
|
+
let wallet: WalletMetadata | undefined
|
|
189
|
+
|
|
190
|
+
if (namespace === 'eip155') {
|
|
191
|
+
// For EIP155, match by eip155Name
|
|
192
|
+
wallet = this.wallets.find(w => {
|
|
193
|
+
const provider = this.usingIntegratedBrowser
|
|
194
|
+
? w.integratedBrowserInjectedProvider
|
|
195
|
+
: w.extensionInjectedProvider
|
|
196
|
+
return (
|
|
197
|
+
provider?.namespaceMetaData?.eip155?.eip155Name?.toLowerCase() ===
|
|
198
|
+
detected.name.toLowerCase()
|
|
199
|
+
)
|
|
200
|
+
})
|
|
201
|
+
} else if (namespace === 'solana') {
|
|
202
|
+
// For Solana, match by walletStandardName
|
|
203
|
+
wallet = this.wallets.find(w => {
|
|
204
|
+
const provider = this.usingIntegratedBrowser
|
|
205
|
+
? w.integratedBrowserInjectedProvider
|
|
206
|
+
: w.extensionInjectedProvider
|
|
207
|
+
return (
|
|
208
|
+
provider?.namespaceMetaData?.solana?.walletStandardName?.toLowerCase() ===
|
|
209
|
+
detected.name.toLowerCase()
|
|
210
|
+
)
|
|
211
|
+
})
|
|
212
|
+
} else if (namespace === 'tron') {
|
|
213
|
+
// For Tron, match by injectedId path prefix
|
|
214
|
+
const tronDetected = detected as DetectedTronWalletInfo
|
|
215
|
+
wallet = this.wallets.find(w => {
|
|
216
|
+
const provider = this.usingIntegratedBrowser
|
|
217
|
+
? w.integratedBrowserInjectedProvider
|
|
218
|
+
: w.extensionInjectedProvider
|
|
219
|
+
const injectedId =
|
|
220
|
+
provider?.namespaceMetaData?.tron?.injectedId
|
|
221
|
+
return (
|
|
222
|
+
injectedId &&
|
|
223
|
+
tronDetected.uuid ===
|
|
224
|
+
`tron-${injectedId}`.toLowerCase().replace(/\./g, '-')
|
|
225
|
+
)
|
|
226
|
+
})
|
|
227
|
+
} else if (namespace === 'tvm') {
|
|
228
|
+
// For TON, match by jsBridgeKey
|
|
229
|
+
const tonDetected = detected as DetectedTonWalletInfo
|
|
230
|
+
wallet = this.wallets.find(w => {
|
|
231
|
+
const provider = this.usingIntegratedBrowser
|
|
232
|
+
? w.integratedBrowserInjectedProvider
|
|
233
|
+
: w.extensionInjectedProvider
|
|
234
|
+
return (
|
|
235
|
+
provider?.namespaceMetaData?.tvm?.jsBridgeKey ===
|
|
236
|
+
tonDetected.jsBridgeKey
|
|
237
|
+
)
|
|
238
|
+
})
|
|
239
|
+
} else {
|
|
240
|
+
// For other namespaces, fall back to wallet name
|
|
241
|
+
wallet = this.wallets.find(
|
|
242
|
+
w => w.name.toLowerCase() === detected.name.toLowerCase()
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (wallet) {
|
|
247
|
+
// Determine which provider to update based on usingIntegratedBrowser
|
|
248
|
+
const provider = this.usingIntegratedBrowser
|
|
249
|
+
? wallet.integratedBrowserInjectedProvider
|
|
250
|
+
: wallet.extensionInjectedProvider
|
|
251
|
+
|
|
252
|
+
// Update the appropriate namespace metadata
|
|
253
|
+
if (provider?.namespaceMetaData) {
|
|
254
|
+
const nsMetadata =
|
|
255
|
+
provider.namespaceMetaData[namespace as Namespace]
|
|
256
|
+
if (nsMetadata && namespace === 'eip155') {
|
|
257
|
+
// For EIP155, we have specific fields
|
|
258
|
+
const eip155Metadata = nsMetadata as {
|
|
259
|
+
installed?: boolean
|
|
260
|
+
detectedWallet?: DetectedEIP6963WalletInfo
|
|
261
|
+
}
|
|
262
|
+
eip155Metadata.installed = true
|
|
263
|
+
const eip155Detected =
|
|
264
|
+
detected as DetectedEIP6963WalletInfo
|
|
265
|
+
eip155Metadata.detectedWallet = {
|
|
266
|
+
uuid: eip155Detected.uuid,
|
|
267
|
+
name: eip155Detected.name,
|
|
268
|
+
icon: eip155Detected.icon,
|
|
269
|
+
rdns: eip155Detected.rdns
|
|
270
|
+
}
|
|
271
|
+
} else if (namespace === 'solana') {
|
|
272
|
+
// For Solana, we have different fields
|
|
273
|
+
const solanaMetadata = nsMetadata as {
|
|
274
|
+
installed?: boolean
|
|
275
|
+
detectedWallet?: DetectedSolanaWalletInfo
|
|
276
|
+
}
|
|
277
|
+
solanaMetadata.installed = true
|
|
278
|
+
const solanaDetected =
|
|
279
|
+
detected as DetectedSolanaWalletInfo
|
|
280
|
+
solanaMetadata.detectedWallet = {
|
|
281
|
+
uuid: solanaDetected.uuid,
|
|
282
|
+
name: solanaDetected.name,
|
|
283
|
+
features: solanaDetected.features
|
|
284
|
+
}
|
|
285
|
+
} else if (namespace === 'tron') {
|
|
286
|
+
const tronMetadata = nsMetadata as {
|
|
287
|
+
installed?: boolean
|
|
288
|
+
detectedWallet?: DetectedTronWalletInfo
|
|
289
|
+
}
|
|
290
|
+
tronMetadata.installed = true
|
|
291
|
+
const tronDetected = detected as DetectedTronWalletInfo
|
|
292
|
+
tronMetadata.detectedWallet = {
|
|
293
|
+
uuid: tronDetected.uuid,
|
|
294
|
+
name: tronDetected.name
|
|
295
|
+
}
|
|
296
|
+
} else if (namespace === 'tvm') {
|
|
297
|
+
const tonMetadata = nsMetadata as {
|
|
298
|
+
installed?: boolean
|
|
299
|
+
detectedWallet?: DetectedTonWalletInfo
|
|
300
|
+
}
|
|
301
|
+
tonMetadata.installed = true
|
|
302
|
+
const tonDetected = detected as DetectedTonWalletInfo
|
|
303
|
+
tonMetadata.detectedWallet = {
|
|
304
|
+
uuid: tonDetected.uuid,
|
|
305
|
+
name: tonDetected.name,
|
|
306
|
+
icon: tonDetected.icon,
|
|
307
|
+
jsBridgeKey: tonDetected.jsBridgeKey
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
286
311
|
}
|
|
287
312
|
})
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
313
|
+
} catch {
|
|
314
|
+
// Silently handle errors for individual connector/namespace combinations
|
|
315
|
+
}
|
|
316
|
+
}
|
|
292
317
|
}
|
|
293
318
|
}
|
|
294
|
-
await Promise.all(detectionTasks)
|
|
295
319
|
|
|
296
320
|
// Notify the connection service to update its internal wallets reference
|
|
297
321
|
this.connectionService.updateWallets(this.wallets)
|
|
@@ -299,131 +323,12 @@ export class UniversalWalletConnector {
|
|
|
299
323
|
// Mark detection as complete
|
|
300
324
|
this.detectionComplete = true
|
|
301
325
|
|
|
302
|
-
|
|
303
|
-
this.eventManager.
|
|
304
|
-
} catch
|
|
326
|
+
// Notify listeners about the update
|
|
327
|
+
this.eventManager.notify()
|
|
328
|
+
} catch {
|
|
329
|
+
// Silently handle error during initialization
|
|
305
330
|
this.detectionComplete = true
|
|
306
|
-
this.
|
|
307
|
-
this.eventManager.emit('ready', undefined)
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Merge a single detected wallet (from one namespace × connector run) into
|
|
313
|
-
* the configured wallet metadata. Factored out so detection tasks can run
|
|
314
|
-
* in parallel without racing on the merge logic.
|
|
315
|
-
*/
|
|
316
|
-
private applyDetectedWallet(
|
|
317
|
-
namespace: Namespace,
|
|
318
|
-
detected: {
|
|
319
|
-
uuid: string
|
|
320
|
-
name: string
|
|
321
|
-
icon?: string
|
|
322
|
-
rdns?: string
|
|
323
|
-
features?: string[]
|
|
324
|
-
jsBridgeKey?: string
|
|
325
|
-
}
|
|
326
|
-
): void {
|
|
327
|
-
let wallet: WalletMetadata | undefined
|
|
328
|
-
|
|
329
|
-
const pickProvider = (w: WalletMetadata) =>
|
|
330
|
-
this.usingIntegratedBrowser
|
|
331
|
-
? w.integratedBrowserInjectedProvider
|
|
332
|
-
: w.extensionInjectedProvider
|
|
333
|
-
|
|
334
|
-
if (namespace === 'eip155') {
|
|
335
|
-
wallet = this.wallets.find(
|
|
336
|
-
w =>
|
|
337
|
-
pickProvider(
|
|
338
|
-
w
|
|
339
|
-
)?.namespaceMetaData?.eip155?.eip155Name?.toLowerCase() ===
|
|
340
|
-
detected.name.toLowerCase()
|
|
341
|
-
)
|
|
342
|
-
} else if (namespace === 'solana') {
|
|
343
|
-
wallet = this.wallets.find(
|
|
344
|
-
w =>
|
|
345
|
-
pickProvider(
|
|
346
|
-
w
|
|
347
|
-
)?.namespaceMetaData?.solana?.walletStandardName?.toLowerCase() ===
|
|
348
|
-
detected.name.toLowerCase()
|
|
349
|
-
)
|
|
350
|
-
} else if (namespace === 'tron') {
|
|
351
|
-
const tronDetected = detected as DetectedTronWalletInfo
|
|
352
|
-
wallet = this.wallets.find(w => {
|
|
353
|
-
const injectedId = pickProvider(w)?.namespaceMetaData?.tron?.injectedId
|
|
354
|
-
return (
|
|
355
|
-
injectedId &&
|
|
356
|
-
tronDetected.uuid ===
|
|
357
|
-
`tron-${injectedId}`.toLowerCase().replace(/\./g, '-')
|
|
358
|
-
)
|
|
359
|
-
})
|
|
360
|
-
} else if (namespace === 'tvm') {
|
|
361
|
-
const tonDetected = detected as DetectedTonWalletInfo
|
|
362
|
-
wallet = this.wallets.find(
|
|
363
|
-
w =>
|
|
364
|
-
pickProvider(w)?.namespaceMetaData?.tvm?.jsBridgeKey ===
|
|
365
|
-
tonDetected.jsBridgeKey
|
|
366
|
-
)
|
|
367
|
-
} else {
|
|
368
|
-
wallet = this.wallets.find(
|
|
369
|
-
w => w.name.toLowerCase() === detected.name.toLowerCase()
|
|
370
|
-
)
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (!wallet) return
|
|
374
|
-
|
|
375
|
-
const provider = pickProvider(wallet)
|
|
376
|
-
if (!provider?.namespaceMetaData) return
|
|
377
|
-
|
|
378
|
-
const nsMetadata = provider.namespaceMetaData[namespace]
|
|
379
|
-
if (!nsMetadata) return
|
|
380
|
-
|
|
381
|
-
if (namespace === 'eip155') {
|
|
382
|
-
const m = nsMetadata as {
|
|
383
|
-
installed?: boolean
|
|
384
|
-
detectedWallet?: DetectedEIP6963WalletInfo
|
|
385
|
-
}
|
|
386
|
-
const d = detected as DetectedEIP6963WalletInfo
|
|
387
|
-
m.installed = true
|
|
388
|
-
m.detectedWallet = {
|
|
389
|
-
uuid: d.uuid,
|
|
390
|
-
name: d.name,
|
|
391
|
-
icon: d.icon,
|
|
392
|
-
rdns: d.rdns
|
|
393
|
-
}
|
|
394
|
-
} else if (namespace === 'solana') {
|
|
395
|
-
const m = nsMetadata as {
|
|
396
|
-
installed?: boolean
|
|
397
|
-
detectedWallet?: DetectedSolanaWalletInfo
|
|
398
|
-
}
|
|
399
|
-
const d = detected as DetectedSolanaWalletInfo
|
|
400
|
-
m.installed = true
|
|
401
|
-
m.detectedWallet = {
|
|
402
|
-
uuid: d.uuid,
|
|
403
|
-
name: d.name,
|
|
404
|
-
features: d.features
|
|
405
|
-
}
|
|
406
|
-
} else if (namespace === 'tron') {
|
|
407
|
-
const m = nsMetadata as {
|
|
408
|
-
installed?: boolean
|
|
409
|
-
detectedWallet?: DetectedTronWalletInfo
|
|
410
|
-
}
|
|
411
|
-
const d = detected as DetectedTronWalletInfo
|
|
412
|
-
m.installed = true
|
|
413
|
-
m.detectedWallet = { uuid: d.uuid, name: d.name }
|
|
414
|
-
} else if (namespace === 'tvm') {
|
|
415
|
-
const m = nsMetadata as {
|
|
416
|
-
installed?: boolean
|
|
417
|
-
detectedWallet?: DetectedTonWalletInfo
|
|
418
|
-
}
|
|
419
|
-
const d = detected as DetectedTonWalletInfo
|
|
420
|
-
m.installed = true
|
|
421
|
-
m.detectedWallet = {
|
|
422
|
-
uuid: d.uuid,
|
|
423
|
-
name: d.name,
|
|
424
|
-
icon: d.icon,
|
|
425
|
-
jsBridgeKey: d.jsBridgeKey
|
|
426
|
-
}
|
|
331
|
+
this.eventManager.notify()
|
|
427
332
|
}
|
|
428
333
|
}
|
|
429
334
|
|
|
@@ -435,32 +340,6 @@ export class UniversalWalletConnector {
|
|
|
435
340
|
return this.detectionComplete
|
|
436
341
|
}
|
|
437
342
|
|
|
438
|
-
// ---- Event subscription ----
|
|
439
|
-
|
|
440
|
-
/** Subscribe to a typed event. Returns an unsubscribe function. */
|
|
441
|
-
on<K extends UWCEventName>(
|
|
442
|
-
event: K,
|
|
443
|
-
listener: UWCEventListener<K>
|
|
444
|
-
): () => void {
|
|
445
|
-
return this.eventManager.on(event, listener)
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
/** Subscribe once; the listener is removed after the first dispatch. */
|
|
449
|
-
once<K extends UWCEventName>(
|
|
450
|
-
event: K,
|
|
451
|
-
listener: UWCEventListener<K>
|
|
452
|
-
): () => void {
|
|
453
|
-
return this.eventManager.once(event, listener)
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
off<K extends UWCEventName>(event: K, listener: UWCEventListener<K>): void {
|
|
457
|
-
this.eventManager.off(event, listener)
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
/**
|
|
461
|
-
* @deprecated Prefer `on(eventName, listener)` for targeted updates.
|
|
462
|
-
* Subscribes to the catch-all `change` event.
|
|
463
|
-
*/
|
|
464
343
|
subscribe(listener: () => void): () => void {
|
|
465
344
|
return this.eventManager.subscribe(listener)
|
|
466
345
|
}
|
|
@@ -482,45 +361,24 @@ export class UniversalWalletConnector {
|
|
|
482
361
|
async connect(
|
|
483
362
|
connectionMode: ConnectionMode,
|
|
484
363
|
walletId: string,
|
|
485
|
-
networkId?: NetworkId
|
|
486
|
-
options?: OperationOptions
|
|
364
|
+
networkId?: NetworkId
|
|
487
365
|
): Promise<void> {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
connectionMode,
|
|
491
|
-
walletId,
|
|
492
|
-
networkId,
|
|
493
|
-
options
|
|
494
|
-
)
|
|
495
|
-
} catch (error) {
|
|
496
|
-
this.emitError(error, 'connect')
|
|
497
|
-
throw error
|
|
498
|
-
}
|
|
366
|
+
await this.connectionService.connect(connectionMode, walletId, networkId)
|
|
367
|
+
this.eventManager.notify()
|
|
499
368
|
}
|
|
500
369
|
|
|
501
370
|
getConnectionURI(): string | undefined {
|
|
502
371
|
return this.connectionService.getConnectionURI()
|
|
503
372
|
}
|
|
504
373
|
|
|
505
|
-
async disconnect(
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
} catch (error) {
|
|
509
|
-
this.emitError(error, 'disconnect')
|
|
510
|
-
throw error
|
|
511
|
-
}
|
|
374
|
+
async disconnect(): Promise<void> {
|
|
375
|
+
await this.connectionService.disconnect()
|
|
376
|
+
this.eventManager.notify()
|
|
512
377
|
}
|
|
513
378
|
|
|
514
|
-
async switchNetwork(
|
|
515
|
-
networkId
|
|
516
|
-
|
|
517
|
-
): Promise<void> {
|
|
518
|
-
try {
|
|
519
|
-
await this.networkSwitchService.switchNetwork(networkId, options)
|
|
520
|
-
} catch (error) {
|
|
521
|
-
this.emitError(error, 'switchNetwork')
|
|
522
|
-
throw error
|
|
523
|
-
}
|
|
379
|
+
async switchNetwork(networkId: NetworkId): Promise<void> {
|
|
380
|
+
await this.networkSwitchService.switchNetwork(networkId)
|
|
381
|
+
this.eventManager.notify()
|
|
524
382
|
}
|
|
525
383
|
|
|
526
384
|
getNetworkSwitchLoadingState() {
|
|
@@ -530,13 +388,9 @@ export class UniversalWalletConnector {
|
|
|
530
388
|
/**
|
|
531
389
|
* Sign a message with the connected wallet
|
|
532
390
|
* @param message The message to sign
|
|
533
|
-
* @param options Optional cancellation signal
|
|
534
391
|
* @returns A promise that resolves to the signature
|
|
535
392
|
*/
|
|
536
|
-
async signMessage(
|
|
537
|
-
message: string,
|
|
538
|
-
options?: OperationOptions
|
|
539
|
-
): Promise<SignatureType> {
|
|
393
|
+
async signMessage(message: string): Promise<SignatureType> {
|
|
540
394
|
const session = this.sessionManager.getSession()
|
|
541
395
|
|
|
542
396
|
if (!session.activeWallet) {
|
|
@@ -547,43 +401,32 @@ export class UniversalWalletConnector {
|
|
|
547
401
|
throw new Error('No active connection')
|
|
548
402
|
}
|
|
549
403
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
message,
|
|
562
|
-
undefined,
|
|
563
|
-
options
|
|
564
|
-
)
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
if (!provider) {
|
|
568
|
-
throw new Error('No provider available for the active wallet')
|
|
569
|
-
}
|
|
404
|
+
// Get the provider from the active wallet based on connection mode
|
|
405
|
+
let provider
|
|
406
|
+
if (session.connectionMode === 'injected') {
|
|
407
|
+
provider = this.usingIntegratedBrowser
|
|
408
|
+
? session.activeWallet.integratedBrowserInjectedProvider
|
|
409
|
+
: session.activeWallet.extensionInjectedProvider
|
|
410
|
+
} else if (session.connectionMode === 'walletConnect') {
|
|
411
|
+
provider = session.activeWallet.walletConnectProvider
|
|
412
|
+
} else if (session.connectionMode === 'tonConnect') {
|
|
413
|
+
return await this.signatureService.signMessage(message)
|
|
414
|
+
}
|
|
570
415
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
this.emitError(error, 'signMessage')
|
|
574
|
-
throw error
|
|
416
|
+
if (!provider) {
|
|
417
|
+
throw new Error('No provider available for the active wallet')
|
|
575
418
|
}
|
|
419
|
+
|
|
420
|
+
return await this.signatureService.signMessage(message, provider)
|
|
576
421
|
}
|
|
577
422
|
|
|
578
423
|
/**
|
|
579
424
|
* Send a transaction with the connected wallet
|
|
580
425
|
* @param request The transaction request parameters
|
|
581
|
-
* @param options Optional cancellation signal
|
|
582
426
|
* @returns A promise that resolves to the transaction result
|
|
583
427
|
*/
|
|
584
428
|
async sendTransaction(
|
|
585
|
-
request: TransactionRequest
|
|
586
|
-
options?: OperationOptions
|
|
429
|
+
request: TransactionRequest
|
|
587
430
|
): Promise<TransactionResult> {
|
|
588
431
|
const session = this.sessionManager.getSession()
|
|
589
432
|
|
|
@@ -595,60 +438,39 @@ export class UniversalWalletConnector {
|
|
|
595
438
|
throw new Error('No active connection')
|
|
596
439
|
}
|
|
597
440
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
request,
|
|
610
|
-
undefined,
|
|
611
|
-
options
|
|
612
|
-
)
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
if (!provider) {
|
|
616
|
-
throw new Error('No provider available for the active wallet')
|
|
617
|
-
}
|
|
441
|
+
// Get the provider from the active wallet based on connection mode
|
|
442
|
+
let provider
|
|
443
|
+
if (session.connectionMode === 'injected') {
|
|
444
|
+
provider = this.usingIntegratedBrowser
|
|
445
|
+
? session.activeWallet.integratedBrowserInjectedProvider
|
|
446
|
+
: session.activeWallet.extensionInjectedProvider
|
|
447
|
+
} else if (session.connectionMode === 'walletConnect') {
|
|
448
|
+
provider = session.activeWallet.walletConnectProvider
|
|
449
|
+
} else if (session.connectionMode === 'tonConnect') {
|
|
450
|
+
return await this.transactionService.sendTransaction(request)
|
|
451
|
+
}
|
|
618
452
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
provider,
|
|
622
|
-
options
|
|
623
|
-
)
|
|
624
|
-
} catch (error) {
|
|
625
|
-
this.emitError(error, 'sendTransaction')
|
|
626
|
-
throw error
|
|
453
|
+
if (!provider) {
|
|
454
|
+
throw new Error('No provider available for the active wallet')
|
|
627
455
|
}
|
|
456
|
+
|
|
457
|
+
return await this.transactionService.sendTransaction(request, provider)
|
|
628
458
|
}
|
|
629
459
|
|
|
630
460
|
/**
|
|
631
461
|
* Fetch wallet capabilities for the connected wallet
|
|
632
462
|
* @param address The wallet address to fetch capabilities for
|
|
633
463
|
* @param activeNetwork Optional network to set as the active network for capabilities
|
|
634
|
-
* @param options Optional cancellation signal
|
|
635
464
|
* @returns A promise that resolves when capabilities are fetched and updated
|
|
636
465
|
*/
|
|
637
466
|
async getWalletCapabilities(
|
|
638
467
|
address: string,
|
|
639
|
-
activeNetwork?: Network
|
|
640
|
-
options?: OperationOptions
|
|
468
|
+
activeNetwork?: Network
|
|
641
469
|
): Promise<void> {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
options
|
|
647
|
-
)
|
|
648
|
-
} catch (error) {
|
|
649
|
-
this.emitError(error, 'getWalletCapabilities')
|
|
650
|
-
throw error
|
|
651
|
-
}
|
|
470
|
+
return await this.walletCapabilitiesService.getWalletCapabilities(
|
|
471
|
+
address,
|
|
472
|
+
activeNetwork
|
|
473
|
+
)
|
|
652
474
|
}
|
|
653
475
|
|
|
654
476
|
/**
|
|
@@ -710,17 +532,4 @@ export class UniversalWalletConnector {
|
|
|
710
532
|
const session = this.sessionManager.getSession()
|
|
711
533
|
return session.activeWalletCapabilities
|
|
712
534
|
}
|
|
713
|
-
|
|
714
|
-
// ---- private helpers ----
|
|
715
|
-
|
|
716
|
-
private emitError(error: unknown, operation: UWCOperation): void {
|
|
717
|
-
const walletError: WalletError =
|
|
718
|
-
error instanceof WalletConnectorError
|
|
719
|
-
? { type: error.type, message: error.message }
|
|
720
|
-
: {
|
|
721
|
-
type: 'unknown',
|
|
722
|
-
message: error instanceof Error ? error.message : String(error)
|
|
723
|
-
}
|
|
724
|
-
this.eventManager.emit('error', { error: walletError, operation })
|
|
725
|
-
}
|
|
726
535
|
}
|