@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meshconnect/uwc-core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.6",
|
|
4
4
|
"description": "Core functionality for Universal Wallet Connector",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
"src"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@meshconnect/uwc-
|
|
20
|
-
"@meshconnect/uwc-
|
|
21
|
-
"@meshconnect/uwc-
|
|
22
|
-
"@meshconnect/uwc-
|
|
19
|
+
"@meshconnect/uwc-injected-connector": "0.10.5",
|
|
20
|
+
"@meshconnect/uwc-ton-connector": "0.5.3",
|
|
21
|
+
"@meshconnect/uwc-types": "0.11.1",
|
|
22
|
+
"@meshconnect/uwc-wallet-connect-connector": "0.4.14"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"typescript": "^5.9.3"
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
type OperationOptions
|
|
5
|
-
} from './universal-wallet-connector'
|
|
6
|
-
export type {
|
|
7
|
-
UWCEventMap,
|
|
8
|
-
UWCEventName,
|
|
9
|
-
UWCEventListener,
|
|
10
|
-
UWCOperation
|
|
11
|
-
} from './events'
|
|
1
|
+
export * from './universal-wallet-connector'
|
|
2
|
+
export * from './managers'
|
|
3
|
+
export * from './services'
|
|
@@ -71,74 +71,4 @@ describe('EventManager', () => {
|
|
|
71
71
|
eventManager.clearAllListeners()
|
|
72
72
|
expect(eventManager.getListenerCount()).toBe(0)
|
|
73
73
|
})
|
|
74
|
-
|
|
75
|
-
describe('typed events', () => {
|
|
76
|
-
it('dispatches typed event data only to on() listeners of that event', () => {
|
|
77
|
-
const disconnected: unknown[] = []
|
|
78
|
-
const networkSwitched: unknown[] = []
|
|
79
|
-
|
|
80
|
-
eventManager.on('disconnected', data => disconnected.push(data))
|
|
81
|
-
eventManager.on('networkSwitched', data => networkSwitched.push(data))
|
|
82
|
-
|
|
83
|
-
eventManager.emit('disconnected', undefined)
|
|
84
|
-
|
|
85
|
-
expect(disconnected).toHaveLength(1)
|
|
86
|
-
expect(networkSwitched).toHaveLength(0)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('cascades every typed event to the legacy change channel', () => {
|
|
90
|
-
let changeCount = 0
|
|
91
|
-
eventManager.subscribe(() => {
|
|
92
|
-
changeCount++
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
eventManager.emit('connectionUri', {
|
|
96
|
-
uri: 'wc://x',
|
|
97
|
-
connectionMode: 'walletConnect'
|
|
98
|
-
})
|
|
99
|
-
eventManager.emit('disconnected', undefined)
|
|
100
|
-
|
|
101
|
-
expect(changeCount).toBe(2)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it('off() removes a listener from the typed set', () => {
|
|
105
|
-
const calls: unknown[] = []
|
|
106
|
-
const listener = (d: unknown) => calls.push(d)
|
|
107
|
-
eventManager.on('ready', listener)
|
|
108
|
-
eventManager.off('ready', listener)
|
|
109
|
-
eventManager.emit('ready', undefined)
|
|
110
|
-
expect(calls).toHaveLength(0)
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('once() removes the listener after a single dispatch', () => {
|
|
114
|
-
let calls = 0
|
|
115
|
-
eventManager.once('ready', () => {
|
|
116
|
-
calls++
|
|
117
|
-
})
|
|
118
|
-
eventManager.emit('ready', undefined)
|
|
119
|
-
eventManager.emit('ready', undefined)
|
|
120
|
-
expect(calls).toBe(1)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it('a throwing listener does not stop other listeners', () => {
|
|
124
|
-
const calls: string[] = []
|
|
125
|
-
eventManager.on('ready', () => {
|
|
126
|
-
throw new Error('boom')
|
|
127
|
-
})
|
|
128
|
-
eventManager.on('ready', () => {
|
|
129
|
-
calls.push('second')
|
|
130
|
-
})
|
|
131
|
-
eventManager.emit('ready', undefined)
|
|
132
|
-
expect(calls).toEqual(['second'])
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
it('emit("change") does not recurse into itself', () => {
|
|
136
|
-
let count = 0
|
|
137
|
-
eventManager.on('change', () => {
|
|
138
|
-
count++
|
|
139
|
-
})
|
|
140
|
-
eventManager.emit('change', undefined)
|
|
141
|
-
expect(count).toBe(1)
|
|
142
|
-
})
|
|
143
|
-
})
|
|
144
74
|
})
|
|
@@ -1,93 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
type Listener = () => void
|
|
2
|
+
type Unsubscribe = () => void
|
|
2
3
|
|
|
3
|
-
type LegacyListener = () => void
|
|
4
|
-
type UntypedListener = (data: unknown) => void
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Typed event emitter used by UniversalWalletConnector.
|
|
8
|
-
*
|
|
9
|
-
* Each event has its own listener set. Emitting any typed event also
|
|
10
|
-
* dispatches the legacy `change` event, so `subscribe()` callers keep
|
|
11
|
-
* receiving a notification on every state change.
|
|
12
|
-
*/
|
|
13
4
|
export class EventManager {
|
|
14
|
-
private listeners:
|
|
15
|
-
|
|
16
|
-
/** Subscribe to a typed event. Returns an unsubscribe function. */
|
|
17
|
-
on<K extends UWCEventName>(
|
|
18
|
-
event: K,
|
|
19
|
-
listener: UWCEventListener<K>
|
|
20
|
-
): () => void {
|
|
21
|
-
let set = this.listeners.get(event)
|
|
22
|
-
if (!set) {
|
|
23
|
-
set = new Set()
|
|
24
|
-
this.listeners.set(event, set)
|
|
25
|
-
}
|
|
26
|
-
set.add(listener as UntypedListener)
|
|
27
|
-
return () => this.off(event, listener)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Subscribe once; the listener is removed after the first dispatch. */
|
|
31
|
-
once<K extends UWCEventName>(
|
|
32
|
-
event: K,
|
|
33
|
-
listener: UWCEventListener<K>
|
|
34
|
-
): () => void {
|
|
35
|
-
const wrapper: UWCEventListener<K> = data => {
|
|
36
|
-
this.off(event, wrapper)
|
|
37
|
-
listener(data)
|
|
38
|
-
}
|
|
39
|
-
return this.on(event, wrapper)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
off<K extends UWCEventName>(event: K, listener: UWCEventListener<K>): void {
|
|
43
|
-
const set = this.listeners.get(event)
|
|
44
|
-
set?.delete(listener as UntypedListener)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
emit<K extends UWCEventName>(event: K, data: UWCEventMap[K]): void {
|
|
48
|
-
this.dispatch(event, data)
|
|
49
|
-
if (event !== 'change') {
|
|
50
|
-
this.dispatch('change', undefined as UWCEventMap['change'])
|
|
51
|
-
}
|
|
52
|
-
}
|
|
5
|
+
private listeners: Set<Listener> = new Set()
|
|
53
6
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const set = this.listeners.get(event)
|
|
59
|
-
if (!set || set.size === 0) return
|
|
60
|
-
// Clone to guard against mutation during dispatch.
|
|
61
|
-
for (const listener of [...set]) {
|
|
62
|
-
try {
|
|
63
|
-
listener(data)
|
|
64
|
-
} catch {
|
|
65
|
-
// A bad listener shouldn't break the rest of the dispatch chain.
|
|
66
|
-
}
|
|
7
|
+
subscribe(listener: Listener): Unsubscribe {
|
|
8
|
+
this.listeners.add(listener)
|
|
9
|
+
return () => {
|
|
10
|
+
this.listeners.delete(listener)
|
|
67
11
|
}
|
|
68
12
|
}
|
|
69
13
|
|
|
70
|
-
// ---- legacy API (still used by the React ConnectionProvider) ----
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* @deprecated Prefer `on(eventName, listener)` for targeted updates.
|
|
74
|
-
* Subscribes to the catch-all `change` event.
|
|
75
|
-
*/
|
|
76
|
-
subscribe(listener: LegacyListener): () => void {
|
|
77
|
-
return this.on('change', listener)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** @deprecated Prefer `emit(eventName, data)`. Emits `change` with no payload. */
|
|
81
14
|
notify(): void {
|
|
82
|
-
this.
|
|
15
|
+
this.listeners.forEach(listener => listener())
|
|
83
16
|
}
|
|
84
17
|
|
|
85
18
|
getListenerCount(): number {
|
|
86
|
-
|
|
87
|
-
for (const set of this.listeners.values()) {
|
|
88
|
-
count += set.size
|
|
89
|
-
}
|
|
90
|
-
return count
|
|
19
|
+
return this.listeners.size
|
|
91
20
|
}
|
|
92
21
|
|
|
93
22
|
clearAllListeners(): void {
|
|
@@ -249,12 +249,8 @@ describe('ConnectionService', () => {
|
|
|
249
249
|
})
|
|
250
250
|
})
|
|
251
251
|
|
|
252
|
-
it('
|
|
253
|
-
const
|
|
254
|
-
const changeListener = vi.fn()
|
|
255
|
-
eventManager.on('connectionUri', uriListener)
|
|
256
|
-
eventManager.on('change', changeListener)
|
|
257
|
-
|
|
252
|
+
it('polls for URI and notifies eventManager when available', async () => {
|
|
253
|
+
const notifySpy = vi.spyOn(eventManager, 'notify')
|
|
258
254
|
let connectResolve: (v: any) => void
|
|
259
255
|
|
|
260
256
|
tonConnector.connect = vi.fn().mockReturnValue(
|
|
@@ -279,11 +275,7 @@ describe('ConnectionService', () => {
|
|
|
279
275
|
// Wait for polling to detect URI
|
|
280
276
|
await new Promise(r => setTimeout(r, 250))
|
|
281
277
|
|
|
282
|
-
expect(
|
|
283
|
-
uri: 'tc://some-uri',
|
|
284
|
-
connectionMode: 'tonConnect'
|
|
285
|
-
})
|
|
286
|
-
expect(changeListener).toHaveBeenCalled()
|
|
278
|
+
expect(notifySpy).toHaveBeenCalled()
|
|
287
279
|
|
|
288
280
|
// Resolve the connection to let the test finish
|
|
289
281
|
connectResolve!({
|
|
@@ -13,10 +13,6 @@ import type {
|
|
|
13
13
|
import type { SessionManager } from '../managers/session-manager'
|
|
14
14
|
import type { EventManager } from '../managers/event-manager'
|
|
15
15
|
|
|
16
|
-
export interface ServiceOptions {
|
|
17
|
-
signal?: AbortSignal
|
|
18
|
-
}
|
|
19
|
-
|
|
20
16
|
export class ConnectionService {
|
|
21
17
|
private activeConnector: Connector | null = null
|
|
22
18
|
|
|
@@ -32,13 +28,8 @@ export class ConnectionService {
|
|
|
32
28
|
async connect(
|
|
33
29
|
connectionMode: ConnectionMode,
|
|
34
30
|
walletId: string,
|
|
35
|
-
networkId?: NetworkId
|
|
36
|
-
options?: ServiceOptions
|
|
31
|
+
networkId?: NetworkId
|
|
37
32
|
): Promise<void> {
|
|
38
|
-
options?.signal?.throwIfAborted()
|
|
39
|
-
|
|
40
|
-
this.eventManager.emit('connecting', { connectionMode, walletId })
|
|
41
|
-
|
|
42
33
|
// Find the wallet
|
|
43
34
|
const wallet = this.findWallet(walletId)
|
|
44
35
|
|
|
@@ -68,12 +59,7 @@ export class ConnectionService {
|
|
|
68
59
|
connectionMode === 'tonConnect' ||
|
|
69
60
|
connectionMode === 'walletConnect'
|
|
70
61
|
) {
|
|
71
|
-
result = await this.connectWithURIPoll(
|
|
72
|
-
connector,
|
|
73
|
-
network,
|
|
74
|
-
provider,
|
|
75
|
-
connectionMode
|
|
76
|
-
)
|
|
62
|
+
result = await this.connectWithURIPoll(connector, network, provider)
|
|
77
63
|
} else {
|
|
78
64
|
throw new Error(`Unsupported connection mode: ${connectionMode}`)
|
|
79
65
|
}
|
|
@@ -82,9 +68,6 @@ export class ConnectionService {
|
|
|
82
68
|
throw error
|
|
83
69
|
}
|
|
84
70
|
|
|
85
|
-
// If the caller aborted during the await, bail before mutating session
|
|
86
|
-
options?.signal?.throwIfAborted()
|
|
87
|
-
|
|
88
71
|
// Filter available addresses to only include those for configured networks
|
|
89
72
|
const filteredAvailableAddresses = result.availableAddresses.filter(addr =>
|
|
90
73
|
this.networks.some(n => n.id === addr.networkId)
|
|
@@ -101,26 +84,20 @@ export class ConnectionService {
|
|
|
101
84
|
),
|
|
102
85
|
availableAddresses: filteredAvailableAddresses
|
|
103
86
|
})
|
|
104
|
-
|
|
105
|
-
const session = this.sessionManager.getSession()
|
|
106
|
-
this.eventManager.emit('connected', { session })
|
|
107
|
-
this.eventManager.emit('sessionChanged', { session })
|
|
108
87
|
}
|
|
109
88
|
|
|
110
89
|
private async connectWithURIPoll(
|
|
111
90
|
connector: Connector,
|
|
112
91
|
network: Network,
|
|
113
|
-
provider: SupportedProvider
|
|
114
|
-
connectionMode: ConnectionMode
|
|
92
|
+
provider: SupportedProvider
|
|
115
93
|
): Promise<ConnectorResult> {
|
|
116
94
|
const connectPromise = connector.connect(network, provider)
|
|
117
95
|
|
|
118
|
-
let emittedUri: string | undefined
|
|
119
96
|
const pollForURI = setInterval(() => {
|
|
120
97
|
const uri = this.getConnectionURI()
|
|
121
|
-
if (uri
|
|
122
|
-
|
|
123
|
-
this.eventManager.
|
|
98
|
+
if (uri) {
|
|
99
|
+
clearInterval(pollForURI)
|
|
100
|
+
this.eventManager.notify()
|
|
124
101
|
}
|
|
125
102
|
}, 100)
|
|
126
103
|
|
|
@@ -242,8 +219,7 @@ export class ConnectionService {
|
|
|
242
219
|
return network
|
|
243
220
|
}
|
|
244
221
|
|
|
245
|
-
async disconnect(
|
|
246
|
-
options?.signal?.throwIfAborted()
|
|
222
|
+
async disconnect(): Promise<void> {
|
|
247
223
|
try {
|
|
248
224
|
if (
|
|
249
225
|
this.activeConnector &&
|
|
@@ -254,9 +230,6 @@ export class ConnectionService {
|
|
|
254
230
|
} finally {
|
|
255
231
|
this.activeConnector = null
|
|
256
232
|
this.sessionManager.clearSession()
|
|
257
|
-
const session = this.sessionManager.getSession()
|
|
258
|
-
this.eventManager.emit('disconnected', undefined)
|
|
259
|
-
this.eventManager.emit('sessionChanged', { session })
|
|
260
233
|
}
|
|
261
234
|
}
|
|
262
235
|
|
|
@@ -11,7 +11,6 @@ import type {
|
|
|
11
11
|
} from '@meshconnect/uwc-types'
|
|
12
12
|
import type { SessionManager } from '../managers/session-manager'
|
|
13
13
|
import type { EventManager } from '../managers/event-manager'
|
|
14
|
-
import type { ServiceOptions } from './connection-service'
|
|
15
14
|
|
|
16
15
|
export class NetworkSwitchService {
|
|
17
16
|
private isLoading = false
|
|
@@ -32,12 +31,7 @@ export class NetworkSwitchService {
|
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
async switchNetwork(
|
|
36
|
-
networkId: NetworkId,
|
|
37
|
-
options?: ServiceOptions
|
|
38
|
-
): Promise<void> {
|
|
39
|
-
options?.signal?.throwIfAborted()
|
|
40
|
-
|
|
34
|
+
async switchNetwork(networkId: NetworkId): Promise<void> {
|
|
41
35
|
// Check if there's an active connection
|
|
42
36
|
const session = this.sessionManager.getSession()
|
|
43
37
|
if (!session) {
|
|
@@ -110,10 +104,7 @@ export class NetworkSwitchService {
|
|
|
110
104
|
// Set loading states
|
|
111
105
|
this.isLoading = true
|
|
112
106
|
this.isWaitingForUserApproval = requiresApproval
|
|
113
|
-
this.eventManager.
|
|
114
|
-
isLoading: true,
|
|
115
|
-
isWaitingForUserApproval: requiresApproval
|
|
116
|
-
})
|
|
107
|
+
this.eventManager.notify()
|
|
117
108
|
|
|
118
109
|
// Perform the network switch and get the new address
|
|
119
110
|
// Pass the appropriate provider based on connection mode
|
|
@@ -138,8 +129,6 @@ export class NetworkSwitchService {
|
|
|
138
129
|
result = await activeConnector.switchNetwork(network)
|
|
139
130
|
}
|
|
140
131
|
|
|
141
|
-
options?.signal?.throwIfAborted()
|
|
142
|
-
|
|
143
132
|
// Filter available addresses to only include those for configured networks
|
|
144
133
|
const filteredAvailableAddresses = result.availableAddresses
|
|
145
134
|
? result.availableAddresses.filter(addr =>
|
|
@@ -155,19 +144,11 @@ export class NetworkSwitchService {
|
|
|
155
144
|
availableAddresses: filteredAvailableAddresses
|
|
156
145
|
})
|
|
157
146
|
})
|
|
158
|
-
|
|
159
|
-
this.eventManager.emit('networkSwitched', { network })
|
|
160
|
-
this.eventManager.emit('sessionChanged', {
|
|
161
|
-
session: this.sessionManager.getSession()
|
|
162
|
-
})
|
|
163
147
|
} finally {
|
|
164
148
|
// Clear loading states
|
|
165
149
|
this.isLoading = false
|
|
166
150
|
this.isWaitingForUserApproval = false
|
|
167
|
-
this.eventManager.
|
|
168
|
-
isLoading: false,
|
|
169
|
-
isWaitingForUserApproval: false
|
|
170
|
-
})
|
|
151
|
+
this.eventManager.notify()
|
|
171
152
|
}
|
|
172
153
|
}
|
|
173
154
|
|
|
@@ -8,7 +8,6 @@ import type {
|
|
|
8
8
|
SignatureType
|
|
9
9
|
} from '@meshconnect/uwc-types'
|
|
10
10
|
import type { SessionManager } from '../managers/session-manager'
|
|
11
|
-
import type { ServiceOptions } from './connection-service'
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* Service for handling signature operations across different connector types
|
|
@@ -23,15 +22,12 @@ export class SignatureService {
|
|
|
23
22
|
* Sign a message with the currently connected wallet
|
|
24
23
|
* @param message The message to sign
|
|
25
24
|
* @param provider The wallet provider to use for signing (required for injected connector)
|
|
26
|
-
* @param options Optional cancellation signal
|
|
27
25
|
* @returns A promise that resolves to the signature
|
|
28
26
|
*/
|
|
29
27
|
async signMessage(
|
|
30
28
|
message: string,
|
|
31
|
-
provider?: SupportedProvider
|
|
32
|
-
options?: ServiceOptions
|
|
29
|
+
provider?: SupportedProvider
|
|
33
30
|
): Promise<SignatureType> {
|
|
34
|
-
options?.signal?.throwIfAborted()
|
|
35
31
|
const session = this.sessionManager.getSession()
|
|
36
32
|
|
|
37
33
|
if (!session.connectionMode) {
|
|
@@ -56,33 +52,29 @@ export class SignatureService {
|
|
|
56
52
|
}
|
|
57
53
|
|
|
58
54
|
// Call the connector's signMessage method with the appropriate provider
|
|
59
|
-
let signature: SignatureType
|
|
60
55
|
if (session.connectionMode === 'injected') {
|
|
61
56
|
if (!provider) {
|
|
62
57
|
throw new Error('Provider is required for injected connector')
|
|
63
58
|
}
|
|
64
|
-
|
|
59
|
+
return await connector.signMessage(
|
|
65
60
|
message,
|
|
66
61
|
provider as
|
|
67
62
|
| ExtensionInjectedProvider
|
|
68
63
|
| IntegratedBrowserInjectedProvider
|
|
69
64
|
)
|
|
70
65
|
} else if (session.connectionMode === 'tonConnect') {
|
|
71
|
-
|
|
66
|
+
return await connector.signMessage(message)
|
|
72
67
|
} else if (session.connectionMode === 'walletConnect') {
|
|
73
68
|
if (!provider) {
|
|
74
69
|
throw new Error('Provider is required for WalletConnect connector')
|
|
75
70
|
}
|
|
76
|
-
|
|
71
|
+
return await connector.signMessage(
|
|
77
72
|
message,
|
|
78
73
|
provider as WalletConnectProvider
|
|
79
74
|
)
|
|
80
75
|
} else {
|
|
81
76
|
// For other connectors that might not need the provider
|
|
82
|
-
|
|
77
|
+
return await connector.signMessage(message)
|
|
83
78
|
}
|
|
84
|
-
|
|
85
|
-
options?.signal?.throwIfAborted()
|
|
86
|
-
return signature
|
|
87
79
|
}
|
|
88
80
|
}
|
|
@@ -9,7 +9,6 @@ import type {
|
|
|
9
9
|
TransactionResult
|
|
10
10
|
} from '@meshconnect/uwc-types'
|
|
11
11
|
import type { SessionManager } from '../managers/session-manager'
|
|
12
|
-
import type { ServiceOptions } from './connection-service'
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* Service for handling transaction operations across different connector types
|
|
@@ -24,15 +23,12 @@ export class TransactionService {
|
|
|
24
23
|
* Send a transaction with the currently connected wallet
|
|
25
24
|
* @param request The transaction request parameters
|
|
26
25
|
* @param provider The wallet provider to use for sending (required for injected connector)
|
|
27
|
-
* @param options Optional cancellation signal
|
|
28
26
|
* @returns A promise that resolves to the transaction result
|
|
29
27
|
*/
|
|
30
28
|
async sendTransaction(
|
|
31
29
|
request: TransactionRequest,
|
|
32
|
-
provider?: SupportedProvider
|
|
33
|
-
options?: ServiceOptions
|
|
30
|
+
provider?: SupportedProvider
|
|
34
31
|
): Promise<TransactionResult> {
|
|
35
|
-
options?.signal?.throwIfAborted()
|
|
36
32
|
const session = this.sessionManager.getSession()
|
|
37
33
|
|
|
38
34
|
if (!session.connectionMode) {
|
|
@@ -57,33 +53,29 @@ export class TransactionService {
|
|
|
57
53
|
}
|
|
58
54
|
|
|
59
55
|
// Call the connector's sendTransaction method with the appropriate provider
|
|
60
|
-
let result: TransactionResult
|
|
61
56
|
if (session.connectionMode === 'injected') {
|
|
62
57
|
if (!provider) {
|
|
63
58
|
throw new Error('Provider is required for injected connector')
|
|
64
59
|
}
|
|
65
|
-
|
|
60
|
+
return await connector.sendTransaction(
|
|
66
61
|
request,
|
|
67
62
|
provider as
|
|
68
63
|
| ExtensionInjectedProvider
|
|
69
64
|
| IntegratedBrowserInjectedProvider
|
|
70
65
|
)
|
|
71
66
|
} else if (session.connectionMode === 'tonConnect') {
|
|
72
|
-
|
|
67
|
+
return await connector.sendTransaction(request)
|
|
73
68
|
} else if (session.connectionMode === 'walletConnect') {
|
|
74
69
|
if (!provider) {
|
|
75
70
|
throw new Error('Provider is required for WalletConnect connector')
|
|
76
71
|
}
|
|
77
|
-
|
|
72
|
+
return await connector.sendTransaction(
|
|
78
73
|
request,
|
|
79
74
|
provider as WalletConnectProvider
|
|
80
75
|
)
|
|
81
76
|
} else {
|
|
82
77
|
// For other connectors that might not need the provider
|
|
83
|
-
|
|
78
|
+
return await connector.sendTransaction(request)
|
|
84
79
|
}
|
|
85
|
-
|
|
86
|
-
options?.signal?.throwIfAborted()
|
|
87
|
-
return result
|
|
88
80
|
}
|
|
89
81
|
}
|
|
@@ -6,7 +6,6 @@ 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'
|
|
10
9
|
|
|
11
10
|
export class WalletCapabilitiesService {
|
|
12
11
|
constructor(
|
|
@@ -18,11 +17,8 @@ export class WalletCapabilitiesService {
|
|
|
18
17
|
|
|
19
18
|
async getWalletCapabilities(
|
|
20
19
|
address: string,
|
|
21
|
-
activeNetwork?: Network
|
|
22
|
-
options?: ServiceOptions
|
|
20
|
+
activeNetwork?: Network
|
|
23
21
|
): Promise<void> {
|
|
24
|
-
options?.signal?.throwIfAborted()
|
|
25
|
-
|
|
26
22
|
let activeWalletCapabilities: Record<string, EVMCapabilities> = {}
|
|
27
23
|
let activeNetworkWalletCapabilities: EVMCapabilities = {}
|
|
28
24
|
|
|
@@ -53,8 +49,6 @@ export class WalletCapabilitiesService {
|
|
|
53
49
|
capabilities = {}
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
options?.signal?.throwIfAborted()
|
|
57
|
-
|
|
58
52
|
// keep only supported networks
|
|
59
53
|
activeWalletCapabilities = Object.fromEntries(
|
|
60
54
|
Object.entries(capabilities).filter(([networkId, _]) =>
|
|
@@ -77,13 +71,7 @@ export class WalletCapabilitiesService {
|
|
|
77
71
|
activeNetworkWalletCapabilities: null
|
|
78
72
|
})
|
|
79
73
|
}
|
|
80
|
-
|
|
81
|
-
this.eventManager.emit('capabilitiesUpdated', {
|
|
82
|
-
capabilities: activeWalletCapabilities
|
|
83
|
-
})
|
|
84
|
-
this.eventManager.emit('sessionChanged', {
|
|
85
|
-
session: this.sessionManager.getSession()
|
|
86
|
-
})
|
|
74
|
+
this.eventManager.notify()
|
|
87
75
|
}
|
|
88
76
|
}
|
|
89
77
|
}
|
|
@@ -29,11 +29,7 @@ const mockSessionManager = {
|
|
|
29
29
|
|
|
30
30
|
const mockEventManager = {
|
|
31
31
|
subscribe: vi.fn().mockReturnValue(() => {}),
|
|
32
|
-
notify: vi.fn()
|
|
33
|
-
emit: vi.fn(),
|
|
34
|
-
on: vi.fn().mockReturnValue(() => {}),
|
|
35
|
-
off: vi.fn(),
|
|
36
|
-
once: vi.fn().mockReturnValue(() => {})
|
|
32
|
+
notify: vi.fn()
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
const mockConnectionService = {
|
|
@@ -121,7 +117,8 @@ describe('UniversalWalletConnector', () => {
|
|
|
121
117
|
let mockWalletConnectConfig: WalletConnectConfig
|
|
122
118
|
|
|
123
119
|
beforeEach(() => {
|
|
124
|
-
UniversalWalletConnector.
|
|
120
|
+
;(UniversalWalletConnector as any).instanceCount = 0
|
|
121
|
+
;(UniversalWalletConnector as any).hasWarnedAboutMultipleInstances = false
|
|
125
122
|
|
|
126
123
|
mockNetworks = [
|
|
127
124
|
{
|
|
@@ -405,87 +402,6 @@ describe('UniversalWalletConnector', () => {
|
|
|
405
402
|
expect(typeof connector.sendTransaction).toBe('function')
|
|
406
403
|
expect(typeof connector.isConnectionModeAvailable).toBe('function')
|
|
407
404
|
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()
|
|
489
405
|
})
|
|
490
406
|
})
|
|
491
407
|
|