@meshconnect/uwc-core 2.5.4 → 2.5.7
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/services/network-switch-service.d.ts +2 -0
- package/dist/services/network-switch-service.d.ts.map +1 -1
- package/dist/services/network-switch-service.js +91 -30
- package/dist/services/network-switch-service.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/src/services/network-switch-service.test.ts +232 -0
- package/src/services/network-switch-service.ts +109 -41
- package/src/version.ts +1 -1
|
@@ -17,6 +17,8 @@ export declare class NetworkSwitchService {
|
|
|
17
17
|
isWaitingForUserApproval: boolean;
|
|
18
18
|
};
|
|
19
19
|
switchNetwork(networkId: NetworkId, options?: ServiceOptions): Promise<void>;
|
|
20
|
+
/** Shared terminal for a switch that landed — real or no-op'd — on `network`. */
|
|
21
|
+
private emitNetworkSwitched;
|
|
20
22
|
private checkIfApprovalRequired;
|
|
21
23
|
}
|
|
22
24
|
//# sourceMappingURL=network-switch-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-switch-service.d.ts","sourceRoot":"","sources":["../../src/services/network-switch-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,SAAS,EACT,cAAc,
|
|
1
|
+
{"version":3,"file":"network-switch-service.d.ts","sourceRoot":"","sources":["../../src/services/network-switch-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,SAAS,EACT,cAAc,EAOf,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAI1D,qBAAa,oBAAoB;IAK7B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,YAAY;IAEpB,OAAO,CAAC,uBAAuB;IAVjC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,wBAAwB,CAAQ;IAExC,YACU,QAAQ,EAAE,OAAO,EAAE,EACnB,cAAc,EAAE,cAAc,EAC9B,UAAU,EAAE,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,EAC1C,sBAAsB,EAAE,OAAO,EAC/B,YAAY,EAAE,YAAY,EAE1B,uBAAuB,EAAE,MAAM,EACrC;IAEJ,eAAe;QAEX,SAAS;QACT,wBAAwB;MAE3B;IAEK,aAAa,CACjB,SAAS,EAAE,SAAS,EACpB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CA0Nf;IAED,iFAAiF;IACjF,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,uBAAuB;CAyChC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { instrumentHandoff } from '../observability/instrument-handoff';
|
|
2
|
+
import { isAbortError, isUserRejection } from '../utils/to-wallet-error';
|
|
2
3
|
export class NetworkSwitchService {
|
|
3
4
|
networks;
|
|
4
5
|
sessionManager;
|
|
@@ -94,30 +95,86 @@ export class NetworkSwitchService {
|
|
|
94
95
|
// so `awaitingWallet` marks the real wallet boundary; pre-wallet validation
|
|
95
96
|
// failures throw above and never enter the funnel.
|
|
96
97
|
// Pass the appropriate provider based on connection mode.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
98
|
+
let result;
|
|
99
|
+
try {
|
|
100
|
+
result = await instrumentHandoff({
|
|
101
|
+
eventManager: this.eventManager,
|
|
102
|
+
timeoutMs: this.walletResponseTimeoutMs,
|
|
103
|
+
signal: options?.signal
|
|
104
|
+
}, {
|
|
105
|
+
operation: 'switchNetwork',
|
|
106
|
+
connectionMode: session.connectionMode,
|
|
107
|
+
walletId: currentWallet.id,
|
|
108
|
+
namespace: network.namespace,
|
|
109
|
+
chainId: network.id,
|
|
110
|
+
targetAlreadyActive
|
|
111
|
+
}, async () => {
|
|
112
|
+
if ((session.connectionMode === 'injected' ||
|
|
113
|
+
session.connectionMode === 'tonConnect') &&
|
|
114
|
+
provider) {
|
|
115
|
+
return await activeConnector.switchNetwork(network, provider);
|
|
116
|
+
}
|
|
117
|
+
else if (session.connectionMode === 'walletConnect' && provider) {
|
|
118
|
+
return await activeConnector.switchNetwork(network, provider);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
return await activeConnector.switchNetwork(network);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
// A caller-driven cancellation is not a wallet outcome to second-guess —
|
|
127
|
+
// let it propagate untouched, same as instrumentHandoff's own check.
|
|
128
|
+
// Otherwise an abort mid-flight on an already-active target would be
|
|
129
|
+
// swallowed into a silent success instead of the cancellation the
|
|
130
|
+
// caller asked for.
|
|
131
|
+
if (isAbortError(error) || options?.signal?.aborted)
|
|
132
|
+
throw error;
|
|
133
|
+
// An explicit "no" is not a race to paper over: prod data (PRG-714
|
|
134
|
+
// review) shows this exact targetAlreadyActive+rejection window has
|
|
135
|
+
// carried real user declines (errorCode 4001, "Not Allowed"), not
|
|
136
|
+
// just stale-confirmation races. Swallowing one into success would
|
|
137
|
+
// have the caller believe the switch — and a following
|
|
138
|
+
// sendTransaction — was approved. isUserRejection is transport-
|
|
139
|
+
// agnostic (WalletConnectorError{type:'rejected'} or EIP-1193
|
|
140
|
+
// 4001/ACTION_REJECTED), so injected/tonConnect/walletConnect are all
|
|
141
|
+
// covered, unlike a code-4902 narrowing.
|
|
142
|
+
if (isUserRejection(error))
|
|
143
|
+
throw error;
|
|
144
|
+
// PRG-714: some injected providers (MetaMask) race their own
|
|
145
|
+
// `wallet_addEthereumChain` confirmation against this confirmatory
|
|
146
|
+
// switch — the chain is already active per our session, but the
|
|
147
|
+
// provider answers with a stale 4902 "unrecognized chain" rejection.
|
|
148
|
+
// The session is the source of truth here, not that reply: trust it
|
|
149
|
+
// was already active and no-op to success instead of failing an
|
|
150
|
+
// otherwise-successful switch. Not narrowed to error code 4902 —
|
|
151
|
+
// tonConnect/walletConnect connectors don't speak EIP-1193 error
|
|
152
|
+
// codes, and the same race can surface there under a different shape.
|
|
153
|
+
//
|
|
154
|
+
// Re-read the session HERE rather than trust the `targetAlreadyActive`
|
|
155
|
+
// captured before the wallet call: it can move while we were
|
|
156
|
+
// awaiting the wallet (another switch lands, `accountsChanged` updates
|
|
157
|
+
// `activeAddress` — see connection-service.ts), and the captured
|
|
158
|
+
// snapshot would answer "was this a no-op when we started" instead of
|
|
159
|
+
// the question that actually matters here, "is it still a no-op now".
|
|
160
|
+
//
|
|
161
|
+
// Known tradeoff: `session.activeNetwork` is set only by a prior
|
|
162
|
+
// successful `connect`/`switchNetwork` (see `SessionManager`) — it is
|
|
163
|
+
// NOT synced from the live `chainChanged` telemetry event, so it can
|
|
164
|
+
// go stale if the wallet changes chain by some path outside UWC.
|
|
165
|
+
// That's an existing property of this session model (every other
|
|
166
|
+
// `activeNetwork` read in `connection-service.ts` trusts it the same
|
|
167
|
+
// way); a rejection this short-circuit swallows in that stale window
|
|
168
|
+
// would mask a genuine failure instead of confirming a no-op. Fixing
|
|
169
|
+
// that needs live chain-state sync, which is a bigger, separate
|
|
170
|
+
// decision than this hotfix.
|
|
171
|
+
const currentSession = this.sessionManager.getSession();
|
|
172
|
+
if (currentSession.activeNetwork?.id === networkId) {
|
|
173
|
+
this.emitNetworkSwitched(network, currentSession.activeAddress ?? undefined);
|
|
174
|
+
return;
|
|
119
175
|
}
|
|
120
|
-
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
121
178
|
options?.signal?.throwIfAborted();
|
|
122
179
|
// Filter available addresses to only include those for configured networks
|
|
123
180
|
const filteredAvailableAddresses = result.availableAddresses
|
|
@@ -131,13 +188,7 @@ export class NetworkSwitchService {
|
|
|
131
188
|
availableAddresses: filteredAvailableAddresses
|
|
132
189
|
})
|
|
133
190
|
});
|
|
134
|
-
this.
|
|
135
|
-
network,
|
|
136
|
-
address: result.address
|
|
137
|
-
});
|
|
138
|
-
this.eventManager.emit('sessionChanged', {
|
|
139
|
-
session: this.sessionManager.getSession()
|
|
140
|
-
});
|
|
191
|
+
this.emitNetworkSwitched(network, result.address);
|
|
141
192
|
}
|
|
142
193
|
finally {
|
|
143
194
|
// Clear loading states
|
|
@@ -149,6 +200,16 @@ export class NetworkSwitchService {
|
|
|
149
200
|
});
|
|
150
201
|
}
|
|
151
202
|
}
|
|
203
|
+
/** Shared terminal for a switch that landed — real or no-op'd — on `network`. */
|
|
204
|
+
emitNetworkSwitched(network, address) {
|
|
205
|
+
this.eventManager.emit('networkSwitched', {
|
|
206
|
+
network,
|
|
207
|
+
...(address && { address })
|
|
208
|
+
});
|
|
209
|
+
this.eventManager.emit('sessionChanged', {
|
|
210
|
+
session: this.sessionManager.getSession()
|
|
211
|
+
});
|
|
212
|
+
}
|
|
152
213
|
checkIfApprovalRequired(wallet, targetNetwork, currentNetwork) {
|
|
153
214
|
if (!currentNetwork)
|
|
154
215
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-switch-service.js","sourceRoot":"","sources":["../../src/services/network-switch-service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"network-switch-service.js","sourceRoot":"","sources":["../../src/services/network-switch-service.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const UWC_CORE_VERSION = "2.5.
|
|
1
|
+
export declare const UWC_CORE_VERSION = "2.5.7";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meshconnect/uwc-core",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.7",
|
|
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-injected-connector": "0.24.
|
|
19
|
+
"@meshconnect/uwc-injected-connector": "0.24.6",
|
|
20
20
|
"@meshconnect/uwc-ton-connector": "0.9.4",
|
|
21
21
|
"@meshconnect/uwc-types": "0.28.2",
|
|
22
|
-
"@meshconnect/uwc-wallet-connect-connector": "0.14.
|
|
22
|
+
"@meshconnect/uwc-wallet-connect-connector": "0.14.11"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"typescript": "^7.0.2"
|
|
@@ -267,4 +267,236 @@ describe('NetworkSwitchService', () => {
|
|
|
267
267
|
}
|
|
268
268
|
])
|
|
269
269
|
})
|
|
270
|
+
|
|
271
|
+
it('PRG-714: does not fail a switch to the already-active chain when the wallet rejects the confirmatory call', async () => {
|
|
272
|
+
sessionManager.updateSession({
|
|
273
|
+
connectionMode: 'injected',
|
|
274
|
+
activeNetwork: networks[1], // eip155:137 — the wallet already reports this chain active
|
|
275
|
+
activeAddress: '0xabc',
|
|
276
|
+
activeWallet: {
|
|
277
|
+
id: 'metamask',
|
|
278
|
+
name: 'MetaMask',
|
|
279
|
+
metadata: {
|
|
280
|
+
icon: 'test',
|
|
281
|
+
downloadUrl: 'test',
|
|
282
|
+
supportedChains: ['eip155:1', 'eip155:137']
|
|
283
|
+
},
|
|
284
|
+
extensionInjectedProvider: {
|
|
285
|
+
supportedNetworkIds: ['eip155:1', 'eip155:137']
|
|
286
|
+
}
|
|
287
|
+
} as any
|
|
288
|
+
})
|
|
289
|
+
// MetaMask already fired chainChanged for eip155:137 (the add-chain sheet
|
|
290
|
+
// succeeded), but the confirmatory switchNetwork call races that
|
|
291
|
+
// confirmation and gets a stale "unrecognized chain" rejection back.
|
|
292
|
+
mockConnector.switchNetwork = vi
|
|
293
|
+
.fn()
|
|
294
|
+
.mockRejectedValue(
|
|
295
|
+
Object.assign(
|
|
296
|
+
new Error(
|
|
297
|
+
'Unrecognized chain ID "0x89". Try adding the chain using wallet_addEthereumChain first.'
|
|
298
|
+
),
|
|
299
|
+
{ code: 4902 }
|
|
300
|
+
)
|
|
301
|
+
)
|
|
302
|
+
const switched: Array<{ network: unknown; address?: string }> = []
|
|
303
|
+
const sessionChanges: unknown[] = []
|
|
304
|
+
eventManager.on('networkSwitched', d => switched.push(d))
|
|
305
|
+
eventManager.on('sessionChanged', d => sessionChanges.push(d))
|
|
306
|
+
|
|
307
|
+
await expect(
|
|
308
|
+
networkSwitchService.switchNetwork('eip155:137')
|
|
309
|
+
).resolves.toBeUndefined()
|
|
310
|
+
|
|
311
|
+
expect(switched).toEqual([
|
|
312
|
+
{
|
|
313
|
+
network: expect.objectContaining({ id: 'eip155:137' }),
|
|
314
|
+
address: '0xabc'
|
|
315
|
+
}
|
|
316
|
+
])
|
|
317
|
+
// The short-circuit emits the same sessionChanged terminal as a real
|
|
318
|
+
// switch, carrying the (unchanged) session — callers that only listen for
|
|
319
|
+
// sessionChanged must still see this no-op complete.
|
|
320
|
+
expect(sessionChanges).toEqual([
|
|
321
|
+
{
|
|
322
|
+
session: expect.objectContaining({
|
|
323
|
+
activeNetwork: expect.objectContaining({ id: 'eip155:137' }),
|
|
324
|
+
activeAddress: '0xabc'
|
|
325
|
+
})
|
|
326
|
+
}
|
|
327
|
+
])
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
it('PRG-714: rethrows the wallet rejection when the target chain is NOT already active', async () => {
|
|
331
|
+
sessionManager.updateSession({
|
|
332
|
+
connectionMode: 'injected',
|
|
333
|
+
activeNetwork: networks[0], // eip155:1 — a genuinely different chain from the target
|
|
334
|
+
activeAddress: '0xabc',
|
|
335
|
+
activeWallet: {
|
|
336
|
+
id: 'metamask',
|
|
337
|
+
name: 'MetaMask',
|
|
338
|
+
metadata: {
|
|
339
|
+
icon: 'test',
|
|
340
|
+
downloadUrl: 'test',
|
|
341
|
+
supportedChains: ['eip155:1', 'eip155:137']
|
|
342
|
+
},
|
|
343
|
+
extensionInjectedProvider: {
|
|
344
|
+
supportedNetworkIds: ['eip155:1', 'eip155:137']
|
|
345
|
+
}
|
|
346
|
+
} as any
|
|
347
|
+
})
|
|
348
|
+
const rejection = new Error('User rejected the request')
|
|
349
|
+
mockConnector.switchNetwork = vi.fn().mockRejectedValue(rejection)
|
|
350
|
+
const switched = vi.fn()
|
|
351
|
+
eventManager.on('networkSwitched', switched)
|
|
352
|
+
|
|
353
|
+
// targetAlreadyActive is false here — a real switch that fails must still
|
|
354
|
+
// fail. The short-circuit must not fire outside its one narrow case.
|
|
355
|
+
await expect(networkSwitchService.switchNetwork('eip155:137')).rejects.toBe(
|
|
356
|
+
rejection
|
|
357
|
+
)
|
|
358
|
+
expect(switched).not.toHaveBeenCalled()
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
it('PRG-714: rethrows an explicit user rejection even when the target chain is already active', async () => {
|
|
362
|
+
sessionManager.updateSession({
|
|
363
|
+
connectionMode: 'injected',
|
|
364
|
+
activeNetwork: networks[1], // eip155:137 — already active
|
|
365
|
+
activeAddress: '0xabc',
|
|
366
|
+
activeWallet: {
|
|
367
|
+
id: 'rabby',
|
|
368
|
+
name: 'Rabby',
|
|
369
|
+
metadata: {
|
|
370
|
+
icon: 'test',
|
|
371
|
+
downloadUrl: 'test',
|
|
372
|
+
supportedChains: ['eip155:1', 'eip155:137']
|
|
373
|
+
},
|
|
374
|
+
extensionInjectedProvider: {
|
|
375
|
+
supportedNetworkIds: ['eip155:1', 'eip155:137']
|
|
376
|
+
}
|
|
377
|
+
} as any
|
|
378
|
+
})
|
|
379
|
+
// Prod data (PRG-714 review): this exact targetAlreadyActive+rejection
|
|
380
|
+
// window has carried real EIP-1193 4001 declines, not just stale-4902
|
|
381
|
+
// races. An explicit "no" must still fail the switch.
|
|
382
|
+
const rejection = Object.assign(new Error('Not Allowed'), { code: 4001 })
|
|
383
|
+
mockConnector.switchNetwork = vi.fn().mockRejectedValue(rejection)
|
|
384
|
+
const switched = vi.fn()
|
|
385
|
+
eventManager.on('networkSwitched', switched)
|
|
386
|
+
|
|
387
|
+
await expect(networkSwitchService.switchNetwork('eip155:137')).rejects.toBe(
|
|
388
|
+
rejection
|
|
389
|
+
)
|
|
390
|
+
expect(switched).not.toHaveBeenCalled()
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
it('PRG-714: re-checks session state at catch time instead of trusting the pre-call snapshot', async () => {
|
|
394
|
+
sessionManager.updateSession({
|
|
395
|
+
connectionMode: 'injected',
|
|
396
|
+
activeNetwork: networks[1], // eip155:137 — active when the call STARTS
|
|
397
|
+
activeAddress: '0xabc',
|
|
398
|
+
activeWallet: {
|
|
399
|
+
id: 'metamask',
|
|
400
|
+
name: 'MetaMask',
|
|
401
|
+
metadata: {
|
|
402
|
+
icon: 'test',
|
|
403
|
+
downloadUrl: 'test',
|
|
404
|
+
supportedChains: ['eip155:1', 'eip155:137']
|
|
405
|
+
},
|
|
406
|
+
extensionInjectedProvider: {
|
|
407
|
+
supportedNetworkIds: ['eip155:1', 'eip155:137']
|
|
408
|
+
}
|
|
409
|
+
} as any
|
|
410
|
+
})
|
|
411
|
+
const rejection = new Error('Provider crashed mid-switch')
|
|
412
|
+
// Simulates a second operation (another switch, a wallet-side chain
|
|
413
|
+
// change) landing WHILE this call is awaiting the wallet: the session
|
|
414
|
+
// moves off the target before the rejection is even thrown. The stale
|
|
415
|
+
// `targetAlreadyActive` captured at the top of switchNetwork would say
|
|
416
|
+
// "still true" — the short-circuit must not trust that snapshot.
|
|
417
|
+
mockConnector.switchNetwork = vi.fn().mockImplementation(async () => {
|
|
418
|
+
sessionManager.updateSession({ activeNetwork: networks[0] }) // eip155:1
|
|
419
|
+
throw rejection
|
|
420
|
+
})
|
|
421
|
+
const switched = vi.fn()
|
|
422
|
+
eventManager.on('networkSwitched', switched)
|
|
423
|
+
|
|
424
|
+
await expect(networkSwitchService.switchNetwork('eip155:137')).rejects.toBe(
|
|
425
|
+
rejection
|
|
426
|
+
)
|
|
427
|
+
expect(switched).not.toHaveBeenCalled()
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
it('PRG-714: omits address from networkSwitched when the already-active session has none', async () => {
|
|
431
|
+
sessionManager.updateSession({
|
|
432
|
+
connectionMode: 'injected',
|
|
433
|
+
activeNetwork: networks[1], // eip155:137 — already active, but no address on file
|
|
434
|
+
activeAddress: null,
|
|
435
|
+
activeWallet: {
|
|
436
|
+
id: 'metamask',
|
|
437
|
+
name: 'MetaMask',
|
|
438
|
+
metadata: {
|
|
439
|
+
icon: 'test',
|
|
440
|
+
downloadUrl: 'test',
|
|
441
|
+
supportedChains: ['eip155:1', 'eip155:137']
|
|
442
|
+
},
|
|
443
|
+
extensionInjectedProvider: {
|
|
444
|
+
supportedNetworkIds: ['eip155:1', 'eip155:137']
|
|
445
|
+
}
|
|
446
|
+
} as any
|
|
447
|
+
})
|
|
448
|
+
mockConnector.switchNetwork = vi
|
|
449
|
+
.fn()
|
|
450
|
+
.mockRejectedValue(
|
|
451
|
+
Object.assign(new Error('Unrecognized chain ID'), { code: 4902 })
|
|
452
|
+
)
|
|
453
|
+
const switched: Array<{ network: unknown; address?: string }> = []
|
|
454
|
+
eventManager.on('networkSwitched', d => switched.push(d))
|
|
455
|
+
|
|
456
|
+
await expect(
|
|
457
|
+
networkSwitchService.switchNetwork('eip155:137')
|
|
458
|
+
).resolves.toBeUndefined()
|
|
459
|
+
|
|
460
|
+
expect(switched).toEqual([
|
|
461
|
+
{ network: expect.objectContaining({ id: 'eip155:137' }) }
|
|
462
|
+
])
|
|
463
|
+
expect(switched[0]).not.toHaveProperty('address')
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
it('PRG-714 regression: does not swallow a caller abort into success on an already-active target', async () => {
|
|
467
|
+
sessionManager.updateSession({
|
|
468
|
+
connectionMode: 'injected',
|
|
469
|
+
activeNetwork: networks[1], // eip155:137 — already active, same as the no-op case above
|
|
470
|
+
activeAddress: '0xabc',
|
|
471
|
+
activeWallet: {
|
|
472
|
+
id: 'metamask',
|
|
473
|
+
name: 'MetaMask',
|
|
474
|
+
metadata: {
|
|
475
|
+
icon: 'test',
|
|
476
|
+
downloadUrl: 'test',
|
|
477
|
+
supportedChains: ['eip155:1', 'eip155:137']
|
|
478
|
+
},
|
|
479
|
+
extensionInjectedProvider: {
|
|
480
|
+
supportedNetworkIds: ['eip155:1', 'eip155:137']
|
|
481
|
+
}
|
|
482
|
+
} as any
|
|
483
|
+
})
|
|
484
|
+
// A caller-driven cancellation, not a wallet outcome — must propagate as
|
|
485
|
+
// the abort it is, not get reinterpreted as "target already active, so
|
|
486
|
+
// this must have succeeded".
|
|
487
|
+
const abortError = Object.assign(new Error('The operation was aborted.'), {
|
|
488
|
+
name: 'AbortError'
|
|
489
|
+
})
|
|
490
|
+
mockConnector.switchNetwork = vi.fn().mockRejectedValue(abortError)
|
|
491
|
+
const switched = vi.fn()
|
|
492
|
+
eventManager.on('networkSwitched', switched)
|
|
493
|
+
|
|
494
|
+
await expect(
|
|
495
|
+
networkSwitchService.switchNetwork('eip155:137', {
|
|
496
|
+
signal: new AbortController().signal
|
|
497
|
+
})
|
|
498
|
+
).rejects.toBe(abortError)
|
|
499
|
+
|
|
500
|
+
expect(switched).not.toHaveBeenCalled()
|
|
501
|
+
})
|
|
270
502
|
})
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
Connector,
|
|
5
5
|
ConnectionMode,
|
|
6
6
|
SupportedProvider,
|
|
7
|
+
SwitchNetworkResult,
|
|
7
8
|
WalletMetadata,
|
|
8
9
|
ExtensionInjectedProvider,
|
|
9
10
|
IntegratedBrowserInjectedProvider,
|
|
@@ -13,6 +14,7 @@ import type { SessionManager } from '../managers/session-manager'
|
|
|
13
14
|
import type { EventManager } from '../managers/event-manager'
|
|
14
15
|
import type { ServiceOptions } from './connection-service'
|
|
15
16
|
import { instrumentHandoff } from '../observability/instrument-handoff'
|
|
17
|
+
import { isAbortError, isUserRejection } from '../utils/to-wallet-error'
|
|
16
18
|
|
|
17
19
|
export class NetworkSwitchService {
|
|
18
20
|
private isLoading = false
|
|
@@ -133,42 +135,100 @@ export class NetworkSwitchService {
|
|
|
133
135
|
// so `awaitingWallet` marks the real wallet boundary; pre-wallet validation
|
|
134
136
|
// failures throw above and never enter the funnel.
|
|
135
137
|
// Pass the appropriate provider based on connection mode.
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
138
|
+
let result: SwitchNetworkResult
|
|
139
|
+
try {
|
|
140
|
+
result = await instrumentHandoff(
|
|
141
|
+
{
|
|
142
|
+
eventManager: this.eventManager,
|
|
143
|
+
timeoutMs: this.walletResponseTimeoutMs,
|
|
144
|
+
signal: options?.signal
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
operation: 'switchNetwork',
|
|
148
|
+
connectionMode: session.connectionMode,
|
|
149
|
+
walletId: currentWallet.id,
|
|
150
|
+
namespace: network.namespace,
|
|
151
|
+
chainId: network.id,
|
|
152
|
+
targetAlreadyActive
|
|
153
|
+
},
|
|
154
|
+
async () => {
|
|
155
|
+
if (
|
|
156
|
+
(session.connectionMode === 'injected' ||
|
|
157
|
+
session.connectionMode === 'tonConnect') &&
|
|
158
|
+
provider
|
|
159
|
+
) {
|
|
160
|
+
return await activeConnector.switchNetwork(
|
|
161
|
+
network,
|
|
162
|
+
provider as
|
|
163
|
+
| ExtensionInjectedProvider
|
|
164
|
+
| IntegratedBrowserInjectedProvider
|
|
165
|
+
)
|
|
166
|
+
} else if (session.connectionMode === 'walletConnect' && provider) {
|
|
167
|
+
return await activeConnector.switchNetwork(
|
|
168
|
+
network,
|
|
169
|
+
provider as WalletConnectProvider
|
|
170
|
+
)
|
|
171
|
+
} else {
|
|
172
|
+
return await activeConnector.switchNetwork(network)
|
|
173
|
+
}
|
|
169
174
|
}
|
|
175
|
+
)
|
|
176
|
+
} catch (error) {
|
|
177
|
+
// A caller-driven cancellation is not a wallet outcome to second-guess —
|
|
178
|
+
// let it propagate untouched, same as instrumentHandoff's own check.
|
|
179
|
+
// Otherwise an abort mid-flight on an already-active target would be
|
|
180
|
+
// swallowed into a silent success instead of the cancellation the
|
|
181
|
+
// caller asked for.
|
|
182
|
+
if (isAbortError(error) || options?.signal?.aborted) throw error
|
|
183
|
+
|
|
184
|
+
// An explicit "no" is not a race to paper over: prod data (PRG-714
|
|
185
|
+
// review) shows this exact targetAlreadyActive+rejection window has
|
|
186
|
+
// carried real user declines (errorCode 4001, "Not Allowed"), not
|
|
187
|
+
// just stale-confirmation races. Swallowing one into success would
|
|
188
|
+
// have the caller believe the switch — and a following
|
|
189
|
+
// sendTransaction — was approved. isUserRejection is transport-
|
|
190
|
+
// agnostic (WalletConnectorError{type:'rejected'} or EIP-1193
|
|
191
|
+
// 4001/ACTION_REJECTED), so injected/tonConnect/walletConnect are all
|
|
192
|
+
// covered, unlike a code-4902 narrowing.
|
|
193
|
+
if (isUserRejection(error)) throw error
|
|
194
|
+
|
|
195
|
+
// PRG-714: some injected providers (MetaMask) race their own
|
|
196
|
+
// `wallet_addEthereumChain` confirmation against this confirmatory
|
|
197
|
+
// switch — the chain is already active per our session, but the
|
|
198
|
+
// provider answers with a stale 4902 "unrecognized chain" rejection.
|
|
199
|
+
// The session is the source of truth here, not that reply: trust it
|
|
200
|
+
// was already active and no-op to success instead of failing an
|
|
201
|
+
// otherwise-successful switch. Not narrowed to error code 4902 —
|
|
202
|
+
// tonConnect/walletConnect connectors don't speak EIP-1193 error
|
|
203
|
+
// codes, and the same race can surface there under a different shape.
|
|
204
|
+
//
|
|
205
|
+
// Re-read the session HERE rather than trust the `targetAlreadyActive`
|
|
206
|
+
// captured before the wallet call: it can move while we were
|
|
207
|
+
// awaiting the wallet (another switch lands, `accountsChanged` updates
|
|
208
|
+
// `activeAddress` — see connection-service.ts), and the captured
|
|
209
|
+
// snapshot would answer "was this a no-op when we started" instead of
|
|
210
|
+
// the question that actually matters here, "is it still a no-op now".
|
|
211
|
+
//
|
|
212
|
+
// Known tradeoff: `session.activeNetwork` is set only by a prior
|
|
213
|
+
// successful `connect`/`switchNetwork` (see `SessionManager`) — it is
|
|
214
|
+
// NOT synced from the live `chainChanged` telemetry event, so it can
|
|
215
|
+
// go stale if the wallet changes chain by some path outside UWC.
|
|
216
|
+
// That's an existing property of this session model (every other
|
|
217
|
+
// `activeNetwork` read in `connection-service.ts` trusts it the same
|
|
218
|
+
// way); a rejection this short-circuit swallows in that stale window
|
|
219
|
+
// would mask a genuine failure instead of confirming a no-op. Fixing
|
|
220
|
+
// that needs live chain-state sync, which is a bigger, separate
|
|
221
|
+
// decision than this hotfix.
|
|
222
|
+
const currentSession = this.sessionManager.getSession()
|
|
223
|
+
if (currentSession.activeNetwork?.id === networkId) {
|
|
224
|
+
this.emitNetworkSwitched(
|
|
225
|
+
network,
|
|
226
|
+
currentSession.activeAddress ?? undefined
|
|
227
|
+
)
|
|
228
|
+
return
|
|
170
229
|
}
|
|
171
|
-
|
|
230
|
+
throw error
|
|
231
|
+
}
|
|
172
232
|
|
|
173
233
|
options?.signal?.throwIfAborted()
|
|
174
234
|
|
|
@@ -188,13 +248,7 @@ export class NetworkSwitchService {
|
|
|
188
248
|
})
|
|
189
249
|
})
|
|
190
250
|
|
|
191
|
-
this.
|
|
192
|
-
network,
|
|
193
|
-
address: result.address
|
|
194
|
-
})
|
|
195
|
-
this.eventManager.emit('sessionChanged', {
|
|
196
|
-
session: this.sessionManager.getSession()
|
|
197
|
-
})
|
|
251
|
+
this.emitNetworkSwitched(network, result.address)
|
|
198
252
|
} finally {
|
|
199
253
|
// Clear loading states
|
|
200
254
|
this.isLoading = false
|
|
@@ -206,6 +260,20 @@ export class NetworkSwitchService {
|
|
|
206
260
|
}
|
|
207
261
|
}
|
|
208
262
|
|
|
263
|
+
/** Shared terminal for a switch that landed — real or no-op'd — on `network`. */
|
|
264
|
+
private emitNetworkSwitched(
|
|
265
|
+
network: Network,
|
|
266
|
+
address: string | undefined
|
|
267
|
+
): void {
|
|
268
|
+
this.eventManager.emit('networkSwitched', {
|
|
269
|
+
network,
|
|
270
|
+
...(address && { address })
|
|
271
|
+
})
|
|
272
|
+
this.eventManager.emit('sessionChanged', {
|
|
273
|
+
session: this.sessionManager.getSession()
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
|
|
209
277
|
private checkIfApprovalRequired(
|
|
210
278
|
wallet: WalletMetadata,
|
|
211
279
|
targetNetwork: Network,
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated from package.json by scripts/generate-version.mjs — do not edit.
|
|
2
|
-
export const UWC_CORE_VERSION = '2.5.
|
|
2
|
+
export const UWC_CORE_VERSION = '2.5.7'
|