@meshconnect/uwc-core 2.7.2-snapshot.c393760 → 2.7.3
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/events.d.ts +5 -11
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/observability/instrument-handoff.d.ts +0 -3
- package/dist/observability/instrument-handoff.d.ts.map +1 -1
- package/dist/observability/instrument-handoff.js +0 -6
- package/dist/observability/instrument-handoff.js.map +1 -1
- package/dist/observability/telemetry.d.ts +12 -3
- package/dist/observability/telemetry.d.ts.map +1 -1
- package/dist/observability/telemetry.js +5 -7
- package/dist/observability/telemetry.js.map +1 -1
- package/dist/services/connection-service.d.ts +2 -6
- package/dist/services/connection-service.d.ts.map +1 -1
- package/dist/services/connection-service.js +9 -19
- package/dist/services/connection-service.js.map +1 -1
- package/dist/services/index.d.ts +0 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +0 -1
- package/dist/services/index.js.map +1 -1
- package/dist/universal-wallet-connector.d.ts +1 -8
- package/dist/universal-wallet-connector.d.ts.map +1 -1
- package/dist/universal-wallet-connector.js +1 -2
- package/dist/universal-wallet-connector.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -5
- package/src/events.ts +6 -11
- package/src/index.ts +0 -4
- package/src/observability/instrument-handoff.ts +0 -9
- package/src/observability/telemetry.test.ts +37 -0
- package/src/observability/telemetry.ts +19 -10
- package/src/services/connection-service.test.ts +6 -46
- package/src/services/connection-service.ts +11 -28
- package/src/services/index.ts +0 -1
- package/src/universal-wallet-connector.ts +1 -10
- package/src/version.ts +1 -1
- package/dist/services/network-selection.d.ts +0 -34
- package/dist/services/network-selection.d.ts.map +0 -1
- package/dist/services/network-selection.js +0 -54
- package/dist/services/network-selection.js.map +0 -1
- package/src/services/network-selection.test.ts +0 -152
- package/src/services/network-selection.ts +0 -86
|
@@ -114,11 +114,11 @@ describe('ConnectionService', () => {
|
|
|
114
114
|
const mockProvider = {
|
|
115
115
|
supportedNetworkIds: ['eip155:1']
|
|
116
116
|
}
|
|
117
|
-
const
|
|
118
|
-
'
|
|
119
|
-
|
|
117
|
+
const network = connectionService['validateAndDetermineNetwork'](
|
|
118
|
+
'eip155:1',
|
|
119
|
+
mockProvider as any
|
|
120
|
+
)
|
|
120
121
|
expect(network).toEqual(networks[0])
|
|
121
|
-
expect(selection).toBe('explicit')
|
|
122
122
|
})
|
|
123
123
|
|
|
124
124
|
it('should throw error for unknown network', () => {
|
|
@@ -128,8 +128,7 @@ describe('ConnectionService', () => {
|
|
|
128
128
|
expect(() => {
|
|
129
129
|
connectionService['validateAndDetermineNetwork'](
|
|
130
130
|
'eip155:8453',
|
|
131
|
-
mockProvider as any
|
|
132
|
-
'injected'
|
|
131
|
+
mockProvider as any
|
|
133
132
|
)
|
|
134
133
|
}).toThrow('Network eip155:8453 is not in the configured networks')
|
|
135
134
|
})
|
|
@@ -144,8 +143,7 @@ describe('ConnectionService', () => {
|
|
|
144
143
|
try {
|
|
145
144
|
connectionService['validateAndDetermineNetwork'](
|
|
146
145
|
undefined,
|
|
147
|
-
mockProvider as any
|
|
148
|
-
'injected'
|
|
146
|
+
mockProvider as any
|
|
149
147
|
)
|
|
150
148
|
} catch (e) {
|
|
151
149
|
thrown = e
|
|
@@ -378,44 +376,6 @@ describe('ConnectionService', () => {
|
|
|
378
376
|
expect(awaiting.namespace).toBe('eip155')
|
|
379
377
|
expect(awaiting.chainId).toBe('eip155:1')
|
|
380
378
|
expect(awaiting.handoffId).toBe(events[1].data.handoffId)
|
|
381
|
-
expect(awaiting.networkSelection).toBe('explicit')
|
|
382
|
-
})
|
|
383
|
-
|
|
384
|
-
it('auto-picks a detected namespace over an undetected first network (ONC-2110)', async () => {
|
|
385
|
-
networks.push({
|
|
386
|
-
...networks[0],
|
|
387
|
-
id: 'tron:0x2b6653dc',
|
|
388
|
-
internalId: 2,
|
|
389
|
-
name: 'Tron',
|
|
390
|
-
namespace: 'tron',
|
|
391
|
-
networkType: 'tron'
|
|
392
|
-
} as Network)
|
|
393
|
-
// Trust mobile: catalog lists Tron first, but only EVM was detected.
|
|
394
|
-
wallets[0].extensionInjectedProvider = {
|
|
395
|
-
supportedNetworkIds: ['tron:0x2b6653dc', 'eip155:1'],
|
|
396
|
-
namespaceMetaData: {
|
|
397
|
-
tron: { injectedId: 'trustWallet.tronLink', installed: false },
|
|
398
|
-
eip155: { eip155Name: 'Trust Wallet', installed: true }
|
|
399
|
-
}
|
|
400
|
-
} as any
|
|
401
|
-
const awaiting = vi.fn()
|
|
402
|
-
eventManager.on('awaitingWallet', awaiting)
|
|
403
|
-
mockConnector.connect = vi.fn().mockResolvedValue({
|
|
404
|
-
networkId: 'eip155:1',
|
|
405
|
-
address: '0x1234',
|
|
406
|
-
availableAddresses: [{ address: '0x1234', networkId: 'eip155:1' }]
|
|
407
|
-
})
|
|
408
|
-
|
|
409
|
-
await connectionService.connect('injected', 'metamask')
|
|
410
|
-
|
|
411
|
-
expect(awaiting).toHaveBeenCalledWith(
|
|
412
|
-
expect.objectContaining({
|
|
413
|
-
chainId: 'eip155:1',
|
|
414
|
-
namespace: 'eip155',
|
|
415
|
-
networkSelection: 'detected'
|
|
416
|
-
})
|
|
417
|
-
)
|
|
418
|
-
expect(sessionManager.getSession().activeNetwork?.id).toBe('eip155:1')
|
|
419
379
|
})
|
|
420
380
|
|
|
421
381
|
it('emits one stable attempt ID per connect and a different ID for the next connect', async () => {
|
|
@@ -18,11 +18,6 @@ import { raceAbort } from '../utils/abort'
|
|
|
18
18
|
import { generateId } from '../utils/id'
|
|
19
19
|
import { instrumentHandoff } from '../observability/instrument-handoff'
|
|
20
20
|
import { attachLifecycle } from '../observability/lifecycle-bridge'
|
|
21
|
-
import {
|
|
22
|
-
DEFAULT_NAMESPACE_PRIORITY,
|
|
23
|
-
type NetworkSelection,
|
|
24
|
-
pickAutoNetwork
|
|
25
|
-
} from './network-selection'
|
|
26
21
|
|
|
27
22
|
export interface ServiceOptions {
|
|
28
23
|
signal?: AbortSignal
|
|
@@ -92,9 +87,7 @@ export class ConnectionService {
|
|
|
92
87
|
private usingIntegratedBrowser: boolean,
|
|
93
88
|
private eventManager: EventManager,
|
|
94
89
|
// Observational wallet-response deadline for the handoff timeout marker.
|
|
95
|
-
private walletResponseTimeoutMs: number
|
|
96
|
-
/** Namespace preference for an auto-picked connect network — see `pickAutoNetwork`. */
|
|
97
|
-
private preferredNamespaces: readonly Namespace[] = DEFAULT_NAMESPACE_PRIORITY
|
|
90
|
+
private walletResponseTimeoutMs: number
|
|
98
91
|
) {}
|
|
99
92
|
|
|
100
93
|
async connect(
|
|
@@ -111,8 +104,7 @@ export class ConnectionService {
|
|
|
111
104
|
// connect() would spuriously abort (MFS-602).
|
|
112
105
|
const wallet = this.findWallet(walletId)
|
|
113
106
|
const provider = this.getProviderForMode(wallet, connectionMode)
|
|
114
|
-
const
|
|
115
|
-
this.validateAndDetermineNetwork(networkId, provider, connectionMode)
|
|
107
|
+
const network = this.validateAndDetermineNetwork(networkId, provider)
|
|
116
108
|
const connector = this.getConnector(connectionMode)
|
|
117
109
|
// A silent-only connect is a promise never to open wallet UI. Only the
|
|
118
110
|
// injected connector can keep it — WalletConnect / TON Connect always hand
|
|
@@ -184,8 +176,7 @@ export class ConnectionService {
|
|
|
184
176
|
connectAttemptId,
|
|
185
177
|
// Lets telemetry tell a silent restore from a tapped connect: both
|
|
186
178
|
// succeed the same way, and only a miss carries a distinct failureKind.
|
|
187
|
-
silentOnly: options?.silentOnly === true
|
|
188
|
-
networkSelection
|
|
179
|
+
silentOnly: options?.silentOnly === true
|
|
189
180
|
},
|
|
190
181
|
async handoffId => {
|
|
191
182
|
// Publish this attempt's routing for the connector's step sink.
|
|
@@ -956,11 +947,9 @@ export class ConnectionService {
|
|
|
956
947
|
|
|
957
948
|
private validateAndDetermineNetwork(
|
|
958
949
|
networkId: NetworkId | undefined,
|
|
959
|
-
provider: SupportedProvider
|
|
960
|
-
|
|
961
|
-
): { network: Network; selection: NetworkSelection } {
|
|
950
|
+
provider: SupportedProvider
|
|
951
|
+
): Network {
|
|
962
952
|
let targetNetworkId: NetworkId
|
|
963
|
-
let selection: NetworkSelection = 'explicit'
|
|
964
953
|
|
|
965
954
|
if (networkId) {
|
|
966
955
|
// Check if networkId is in the configured networks
|
|
@@ -979,16 +968,11 @@ export class ConnectionService {
|
|
|
979
968
|
|
|
980
969
|
targetNetworkId = networkId
|
|
981
970
|
} else {
|
|
982
|
-
//
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
const picked = pickAutoNetwork(
|
|
986
|
-
provider,
|
|
987
|
-
this.networks,
|
|
988
|
-
connectionMode,
|
|
989
|
-
this.preferredNamespaces
|
|
971
|
+
// Use the first supported network that exists in both wallet and configured networks
|
|
972
|
+
const supportedNetwork = provider.supportedNetworkIds.find(id =>
|
|
973
|
+
this.networks.some(n => n.id === id)
|
|
990
974
|
)
|
|
991
|
-
if (!
|
|
975
|
+
if (!supportedNetwork) {
|
|
992
976
|
// The #1 production connection failure. Throw a typed, self-describing
|
|
993
977
|
// error carrying both CAIP-2 id lists (non-PII) so telemetry can tell a
|
|
994
978
|
// metadata gap from a client-config mistake — see NoCommonNetworkError.
|
|
@@ -997,8 +981,7 @@ export class ConnectionService {
|
|
|
997
981
|
this.networks.map(n => n.id)
|
|
998
982
|
)
|
|
999
983
|
}
|
|
1000
|
-
targetNetworkId =
|
|
1001
|
-
selection = picked.selection
|
|
984
|
+
targetNetworkId = supportedNetwork
|
|
1002
985
|
}
|
|
1003
986
|
|
|
1004
987
|
// Find and return the network object
|
|
@@ -1008,7 +991,7 @@ export class ConnectionService {
|
|
|
1008
991
|
`Network ${targetNetworkId} not found in configured networks`
|
|
1009
992
|
)
|
|
1010
993
|
}
|
|
1011
|
-
return
|
|
994
|
+
return network
|
|
1012
995
|
}
|
|
1013
996
|
|
|
1014
997
|
async disconnect(options?: ServiceOptions): Promise<void> {
|
package/src/services/index.ts
CHANGED
|
@@ -30,7 +30,6 @@ import type { TronConnectorConfig } from '@meshconnect/uwc-tron-connector'
|
|
|
30
30
|
import { SessionManager } from './managers/session-manager'
|
|
31
31
|
import { EventManager } from './managers/event-manager'
|
|
32
32
|
import { ConnectionService } from './services/connection-service'
|
|
33
|
-
import { DEFAULT_NAMESPACE_PRIORITY } from './services/network-selection'
|
|
34
33
|
import { NetworkSwitchService } from './services/network-switch-service'
|
|
35
34
|
import { SignatureService } from './services/signature-service'
|
|
36
35
|
import { TransactionService } from './services/transaction-service'
|
|
@@ -110,13 +109,6 @@ export interface UWCConfig {
|
|
|
110
109
|
* Default 15_000.
|
|
111
110
|
*/
|
|
112
111
|
secondaryGatherTimeoutMs?: number
|
|
113
|
-
/**
|
|
114
|
-
* Namespace preference for a connect that names no `networkId`. Injected mode
|
|
115
|
-
* only, and only among namespaces whose provider detection found installed —
|
|
116
|
-
* an undetected namespace is never auto-picked. Catalog order breaks ties.
|
|
117
|
-
* Default `DEFAULT_NAMESPACE_PRIORITY` (eip155, solana, tron, tvm, bip122).
|
|
118
|
-
*/
|
|
119
|
-
preferredNamespaces?: readonly Namespace[]
|
|
120
112
|
}
|
|
121
113
|
|
|
122
114
|
/** Common options for user-initiated async operations. */
|
|
@@ -451,8 +443,7 @@ export class UniversalWalletConnector {
|
|
|
451
443
|
this.connectors,
|
|
452
444
|
configuredUsingIntegratedBrowser,
|
|
453
445
|
this.eventManager,
|
|
454
|
-
this.walletResponseTimeoutMs
|
|
455
|
-
config.preferredNamespaces ?? DEFAULT_NAMESPACE_PRIORITY
|
|
446
|
+
this.walletResponseTimeoutMs
|
|
456
447
|
)
|
|
457
448
|
this.networkSwitchService = new NetworkSwitchService(
|
|
458
449
|
networks,
|
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.7.
|
|
2
|
+
export const UWC_CORE_VERSION = '2.7.3'
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { ConnectionMode, Namespace, Network, NetworkId, SupportedProvider } from '@meshconnect/uwc-types';
|
|
2
|
-
/**
|
|
3
|
-
* Default namespace preference for an auto-picked connect network (no
|
|
4
|
-
* `networkId` passed): EVM first, then Solana, Tron, TON, Bitcoin. A caller
|
|
5
|
-
* policy, not a correctness rule — override it with `UWCConfig.preferredNamespaces`.
|
|
6
|
-
* Same order as the namespace unions used across the connectors.
|
|
7
|
-
*/
|
|
8
|
-
export declare const DEFAULT_NAMESPACE_PRIORITY: readonly Namespace[];
|
|
9
|
-
/**
|
|
10
|
-
* How the connect network was chosen, surfaced on the hand-off telemetry:
|
|
11
|
-
* - `explicit` — the caller passed a `networkId`.
|
|
12
|
-
* - `detected` — auto-picked among namespaces whose injected provider was
|
|
13
|
-
* detected, ranked by the namespace preference, catalog order breaking ties.
|
|
14
|
-
* - `catalogOrder` — legacy pick: the first configured network in the wallet's
|
|
15
|
-
* `supportedNetworkIds` (non-injected modes, or nothing detected yet).
|
|
16
|
-
*/
|
|
17
|
-
export type NetworkSelection = 'explicit' | 'detected' | 'catalogOrder';
|
|
18
|
-
/**
|
|
19
|
-
* Picks the network for a connect that named none. Candidates are the wallet's
|
|
20
|
-
* `supportedNetworkIds` that are also configured, in catalog order.
|
|
21
|
-
*
|
|
22
|
-
* For an injected connect where detection marked at least one candidate's
|
|
23
|
-
* namespace installed, only installed namespaces are eligible (connecting on an
|
|
24
|
-
* undetected namespace can only fail — e.g. Trust mobile has no
|
|
25
|
-
* `trustWallet.tronLink`), ranked by `preferredNamespaces`, catalog order
|
|
26
|
-
* breaking ties. Every other case keeps the legacy first-candidate pick, so
|
|
27
|
-
* WalletConnect / TON Connect and pre-detection connects are unchanged.
|
|
28
|
-
* Returns `undefined` when no candidate exists (the caller throws).
|
|
29
|
-
*/
|
|
30
|
-
export declare function pickAutoNetwork(provider: SupportedProvider, networks: readonly Network[], connectionMode: ConnectionMode, preferredNamespaces: readonly Namespace[]): {
|
|
31
|
-
networkId: NetworkId;
|
|
32
|
-
selection: NetworkSelection;
|
|
33
|
-
} | undefined;
|
|
34
|
-
//# sourceMappingURL=network-selection.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"network-selection.d.ts","sourceRoot":"","sources":["../../src/services/network-selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,OAAO,EACP,SAAS,EACT,iBAAiB,EAClB,MAAM,wBAAwB,CAAA;AAE/B;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,SAAS,SAAS,EAM1D,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,UAAU,GAAG,cAAc,CAAA;AAavE;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,iBAAiB,EAC3B,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,cAAc,EAAE,cAAc,EAC9B,mBAAmB,EAAE,SAAS,SAAS,EAAE,GACxC;IAAE,SAAS,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,gBAAgB,CAAA;CAAE,GAAG,SAAS,CAyBnE"}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default namespace preference for an auto-picked connect network (no
|
|
3
|
-
* `networkId` passed): EVM first, then Solana, Tron, TON, Bitcoin. A caller
|
|
4
|
-
* policy, not a correctness rule — override it with `UWCConfig.preferredNamespaces`.
|
|
5
|
-
* Same order as the namespace unions used across the connectors.
|
|
6
|
-
*/
|
|
7
|
-
export const DEFAULT_NAMESPACE_PRIORITY = [
|
|
8
|
-
'eip155',
|
|
9
|
-
'solana',
|
|
10
|
-
'tron',
|
|
11
|
-
'tvm',
|
|
12
|
-
'bip122'
|
|
13
|
-
];
|
|
14
|
-
function isNamespaceInstalled(provider, namespace) {
|
|
15
|
-
if (!('namespaceMetaData' in provider))
|
|
16
|
-
return false;
|
|
17
|
-
const meta = provider.namespaceMetaData[namespace];
|
|
18
|
-
return meta?.installed === true;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Picks the network for a connect that named none. Candidates are the wallet's
|
|
22
|
-
* `supportedNetworkIds` that are also configured, in catalog order.
|
|
23
|
-
*
|
|
24
|
-
* For an injected connect where detection marked at least one candidate's
|
|
25
|
-
* namespace installed, only installed namespaces are eligible (connecting on an
|
|
26
|
-
* undetected namespace can only fail — e.g. Trust mobile has no
|
|
27
|
-
* `trustWallet.tronLink`), ranked by `preferredNamespaces`, catalog order
|
|
28
|
-
* breaking ties. Every other case keeps the legacy first-candidate pick, so
|
|
29
|
-
* WalletConnect / TON Connect and pre-detection connects are unchanged.
|
|
30
|
-
* Returns `undefined` when no candidate exists (the caller throws).
|
|
31
|
-
*/
|
|
32
|
-
export function pickAutoNetwork(provider, networks, connectionMode, preferredNamespaces) {
|
|
33
|
-
const candidates = provider.supportedNetworkIds
|
|
34
|
-
.map(id => networks.find(n => n.id === id))
|
|
35
|
-
.filter((n) => n !== undefined);
|
|
36
|
-
const first = candidates[0];
|
|
37
|
-
if (!first)
|
|
38
|
-
return undefined;
|
|
39
|
-
if (connectionMode === 'injected') {
|
|
40
|
-
const installed = candidates.filter(n => isNamespaceInstalled(provider, n.namespace));
|
|
41
|
-
if (installed.length > 0) {
|
|
42
|
-
const rank = (namespace) => {
|
|
43
|
-
const index = preferredNamespaces.indexOf(namespace);
|
|
44
|
-
return index === -1 ? preferredNamespaces.length : index;
|
|
45
|
-
};
|
|
46
|
-
// Array.prototype.sort is stable, so equal ranks keep catalog order.
|
|
47
|
-
const [best] = [...installed].sort((a, b) => rank(a.namespace) - rank(b.namespace));
|
|
48
|
-
if (best)
|
|
49
|
-
return { networkId: best.id, selection: 'detected' };
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return { networkId: first.id, selection: 'catalogOrder' };
|
|
53
|
-
}
|
|
54
|
-
//# sourceMappingURL=network-selection.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"network-selection.js","sourceRoot":"","sources":["../../src/services/network-selection.ts"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAyB;IAC9D,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,KAAK;IACL,QAAQ;CACT,CAAA;AAYD,SAAS,oBAAoB,CAC3B,QAA2B,EAC3B,SAAoB;IAEpB,IAAI,CAAC,CAAC,mBAAmB,IAAI,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAA;IACpD,MAAM,IAAI,GAAG,QAAQ,CAAC,iBAAiB,CACrC,SAAoD,CACd,CAAA;IACxC,OAAO,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;AACjC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAC7B,QAA2B,EAC3B,QAA4B,EAC5B,cAA8B,EAC9B,mBAAyC;IAEzC,MAAM,UAAU,GAAG,QAAQ,CAAC,mBAAmB;SAC5C,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;SAC1C,MAAM,CAAC,CAAC,CAAC,EAAgB,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAA;IAC/C,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;IAC3B,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAA;IAE5B,IAAI,cAAc,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CACtC,oBAAoB,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,CAC5C,CAAA;QACD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,CAAC,SAAoB,EAAE,EAAE;gBACpC,MAAM,KAAK,GAAG,mBAAmB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;gBACpD,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAA;YAC1D,CAAC,CAAA;YACD,qEAAqE;YACrE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAChD,CAAA;YACD,IAAI,IAAI;gBAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,CAAA;QAChE,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,CAAA;AAC3D,CAAC"}
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import type { Network, SupportedProvider } from '@meshconnect/uwc-types'
|
|
3
|
-
import {
|
|
4
|
-
DEFAULT_NAMESPACE_PRIORITY,
|
|
5
|
-
pickAutoNetwork
|
|
6
|
-
} from './network-selection'
|
|
7
|
-
|
|
8
|
-
const network = (id: string, namespace: Network['namespace']): Network =>
|
|
9
|
-
({
|
|
10
|
-
id,
|
|
11
|
-
internalId: 0,
|
|
12
|
-
name: id,
|
|
13
|
-
namespace,
|
|
14
|
-
logoUrl: '',
|
|
15
|
-
networkType: 'evm',
|
|
16
|
-
nativeCurrency: { name: '', symbol: '', decimals: 18 }
|
|
17
|
-
}) as Network
|
|
18
|
-
|
|
19
|
-
const NETWORKS = [
|
|
20
|
-
network('eip155:1', 'eip155'),
|
|
21
|
-
network('eip155:81457', 'eip155'),
|
|
22
|
-
network('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', 'solana'),
|
|
23
|
-
network('tron:0x2b6653dc', 'tron'),
|
|
24
|
-
network('tvm:-239', 'tvm')
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
/** An injected provider whose namespaces carry detection's `installed` flag. */
|
|
28
|
-
const injected = (
|
|
29
|
-
supportedNetworkIds: string[],
|
|
30
|
-
installed: Partial<Record<'eip155' | 'solana' | 'tron' | 'tvm', boolean>>
|
|
31
|
-
): SupportedProvider =>
|
|
32
|
-
({
|
|
33
|
-
supportedNetworkIds,
|
|
34
|
-
namespaceMetaData: {
|
|
35
|
-
eip155: { eip155Name: 'W', installed: installed.eip155 },
|
|
36
|
-
solana: { walletStandardName: 'W', installed: installed.solana },
|
|
37
|
-
tron: { injectedId: 'w.tron', installed: installed.tron },
|
|
38
|
-
tvm: { jsBridgeKey: 'w', installed: installed.tvm }
|
|
39
|
-
}
|
|
40
|
-
}) as unknown as SupportedProvider
|
|
41
|
-
|
|
42
|
-
describe('pickAutoNetwork', () => {
|
|
43
|
-
it('skips an undetected first network (Trust mobile: Tron first, not injected)', () => {
|
|
44
|
-
const provider = injected(
|
|
45
|
-
[
|
|
46
|
-
'tron:0x2b6653dc',
|
|
47
|
-
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
48
|
-
'eip155:1'
|
|
49
|
-
],
|
|
50
|
-
{ eip155: true, solana: true, tron: false, tvm: true }
|
|
51
|
-
)
|
|
52
|
-
expect(
|
|
53
|
-
pickAutoNetwork(
|
|
54
|
-
provider,
|
|
55
|
-
NETWORKS,
|
|
56
|
-
'injected',
|
|
57
|
-
DEFAULT_NAMESPACE_PRIORITY
|
|
58
|
-
)
|
|
59
|
-
).toEqual({ networkId: 'eip155:1', selection: 'detected' })
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('keeps catalog order within a namespace', () => {
|
|
63
|
-
const provider = injected(['eip155:81457', 'eip155:1'], { eip155: true })
|
|
64
|
-
expect(
|
|
65
|
-
pickAutoNetwork(
|
|
66
|
-
provider,
|
|
67
|
-
NETWORKS,
|
|
68
|
-
'injected',
|
|
69
|
-
DEFAULT_NAMESPACE_PRIORITY
|
|
70
|
-
)?.networkId
|
|
71
|
-
).toBe('eip155:81457')
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('honours a caller-supplied namespace preference', () => {
|
|
75
|
-
const provider = injected(
|
|
76
|
-
['eip155:1', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'],
|
|
77
|
-
{ eip155: true, solana: true }
|
|
78
|
-
)
|
|
79
|
-
expect(
|
|
80
|
-
pickAutoNetwork(provider, NETWORKS, 'injected', ['solana', 'eip155'])
|
|
81
|
-
).toEqual({
|
|
82
|
-
networkId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
83
|
-
selection: 'detected'
|
|
84
|
-
})
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
it('ranks a namespace missing from the preference list last', () => {
|
|
88
|
-
const provider = injected(['tvm:-239', 'tron:0x2b6653dc'], {
|
|
89
|
-
tvm: true,
|
|
90
|
-
tron: true
|
|
91
|
-
})
|
|
92
|
-
expect(
|
|
93
|
-
pickAutoNetwork(provider, NETWORKS, 'injected', ['tron'])?.networkId
|
|
94
|
-
).toBe('tron:0x2b6653dc')
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('falls back to catalog order when nothing was detected (e.g. before detection)', () => {
|
|
98
|
-
const provider = injected(['tron:0x2b6653dc', 'eip155:1'], {})
|
|
99
|
-
expect(
|
|
100
|
-
pickAutoNetwork(
|
|
101
|
-
provider,
|
|
102
|
-
NETWORKS,
|
|
103
|
-
'injected',
|
|
104
|
-
DEFAULT_NAMESPACE_PRIORITY
|
|
105
|
-
)
|
|
106
|
-
).toEqual({ networkId: 'tron:0x2b6653dc', selection: 'catalogOrder' })
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it('leaves non-injected modes on catalog order even with installed flags', () => {
|
|
110
|
-
const provider = injected(['tron:0x2b6653dc', 'eip155:1'], {
|
|
111
|
-
eip155: true
|
|
112
|
-
})
|
|
113
|
-
expect(
|
|
114
|
-
pickAutoNetwork(
|
|
115
|
-
provider,
|
|
116
|
-
NETWORKS,
|
|
117
|
-
'walletConnect',
|
|
118
|
-
DEFAULT_NAMESPACE_PRIORITY
|
|
119
|
-
)
|
|
120
|
-
).toEqual({ networkId: 'tron:0x2b6653dc', selection: 'catalogOrder' })
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it('ignores supported networks that are not configured', () => {
|
|
124
|
-
const provider = injected(
|
|
125
|
-
['eip155:999', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'],
|
|
126
|
-
{
|
|
127
|
-
eip155: true,
|
|
128
|
-
solana: true
|
|
129
|
-
}
|
|
130
|
-
)
|
|
131
|
-
expect(
|
|
132
|
-
pickAutoNetwork(
|
|
133
|
-
provider,
|
|
134
|
-
NETWORKS,
|
|
135
|
-
'injected',
|
|
136
|
-
DEFAULT_NAMESPACE_PRIORITY
|
|
137
|
-
)?.networkId
|
|
138
|
-
).toBe('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
it('returns undefined when no supported network is configured', () => {
|
|
142
|
-
const provider = injected(['eip155:999'], { eip155: true })
|
|
143
|
-
expect(
|
|
144
|
-
pickAutoNetwork(
|
|
145
|
-
provider,
|
|
146
|
-
NETWORKS,
|
|
147
|
-
'injected',
|
|
148
|
-
DEFAULT_NAMESPACE_PRIORITY
|
|
149
|
-
)
|
|
150
|
-
).toBeUndefined()
|
|
151
|
-
})
|
|
152
|
-
})
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ConnectionMode,
|
|
3
|
-
Namespace,
|
|
4
|
-
Network,
|
|
5
|
-
NetworkId,
|
|
6
|
-
SupportedProvider
|
|
7
|
-
} from '@meshconnect/uwc-types'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Default namespace preference for an auto-picked connect network (no
|
|
11
|
-
* `networkId` passed): EVM first, then Solana, Tron, TON, Bitcoin. A caller
|
|
12
|
-
* policy, not a correctness rule — override it with `UWCConfig.preferredNamespaces`.
|
|
13
|
-
* Same order as the namespace unions used across the connectors.
|
|
14
|
-
*/
|
|
15
|
-
export const DEFAULT_NAMESPACE_PRIORITY: readonly Namespace[] = [
|
|
16
|
-
'eip155',
|
|
17
|
-
'solana',
|
|
18
|
-
'tron',
|
|
19
|
-
'tvm',
|
|
20
|
-
'bip122'
|
|
21
|
-
]
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* How the connect network was chosen, surfaced on the hand-off telemetry:
|
|
25
|
-
* - `explicit` — the caller passed a `networkId`.
|
|
26
|
-
* - `detected` — auto-picked among namespaces whose injected provider was
|
|
27
|
-
* detected, ranked by the namespace preference, catalog order breaking ties.
|
|
28
|
-
* - `catalogOrder` — legacy pick: the first configured network in the wallet's
|
|
29
|
-
* `supportedNetworkIds` (non-injected modes, or nothing detected yet).
|
|
30
|
-
*/
|
|
31
|
-
export type NetworkSelection = 'explicit' | 'detected' | 'catalogOrder'
|
|
32
|
-
|
|
33
|
-
function isNamespaceInstalled(
|
|
34
|
-
provider: SupportedProvider,
|
|
35
|
-
namespace: Namespace
|
|
36
|
-
): boolean {
|
|
37
|
-
if (!('namespaceMetaData' in provider)) return false
|
|
38
|
-
const meta = provider.namespaceMetaData[
|
|
39
|
-
namespace as keyof typeof provider.namespaceMetaData
|
|
40
|
-
] as { installed?: boolean } | undefined
|
|
41
|
-
return meta?.installed === true
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Picks the network for a connect that named none. Candidates are the wallet's
|
|
46
|
-
* `supportedNetworkIds` that are also configured, in catalog order.
|
|
47
|
-
*
|
|
48
|
-
* For an injected connect where detection marked at least one candidate's
|
|
49
|
-
* namespace installed, only installed namespaces are eligible (connecting on an
|
|
50
|
-
* undetected namespace can only fail — e.g. Trust mobile has no
|
|
51
|
-
* `trustWallet.tronLink`), ranked by `preferredNamespaces`, catalog order
|
|
52
|
-
* breaking ties. Every other case keeps the legacy first-candidate pick, so
|
|
53
|
-
* WalletConnect / TON Connect and pre-detection connects are unchanged.
|
|
54
|
-
* Returns `undefined` when no candidate exists (the caller throws).
|
|
55
|
-
*/
|
|
56
|
-
export function pickAutoNetwork(
|
|
57
|
-
provider: SupportedProvider,
|
|
58
|
-
networks: readonly Network[],
|
|
59
|
-
connectionMode: ConnectionMode,
|
|
60
|
-
preferredNamespaces: readonly Namespace[]
|
|
61
|
-
): { networkId: NetworkId; selection: NetworkSelection } | undefined {
|
|
62
|
-
const candidates = provider.supportedNetworkIds
|
|
63
|
-
.map(id => networks.find(n => n.id === id))
|
|
64
|
-
.filter((n): n is Network => n !== undefined)
|
|
65
|
-
const first = candidates[0]
|
|
66
|
-
if (!first) return undefined
|
|
67
|
-
|
|
68
|
-
if (connectionMode === 'injected') {
|
|
69
|
-
const installed = candidates.filter(n =>
|
|
70
|
-
isNamespaceInstalled(provider, n.namespace)
|
|
71
|
-
)
|
|
72
|
-
if (installed.length > 0) {
|
|
73
|
-
const rank = (namespace: Namespace) => {
|
|
74
|
-
const index = preferredNamespaces.indexOf(namespace)
|
|
75
|
-
return index === -1 ? preferredNamespaces.length : index
|
|
76
|
-
}
|
|
77
|
-
// Array.prototype.sort is stable, so equal ranks keep catalog order.
|
|
78
|
-
const [best] = [...installed].sort(
|
|
79
|
-
(a, b) => rank(a.namespace) - rank(b.namespace)
|
|
80
|
-
)
|
|
81
|
-
if (best) return { networkId: best.id, selection: 'detected' }
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return { networkId: first.id, selection: 'catalogOrder' }
|
|
86
|
-
}
|