@metamask-previews/network-enablement-controller 3.1.0-preview-cc7e30d0 → 3.1.0-preview-5460dce
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/CHANGELOG.md +12 -0
- package/dist/ChainService.cjs +128 -0
- package/dist/ChainService.cjs.map +1 -0
- package/dist/ChainService.d.cts +15 -0
- package/dist/ChainService.d.cts.map +1 -0
- package/dist/ChainService.d.mts +15 -0
- package/dist/ChainService.d.mts.map +1 -0
- package/dist/ChainService.mjs +120 -0
- package/dist/ChainService.mjs.map +1 -0
- package/dist/NetworkEnablementController.cjs +163 -15
- package/dist/NetworkEnablementController.cjs.map +1 -1
- package/dist/NetworkEnablementController.d.cts +15 -1
- package/dist/NetworkEnablementController.d.cts.map +1 -1
- package/dist/NetworkEnablementController.d.mts +15 -1
- package/dist/NetworkEnablementController.d.mts.map +1 -1
- package/dist/NetworkEnablementController.mjs +163 -15
- package/dist/NetworkEnablementController.mjs.map +1 -1
- package/dist/index.cjs +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Add `ChainService` module for SLIP-44 coin type resolution ([#7034](https://github.com/MetaMask/core/pull/7034))
|
|
13
|
+
- Add `getSlip44ByChainId()` function to resolve SLIP-44 coin types from EVM chain IDs
|
|
14
|
+
- Add `getNativeCaip19()` function to generate CAIP-19 asset identifiers for native currencies
|
|
15
|
+
- Add support for fetching chain metadata from chainid.network with caching
|
|
16
|
+
- Add `@metamask/slip44` dependency for symbol-to-coin-type mapping
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- include additional popular networks now enabled by default ([#7014](https://github.com/MetaMask/core/pull/7014))
|
|
21
|
+
|
|
10
22
|
## [3.1.0]
|
|
11
23
|
|
|
12
24
|
### Added
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getNativeCaip19 = exports.getSlip44ByChainId = void 0;
|
|
7
|
+
const controller_utils_1 = require("@metamask/controller-utils");
|
|
8
|
+
// @ts-expect-error - JSON imports need resolveJsonModule
|
|
9
|
+
const slip44_json_1 = __importDefault(require("@metamask/slip44/slip44.json"));
|
|
10
|
+
const utils_1 = require("@metamask/utils");
|
|
11
|
+
/** ---- Constants / Cache ---- */
|
|
12
|
+
const CHAINS_JSON_URL = 'https://chainid.network/chains.json';
|
|
13
|
+
const CACHE_DURATION_MS = 30 * 60 * 1000; // 30 min
|
|
14
|
+
let chainsCache = null;
|
|
15
|
+
let chainsFetchedAt = 0;
|
|
16
|
+
let inflight = null;
|
|
17
|
+
/** Build a quick symbol -> coinType map from slip44 dataset */
|
|
18
|
+
const SLIP44_BY_SYMBOL = (() => {
|
|
19
|
+
const map = {};
|
|
20
|
+
slip44_json_1.default.forEach((e) => {
|
|
21
|
+
const sym = e.symbol?.toUpperCase();
|
|
22
|
+
if (sym && typeof e.index === 'number' && !(sym in map)) {
|
|
23
|
+
map[sym] = e.index;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return map;
|
|
27
|
+
})();
|
|
28
|
+
/** Fallbacks for common native symbols */
|
|
29
|
+
const COMMON_SYMBOL_DEFAULTS = {
|
|
30
|
+
SOL: 501,
|
|
31
|
+
BTC: 0,
|
|
32
|
+
ETH: 60,
|
|
33
|
+
POL: 966,
|
|
34
|
+
MATIC: 966,
|
|
35
|
+
BNB: 714,
|
|
36
|
+
AVAX: 9000,
|
|
37
|
+
SEI: 19000118,
|
|
38
|
+
MON: 268435779,
|
|
39
|
+
FTM: 1007,
|
|
40
|
+
XDAI: 700,
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Fetch with cache + in-flight dedupe.
|
|
44
|
+
*
|
|
45
|
+
* @returns The chains JSON data.
|
|
46
|
+
*/
|
|
47
|
+
async function fetchChains() {
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
if (chainsCache && now - chainsFetchedAt < CACHE_DURATION_MS) {
|
|
50
|
+
return chainsCache;
|
|
51
|
+
}
|
|
52
|
+
if (inflight) {
|
|
53
|
+
return inflight;
|
|
54
|
+
}
|
|
55
|
+
inflight = (async () => {
|
|
56
|
+
const data = (await (0, controller_utils_1.handleFetch)(CHAINS_JSON_URL));
|
|
57
|
+
if (!Array.isArray(data)) {
|
|
58
|
+
throw new Error('chains.json: unexpected shape');
|
|
59
|
+
}
|
|
60
|
+
// Minimal validation; keep what we need
|
|
61
|
+
const parsed = data
|
|
62
|
+
.filter((x) => x && typeof x === 'object')
|
|
63
|
+
.map((x) => {
|
|
64
|
+
const nativeCurrency = x.nativeCurrency;
|
|
65
|
+
return {
|
|
66
|
+
chainId: Number(x.chainId),
|
|
67
|
+
name: x.name,
|
|
68
|
+
nativeCurrency,
|
|
69
|
+
};
|
|
70
|
+
})
|
|
71
|
+
.filter((x) => Number.isFinite(x.chainId));
|
|
72
|
+
chainsCache = parsed;
|
|
73
|
+
chainsFetchedAt = now;
|
|
74
|
+
inflight = null; // clear in-flight marker
|
|
75
|
+
return parsed;
|
|
76
|
+
})();
|
|
77
|
+
try {
|
|
78
|
+
return await inflight;
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
inflight = null;
|
|
82
|
+
throw e;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve SLIP-44 coinType for a given chainId (EVM only).
|
|
87
|
+
*
|
|
88
|
+
* @param chainId - The chain ID to resolve.
|
|
89
|
+
* @returns The SLIP-44 coin type as a string, or null if not found.
|
|
90
|
+
*/
|
|
91
|
+
async function getSlip44ByChainId(chainId) {
|
|
92
|
+
try {
|
|
93
|
+
// 1) Lookup by native symbol from chains.json
|
|
94
|
+
const chains = await fetchChains();
|
|
95
|
+
const chain = chains.find((c) => c.chainId === chainId);
|
|
96
|
+
const symbol = chain?.nativeCurrency?.symbol?.toUpperCase();
|
|
97
|
+
if (symbol) {
|
|
98
|
+
// Exact symbol match from slip44 dataset
|
|
99
|
+
const coinType = SLIP44_BY_SYMBOL[symbol] ?? COMMON_SYMBOL_DEFAULTS[symbol];
|
|
100
|
+
if (coinType !== undefined) {
|
|
101
|
+
return String(coinType);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// 2) Heuristic for ETH-based L2s: default to ETH coin type
|
|
105
|
+
// Many L2s (Arbitrum, Optimism, Base, Linea, Scroll, zkSync, etc.) use ETH as native
|
|
106
|
+
return '60';
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
// Prefer null for ergonomics (callers can fallback silently)
|
|
110
|
+
console.error(`getSlip44ByChainId(${chainId}) failed:`, err);
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.getSlip44ByChainId = getSlip44ByChainId;
|
|
115
|
+
/**
|
|
116
|
+
* Convenience: native CAIP-19 for an EVM chain.
|
|
117
|
+
*
|
|
118
|
+
* @param chainId - The chain ID to generate CAIP-19 for.
|
|
119
|
+
* @returns The CAIP-19 asset type string, or null if not found.
|
|
120
|
+
*/
|
|
121
|
+
async function getNativeCaip19(chainId) {
|
|
122
|
+
const coinType = await getSlip44ByChainId(chainId);
|
|
123
|
+
return coinType
|
|
124
|
+
? (0, utils_1.toCaipAssetType)('eip155', String(chainId), 'slip44', coinType)
|
|
125
|
+
: null;
|
|
126
|
+
}
|
|
127
|
+
exports.getNativeCaip19 = getNativeCaip19;
|
|
128
|
+
//# sourceMappingURL=ChainService.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChainService.cjs","sourceRoot":"","sources":["../src/ChainService.ts"],"names":[],"mappings":"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","sourcesContent":["import { handleFetch } from '@metamask/controller-utils';\n// @ts-expect-error - JSON imports need resolveJsonModule\nimport slip44 from '@metamask/slip44/slip44.json';\nimport { toCaipAssetType } from '@metamask/utils';\n\n/** ---- Types ---- */\ntype ChainsJsonItem = {\n chainId: number;\n name: string;\n nativeCurrency?: { symbol?: string; name?: string; decimals?: number };\n};\n\ntype Slip44Entry = {\n index: number; // the coin type (e.g., 60)\n symbol?: string; // e.g., 'ETH', 'BNB'\n name?: string; // e.g., 'Ethereum'\n};\n\n/** ---- Constants / Cache ---- */\nconst CHAINS_JSON_URL = 'https://chainid.network/chains.json';\nconst CACHE_DURATION_MS = 30 * 60 * 1000; // 30 min\n\nlet chainsCache: ChainsJsonItem[] | null = null;\nlet chainsFetchedAt = 0;\nlet inflight: Promise<ChainsJsonItem[]> | null = null;\n\n/** Build a quick symbol -> coinType map from slip44 dataset */\nconst SLIP44_BY_SYMBOL: Record<string, number> = (() => {\n const map: Record<string, number> = {};\n (slip44 as Slip44Entry[]).forEach((e) => {\n const sym = e.symbol?.toUpperCase();\n if (sym && typeof e.index === 'number' && !(sym in map)) {\n map[sym] = e.index;\n }\n });\n return map;\n})();\n\n/** Fallbacks for common native symbols */\nconst COMMON_SYMBOL_DEFAULTS: Record<string, number> = {\n SOL: 501,\n BTC: 0,\n ETH: 60,\n POL: 966,\n MATIC: 966,\n BNB: 714,\n AVAX: 9000,\n SEI: 19000118,\n MON: 268435779,\n FTM: 1007,\n XDAI: 700,\n};\n\n/**\n * Fetch with cache + in-flight dedupe.\n *\n * @returns The chains JSON data.\n */\nasync function fetchChains(): Promise<ChainsJsonItem[]> {\n const now = Date.now();\n if (chainsCache && now - chainsFetchedAt < CACHE_DURATION_MS) {\n return chainsCache;\n }\n if (inflight) {\n return inflight;\n }\n\n inflight = (async () => {\n const data = (await handleFetch(CHAINS_JSON_URL)) as unknown;\n if (!Array.isArray(data)) {\n throw new Error('chains.json: unexpected shape');\n }\n // Minimal validation; keep what we need\n const parsed = data\n .filter((x) => x && typeof x === 'object')\n .map((x: Record<string, unknown>): ChainsJsonItem => {\n const nativeCurrency = x.nativeCurrency as\n | { symbol?: string; name?: string; decimals?: number }\n | undefined;\n return {\n chainId: Number(x.chainId),\n name: x.name as string,\n nativeCurrency,\n };\n })\n .filter((x) => Number.isFinite(x.chainId));\n\n chainsCache = parsed;\n chainsFetchedAt = now;\n inflight = null; // clear in-flight marker\n return parsed;\n })();\n\n try {\n return await inflight;\n } catch (e) {\n inflight = null;\n throw e;\n }\n}\n\n/**\n * Resolve SLIP-44 coinType for a given chainId (EVM only).\n *\n * @param chainId - The chain ID to resolve.\n * @returns The SLIP-44 coin type as a string, or null if not found.\n */\nexport async function getSlip44ByChainId(\n chainId: number,\n): Promise<string | null> {\n try {\n // 1) Lookup by native symbol from chains.json\n const chains = await fetchChains();\n const chain = chains.find((c) => c.chainId === chainId);\n const symbol = chain?.nativeCurrency?.symbol?.toUpperCase();\n\n if (symbol) {\n // Exact symbol match from slip44 dataset\n const coinType =\n SLIP44_BY_SYMBOL[symbol] ?? COMMON_SYMBOL_DEFAULTS[symbol];\n if (coinType !== undefined) {\n return String(coinType);\n }\n }\n\n // 2) Heuristic for ETH-based L2s: default to ETH coin type\n // Many L2s (Arbitrum, Optimism, Base, Linea, Scroll, zkSync, etc.) use ETH as native\n return '60';\n } catch (err) {\n // Prefer null for ergonomics (callers can fallback silently)\n console.error(`getSlip44ByChainId(${chainId}) failed:`, err);\n return null;\n }\n}\n\n/**\n * Convenience: native CAIP-19 for an EVM chain.\n *\n * @param chainId - The chain ID to generate CAIP-19 for.\n * @returns The CAIP-19 asset type string, or null if not found.\n */\nexport async function getNativeCaip19(chainId: number): Promise<string | null> {\n const coinType = await getSlip44ByChainId(chainId);\n return coinType\n ? toCaipAssetType('eip155', String(chainId), 'slip44', coinType)\n : null;\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve SLIP-44 coinType for a given chainId (EVM only).
|
|
3
|
+
*
|
|
4
|
+
* @param chainId - The chain ID to resolve.
|
|
5
|
+
* @returns The SLIP-44 coin type as a string, or null if not found.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getSlip44ByChainId(chainId: number): Promise<string | null>;
|
|
8
|
+
/**
|
|
9
|
+
* Convenience: native CAIP-19 for an EVM chain.
|
|
10
|
+
*
|
|
11
|
+
* @param chainId - The chain ID to generate CAIP-19 for.
|
|
12
|
+
* @returns The CAIP-19 asset type string, or null if not found.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getNativeCaip19(chainId: number): Promise<string | null>;
|
|
15
|
+
//# sourceMappingURL=ChainService.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChainService.d.cts","sourceRoot":"","sources":["../src/ChainService.ts"],"names":[],"mappings":"AAqGA;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBxB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAK7E"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve SLIP-44 coinType for a given chainId (EVM only).
|
|
3
|
+
*
|
|
4
|
+
* @param chainId - The chain ID to resolve.
|
|
5
|
+
* @returns The SLIP-44 coin type as a string, or null if not found.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getSlip44ByChainId(chainId: number): Promise<string | null>;
|
|
8
|
+
/**
|
|
9
|
+
* Convenience: native CAIP-19 for an EVM chain.
|
|
10
|
+
*
|
|
11
|
+
* @param chainId - The chain ID to generate CAIP-19 for.
|
|
12
|
+
* @returns The CAIP-19 asset type string, or null if not found.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getNativeCaip19(chainId: number): Promise<string | null>;
|
|
15
|
+
//# sourceMappingURL=ChainService.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChainService.d.mts","sourceRoot":"","sources":["../src/ChainService.ts"],"names":[],"mappings":"AAqGA;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBxB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAK7E"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { handleFetch } from "@metamask/controller-utils";
|
|
2
|
+
// @ts-expect-error - JSON imports need resolveJsonModule
|
|
3
|
+
import slip44 from "@metamask/slip44/slip44.json" assert { type: "json" };
|
|
4
|
+
import { toCaipAssetType } from "@metamask/utils";
|
|
5
|
+
/** ---- Constants / Cache ---- */
|
|
6
|
+
const CHAINS_JSON_URL = 'https://chainid.network/chains.json';
|
|
7
|
+
const CACHE_DURATION_MS = 30 * 60 * 1000; // 30 min
|
|
8
|
+
let chainsCache = null;
|
|
9
|
+
let chainsFetchedAt = 0;
|
|
10
|
+
let inflight = null;
|
|
11
|
+
/** Build a quick symbol -> coinType map from slip44 dataset */
|
|
12
|
+
const SLIP44_BY_SYMBOL = (() => {
|
|
13
|
+
const map = {};
|
|
14
|
+
slip44.forEach((e) => {
|
|
15
|
+
const sym = e.symbol?.toUpperCase();
|
|
16
|
+
if (sym && typeof e.index === 'number' && !(sym in map)) {
|
|
17
|
+
map[sym] = e.index;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return map;
|
|
21
|
+
})();
|
|
22
|
+
/** Fallbacks for common native symbols */
|
|
23
|
+
const COMMON_SYMBOL_DEFAULTS = {
|
|
24
|
+
SOL: 501,
|
|
25
|
+
BTC: 0,
|
|
26
|
+
ETH: 60,
|
|
27
|
+
POL: 966,
|
|
28
|
+
MATIC: 966,
|
|
29
|
+
BNB: 714,
|
|
30
|
+
AVAX: 9000,
|
|
31
|
+
SEI: 19000118,
|
|
32
|
+
MON: 268435779,
|
|
33
|
+
FTM: 1007,
|
|
34
|
+
XDAI: 700,
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Fetch with cache + in-flight dedupe.
|
|
38
|
+
*
|
|
39
|
+
* @returns The chains JSON data.
|
|
40
|
+
*/
|
|
41
|
+
async function fetchChains() {
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
if (chainsCache && now - chainsFetchedAt < CACHE_DURATION_MS) {
|
|
44
|
+
return chainsCache;
|
|
45
|
+
}
|
|
46
|
+
if (inflight) {
|
|
47
|
+
return inflight;
|
|
48
|
+
}
|
|
49
|
+
inflight = (async () => {
|
|
50
|
+
const data = (await handleFetch(CHAINS_JSON_URL));
|
|
51
|
+
if (!Array.isArray(data)) {
|
|
52
|
+
throw new Error('chains.json: unexpected shape');
|
|
53
|
+
}
|
|
54
|
+
// Minimal validation; keep what we need
|
|
55
|
+
const parsed = data
|
|
56
|
+
.filter((x) => x && typeof x === 'object')
|
|
57
|
+
.map((x) => {
|
|
58
|
+
const nativeCurrency = x.nativeCurrency;
|
|
59
|
+
return {
|
|
60
|
+
chainId: Number(x.chainId),
|
|
61
|
+
name: x.name,
|
|
62
|
+
nativeCurrency,
|
|
63
|
+
};
|
|
64
|
+
})
|
|
65
|
+
.filter((x) => Number.isFinite(x.chainId));
|
|
66
|
+
chainsCache = parsed;
|
|
67
|
+
chainsFetchedAt = now;
|
|
68
|
+
inflight = null; // clear in-flight marker
|
|
69
|
+
return parsed;
|
|
70
|
+
})();
|
|
71
|
+
try {
|
|
72
|
+
return await inflight;
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
inflight = null;
|
|
76
|
+
throw e;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Resolve SLIP-44 coinType for a given chainId (EVM only).
|
|
81
|
+
*
|
|
82
|
+
* @param chainId - The chain ID to resolve.
|
|
83
|
+
* @returns The SLIP-44 coin type as a string, or null if not found.
|
|
84
|
+
*/
|
|
85
|
+
export async function getSlip44ByChainId(chainId) {
|
|
86
|
+
try {
|
|
87
|
+
// 1) Lookup by native symbol from chains.json
|
|
88
|
+
const chains = await fetchChains();
|
|
89
|
+
const chain = chains.find((c) => c.chainId === chainId);
|
|
90
|
+
const symbol = chain?.nativeCurrency?.symbol?.toUpperCase();
|
|
91
|
+
if (symbol) {
|
|
92
|
+
// Exact symbol match from slip44 dataset
|
|
93
|
+
const coinType = SLIP44_BY_SYMBOL[symbol] ?? COMMON_SYMBOL_DEFAULTS[symbol];
|
|
94
|
+
if (coinType !== undefined) {
|
|
95
|
+
return String(coinType);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// 2) Heuristic for ETH-based L2s: default to ETH coin type
|
|
99
|
+
// Many L2s (Arbitrum, Optimism, Base, Linea, Scroll, zkSync, etc.) use ETH as native
|
|
100
|
+
return '60';
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
// Prefer null for ergonomics (callers can fallback silently)
|
|
104
|
+
console.error(`getSlip44ByChainId(${chainId}) failed:`, err);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Convenience: native CAIP-19 for an EVM chain.
|
|
110
|
+
*
|
|
111
|
+
* @param chainId - The chain ID to generate CAIP-19 for.
|
|
112
|
+
* @returns The CAIP-19 asset type string, or null if not found.
|
|
113
|
+
*/
|
|
114
|
+
export async function getNativeCaip19(chainId) {
|
|
115
|
+
const coinType = await getSlip44ByChainId(chainId);
|
|
116
|
+
return coinType
|
|
117
|
+
? toCaipAssetType('eip155', String(chainId), 'slip44', coinType)
|
|
118
|
+
: null;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=ChainService.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChainService.mjs","sourceRoot":"","sources":["../src/ChainService.ts"],"names":[],"mappings":"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","sourcesContent":["import { handleFetch } from '@metamask/controller-utils';\n// @ts-expect-error - JSON imports need resolveJsonModule\nimport slip44 from '@metamask/slip44/slip44.json';\nimport { toCaipAssetType } from '@metamask/utils';\n\n/** ---- Types ---- */\ntype ChainsJsonItem = {\n chainId: number;\n name: string;\n nativeCurrency?: { symbol?: string; name?: string; decimals?: number };\n};\n\ntype Slip44Entry = {\n index: number; // the coin type (e.g., 60)\n symbol?: string; // e.g., 'ETH', 'BNB'\n name?: string; // e.g., 'Ethereum'\n};\n\n/** ---- Constants / Cache ---- */\nconst CHAINS_JSON_URL = 'https://chainid.network/chains.json';\nconst CACHE_DURATION_MS = 30 * 60 * 1000; // 30 min\n\nlet chainsCache: ChainsJsonItem[] | null = null;\nlet chainsFetchedAt = 0;\nlet inflight: Promise<ChainsJsonItem[]> | null = null;\n\n/** Build a quick symbol -> coinType map from slip44 dataset */\nconst SLIP44_BY_SYMBOL: Record<string, number> = (() => {\n const map: Record<string, number> = {};\n (slip44 as Slip44Entry[]).forEach((e) => {\n const sym = e.symbol?.toUpperCase();\n if (sym && typeof e.index === 'number' && !(sym in map)) {\n map[sym] = e.index;\n }\n });\n return map;\n})();\n\n/** Fallbacks for common native symbols */\nconst COMMON_SYMBOL_DEFAULTS: Record<string, number> = {\n SOL: 501,\n BTC: 0,\n ETH: 60,\n POL: 966,\n MATIC: 966,\n BNB: 714,\n AVAX: 9000,\n SEI: 19000118,\n MON: 268435779,\n FTM: 1007,\n XDAI: 700,\n};\n\n/**\n * Fetch with cache + in-flight dedupe.\n *\n * @returns The chains JSON data.\n */\nasync function fetchChains(): Promise<ChainsJsonItem[]> {\n const now = Date.now();\n if (chainsCache && now - chainsFetchedAt < CACHE_DURATION_MS) {\n return chainsCache;\n }\n if (inflight) {\n return inflight;\n }\n\n inflight = (async () => {\n const data = (await handleFetch(CHAINS_JSON_URL)) as unknown;\n if (!Array.isArray(data)) {\n throw new Error('chains.json: unexpected shape');\n }\n // Minimal validation; keep what we need\n const parsed = data\n .filter((x) => x && typeof x === 'object')\n .map((x: Record<string, unknown>): ChainsJsonItem => {\n const nativeCurrency = x.nativeCurrency as\n | { symbol?: string; name?: string; decimals?: number }\n | undefined;\n return {\n chainId: Number(x.chainId),\n name: x.name as string,\n nativeCurrency,\n };\n })\n .filter((x) => Number.isFinite(x.chainId));\n\n chainsCache = parsed;\n chainsFetchedAt = now;\n inflight = null; // clear in-flight marker\n return parsed;\n })();\n\n try {\n return await inflight;\n } catch (e) {\n inflight = null;\n throw e;\n }\n}\n\n/**\n * Resolve SLIP-44 coinType for a given chainId (EVM only).\n *\n * @param chainId - The chain ID to resolve.\n * @returns The SLIP-44 coin type as a string, or null if not found.\n */\nexport async function getSlip44ByChainId(\n chainId: number,\n): Promise<string | null> {\n try {\n // 1) Lookup by native symbol from chains.json\n const chains = await fetchChains();\n const chain = chains.find((c) => c.chainId === chainId);\n const symbol = chain?.nativeCurrency?.symbol?.toUpperCase();\n\n if (symbol) {\n // Exact symbol match from slip44 dataset\n const coinType =\n SLIP44_BY_SYMBOL[symbol] ?? COMMON_SYMBOL_DEFAULTS[symbol];\n if (coinType !== undefined) {\n return String(coinType);\n }\n }\n\n // 2) Heuristic for ETH-based L2s: default to ETH coin type\n // Many L2s (Arbitrum, Optimism, Base, Linea, Scroll, zkSync, etc.) use ETH as native\n return '60';\n } catch (err) {\n // Prefer null for ergonomics (callers can fallback silently)\n console.error(`getSlip44ByChainId(${chainId}) failed:`, err);\n return null;\n }\n}\n\n/**\n * Convenience: native CAIP-19 for an EVM chain.\n *\n * @param chainId - The chain ID to generate CAIP-19 for.\n * @returns The CAIP-19 asset type string, or null if not found.\n */\nexport async function getNativeCaip19(chainId: number): Promise<string | null> {\n const coinType = await getSlip44ByChainId(chainId);\n return coinType\n ? toCaipAssetType('eip155', String(chainId), 'slip44', coinType)\n : null;\n}\n"]}
|
|
@@ -4,13 +4,20 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
4
4
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
5
5
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
6
6
|
};
|
|
7
|
-
var
|
|
7
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
8
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
11
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
12
|
+
};
|
|
13
|
+
var _NetworkEnablementController_instances, _NetworkEnablementController_initialized, _NetworkEnablementController_ensureNamespaceBucket, _NetworkEnablementController_ensureSlip44NamespaceBucket, _NetworkEnablementController_isInPopularNetworksMode, _NetworkEnablementController_removeNetworkEntry, _NetworkEnablementController_onAddNetwork;
|
|
8
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
15
|
exports.NetworkEnablementController = void 0;
|
|
10
16
|
const base_controller_1 = require("@metamask/base-controller");
|
|
11
17
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
12
18
|
const keyring_api_1 = require("@metamask/keyring-api");
|
|
13
19
|
const utils_1 = require("@metamask/utils");
|
|
20
|
+
const ChainService_1 = require("./ChainService.cjs");
|
|
14
21
|
const constants_1 = require("./constants.cjs");
|
|
15
22
|
const utils_2 = require("./utils.cjs");
|
|
16
23
|
const controllerName = 'NetworkEnablementController';
|
|
@@ -25,6 +32,11 @@ const getDefaultNetworkEnablementControllerState = () => ({
|
|
|
25
32
|
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.Mainnet]]: true,
|
|
26
33
|
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.LineaMainnet]]: true,
|
|
27
34
|
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.BaseMainnet]]: true,
|
|
35
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.ArbitrumOne]]: true,
|
|
36
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.BscMainnet]]: true,
|
|
37
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.OptimismMainnet]]: true,
|
|
38
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.PolygonMainnet]]: true,
|
|
39
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.SeiMainnet]]: true,
|
|
28
40
|
},
|
|
29
41
|
[utils_1.KnownCaipNamespace.Solana]: {
|
|
30
42
|
[keyring_api_1.SolScope.Mainnet]: true,
|
|
@@ -42,6 +54,33 @@ const getDefaultNetworkEnablementControllerState = () => ({
|
|
|
42
54
|
[keyring_api_1.TrxScope.Shasta]: false,
|
|
43
55
|
},
|
|
44
56
|
},
|
|
57
|
+
slip44: {
|
|
58
|
+
[utils_1.KnownCaipNamespace.Eip155]: {
|
|
59
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.Mainnet]]: '60',
|
|
60
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.LineaMainnet]]: '69',
|
|
61
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.BaseMainnet]]: '8453',
|
|
62
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.ArbitrumOne]]: '42161',
|
|
63
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.BscMainnet]]: '56',
|
|
64
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.OptimismMainnet]]: '10',
|
|
65
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.PolygonMainnet]]: '966',
|
|
66
|
+
[controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.SeiMainnet]]: '19000118', // SEI
|
|
67
|
+
},
|
|
68
|
+
[utils_1.KnownCaipNamespace.Solana]: {
|
|
69
|
+
[keyring_api_1.SolScope.Mainnet]: '501',
|
|
70
|
+
[keyring_api_1.SolScope.Testnet]: '501',
|
|
71
|
+
[keyring_api_1.SolScope.Devnet]: '501', // SOL
|
|
72
|
+
},
|
|
73
|
+
[utils_1.KnownCaipNamespace.Bip122]: {
|
|
74
|
+
[keyring_api_1.BtcScope.Mainnet]: '0',
|
|
75
|
+
[keyring_api_1.BtcScope.Testnet]: '0',
|
|
76
|
+
[keyring_api_1.BtcScope.Signet]: '0', // BTC
|
|
77
|
+
},
|
|
78
|
+
[utils_1.KnownCaipNamespace.Tron]: {
|
|
79
|
+
[keyring_api_1.TrxScope.Mainnet]: '195',
|
|
80
|
+
[keyring_api_1.TrxScope.Nile]: '195',
|
|
81
|
+
[keyring_api_1.TrxScope.Shasta]: '195', // TRX
|
|
82
|
+
},
|
|
83
|
+
},
|
|
45
84
|
});
|
|
46
85
|
// Metadata for the controller state
|
|
47
86
|
const metadata = {
|
|
@@ -51,6 +90,12 @@ const metadata = {
|
|
|
51
90
|
includeInDebugSnapshot: true,
|
|
52
91
|
usedInUi: true,
|
|
53
92
|
},
|
|
93
|
+
slip44: {
|
|
94
|
+
includeInStateLogs: true,
|
|
95
|
+
persist: true,
|
|
96
|
+
includeInDebugSnapshot: true,
|
|
97
|
+
usedInUi: true,
|
|
98
|
+
},
|
|
54
99
|
};
|
|
55
100
|
/**
|
|
56
101
|
* Controller responsible for managing network enablement state across different blockchain networks.
|
|
@@ -80,8 +125,12 @@ class NetworkEnablementController extends base_controller_1.BaseController {
|
|
|
80
125
|
},
|
|
81
126
|
});
|
|
82
127
|
_NetworkEnablementController_instances.add(this);
|
|
128
|
+
_NetworkEnablementController_initialized.set(this, false);
|
|
83
129
|
messenger.subscribe('NetworkController:networkAdded', ({ chainId }) => {
|
|
84
|
-
|
|
130
|
+
// Handle async network addition
|
|
131
|
+
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_onAddNetwork).call(this, chainId).catch((error) => {
|
|
132
|
+
console.error('Error adding network:', error);
|
|
133
|
+
});
|
|
85
134
|
});
|
|
86
135
|
messenger.subscribe('NetworkController:networkRemoved', ({ chainId }) => {
|
|
87
136
|
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_removeNetworkEntry).call(this, chainId);
|
|
@@ -144,8 +193,9 @@ class NetworkEnablementController extends base_controller_1.BaseController {
|
|
|
144
193
|
throw new Error(`Chain ID ${chainId} belongs to namespace ${derivedNamespace}, but namespace ${namespace} was specified`);
|
|
145
194
|
}
|
|
146
195
|
this.update((s) => {
|
|
147
|
-
// Ensure the namespace
|
|
196
|
+
// Ensure the namespace buckets exist
|
|
148
197
|
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, s, namespace);
|
|
198
|
+
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureSlip44NamespaceBucket).call(this, s, namespace);
|
|
149
199
|
// Disable all networks in the specified namespace first
|
|
150
200
|
if (s.enabledNetworkMap[namespace]) {
|
|
151
201
|
Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {
|
|
@@ -182,8 +232,9 @@ class NetworkEnablementController extends base_controller_1.BaseController {
|
|
|
182
232
|
const { namespace, storageKey } = (0, utils_2.deriveKeys)(chainId);
|
|
183
233
|
// Check if network exists in NetworkController configurations
|
|
184
234
|
if (networkControllerState.networkConfigurationsByChainId[chainId]) {
|
|
185
|
-
// Ensure namespace
|
|
235
|
+
// Ensure namespace buckets exist
|
|
186
236
|
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, s, namespace);
|
|
237
|
+
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureSlip44NamespaceBucket).call(this, s, namespace);
|
|
187
238
|
// Enable the network
|
|
188
239
|
s.enabledNetworkMap[namespace][storageKey] = true;
|
|
189
240
|
}
|
|
@@ -191,16 +242,18 @@ class NetworkEnablementController extends base_controller_1.BaseController {
|
|
|
191
242
|
// Enable Solana mainnet if it exists in MultichainNetworkController configurations
|
|
192
243
|
const solanaKeys = (0, utils_2.deriveKeys)(keyring_api_1.SolScope.Mainnet);
|
|
193
244
|
if (multichainState.multichainNetworkConfigurationsByChainId[keyring_api_1.SolScope.Mainnet]) {
|
|
194
|
-
// Ensure namespace
|
|
245
|
+
// Ensure namespace buckets exist
|
|
195
246
|
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, s, solanaKeys.namespace);
|
|
247
|
+
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureSlip44NamespaceBucket).call(this, s, solanaKeys.namespace);
|
|
196
248
|
// Enable Solana mainnet
|
|
197
249
|
s.enabledNetworkMap[solanaKeys.namespace][solanaKeys.storageKey] = true;
|
|
198
250
|
}
|
|
199
251
|
// Enable Bitcoin mainnet if it exists in MultichainNetworkController configurations
|
|
200
252
|
const bitcoinKeys = (0, utils_2.deriveKeys)(keyring_api_1.BtcScope.Mainnet);
|
|
201
253
|
if (multichainState.multichainNetworkConfigurationsByChainId[keyring_api_1.BtcScope.Mainnet]) {
|
|
202
|
-
// Ensure namespace
|
|
254
|
+
// Ensure namespace buckets exist
|
|
203
255
|
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, s, bitcoinKeys.namespace);
|
|
256
|
+
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureSlip44NamespaceBucket).call(this, s, bitcoinKeys.namespace);
|
|
204
257
|
// Enable Bitcoin mainnet
|
|
205
258
|
s.enabledNetworkMap[bitcoinKeys.namespace][bitcoinKeys.storageKey] =
|
|
206
259
|
true;
|
|
@@ -208,8 +261,9 @@ class NetworkEnablementController extends base_controller_1.BaseController {
|
|
|
208
261
|
// Enable Tron mainnet if it exists in MultichainNetworkController configurations
|
|
209
262
|
const tronKeys = (0, utils_2.deriveKeys)(keyring_api_1.TrxScope.Mainnet);
|
|
210
263
|
if (multichainState.multichainNetworkConfigurationsByChainId[keyring_api_1.TrxScope.Mainnet]) {
|
|
211
|
-
// Ensure namespace
|
|
264
|
+
// Ensure namespace buckets exist
|
|
212
265
|
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, s, tronKeys.namespace);
|
|
266
|
+
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureSlip44NamespaceBucket).call(this, s, tronKeys.namespace);
|
|
213
267
|
// Enable Tron mainnet
|
|
214
268
|
s.enabledNetworkMap[tronKeys.namespace][tronKeys.storageKey] = true;
|
|
215
269
|
}
|
|
@@ -222,20 +276,29 @@ class NetworkEnablementController extends base_controller_1.BaseController {
|
|
|
222
276
|
* and MultichainNetworkController and syncs the enabled network map accordingly.
|
|
223
277
|
* It ensures proper namespace buckets exist for all configured networks and only
|
|
224
278
|
* adds missing networks with a default value of false, preserving existing user settings.
|
|
279
|
+
* Additionally, it fetches slip44 values for EIP-155 networks that don't have them.
|
|
280
|
+
*
|
|
281
|
+
* This method only runs once per controller instance to avoid unnecessary API calls.
|
|
282
|
+
* Subsequent calls will return immediately without performing any operations.
|
|
283
|
+
* Use `reinit()` if you need to force re-initialization.
|
|
225
284
|
*
|
|
226
285
|
* This method should be called after the NetworkController and MultichainNetworkController
|
|
227
286
|
* have been initialized and their configurations are available.
|
|
228
287
|
*/
|
|
229
|
-
init() {
|
|
288
|
+
async init() {
|
|
289
|
+
if (__classPrivateFieldGet(this, _NetworkEnablementController_initialized, "f")) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
// Get network configurations
|
|
293
|
+
const networkControllerState = this.messenger.call('NetworkController:getState');
|
|
294
|
+
const multichainState = this.messenger.call('MultichainNetworkController:getState');
|
|
295
|
+
// First, initialize the state synchronously
|
|
230
296
|
this.update((s) => {
|
|
231
|
-
// Get network configurations from NetworkController (EVM networks)
|
|
232
|
-
const networkControllerState = this.messenger.call('NetworkController:getState');
|
|
233
|
-
// Get network configurations from MultichainNetworkController (all networks)
|
|
234
|
-
const multichainState = this.messenger.call('MultichainNetworkController:getState');
|
|
235
297
|
// Initialize namespace buckets for EVM networks from NetworkController
|
|
236
298
|
Object.keys(networkControllerState.networkConfigurationsByChainId).forEach((chainId) => {
|
|
237
299
|
const { namespace, storageKey } = (0, utils_2.deriveKeys)(chainId);
|
|
238
300
|
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, s, namespace);
|
|
301
|
+
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureSlip44NamespaceBucket).call(this, s, namespace);
|
|
239
302
|
// Only add network if it doesn't already exist in state (preserves user settings)
|
|
240
303
|
if (s.enabledNetworkMap[namespace][storageKey] === undefined) {
|
|
241
304
|
s.enabledNetworkMap[namespace][storageKey] = false;
|
|
@@ -245,12 +308,63 @@ class NetworkEnablementController extends base_controller_1.BaseController {
|
|
|
245
308
|
Object.keys(multichainState.multichainNetworkConfigurationsByChainId).forEach((chainId) => {
|
|
246
309
|
const { namespace, storageKey } = (0, utils_2.deriveKeys)(chainId);
|
|
247
310
|
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, s, namespace);
|
|
311
|
+
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureSlip44NamespaceBucket).call(this, s, namespace);
|
|
248
312
|
// Only add network if it doesn't already exist in state (preserves user settings)
|
|
249
313
|
if (s.enabledNetworkMap[namespace][storageKey] === undefined) {
|
|
250
314
|
s.enabledNetworkMap[namespace][storageKey] = false;
|
|
251
315
|
}
|
|
252
316
|
});
|
|
253
317
|
});
|
|
318
|
+
// Collect EIP-155 networks that need slip44 values
|
|
319
|
+
const networksToFetch = [];
|
|
320
|
+
Object.keys(networkControllerState.networkConfigurationsByChainId).forEach((chainId) => {
|
|
321
|
+
const { namespace, storageKey, reference } = (0, utils_2.deriveKeys)(chainId);
|
|
322
|
+
if (namespace === 'eip155') {
|
|
323
|
+
// Check if slip44 value already exists in state
|
|
324
|
+
const existingSlip44 = this.state.slip44[namespace]?.[storageKey];
|
|
325
|
+
if (!existingSlip44) {
|
|
326
|
+
const numericChainId = parseInt(reference, 16);
|
|
327
|
+
networksToFetch.push({ chainId, storageKey, numericChainId });
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
// Fetch slip44 values for networks that don't have them
|
|
332
|
+
if (networksToFetch.length > 0) {
|
|
333
|
+
const slip44Promises = networksToFetch.map(async ({ chainId, storageKey, numericChainId }) => {
|
|
334
|
+
try {
|
|
335
|
+
const slip44Value = await (0, ChainService_1.getSlip44ByChainId)(numericChainId);
|
|
336
|
+
return { chainId, storageKey, slip44Value };
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
console.error(`Failed to fetch slip44 for chainId ${chainId}:`, error);
|
|
340
|
+
return { chainId, storageKey, slip44Value: null };
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
const results = await Promise.all(slip44Promises);
|
|
344
|
+
// Update state with fetched slip44 values
|
|
345
|
+
this.update((s) => {
|
|
346
|
+
results.forEach(({ storageKey, slip44Value }) => {
|
|
347
|
+
if (slip44Value !== null) {
|
|
348
|
+
// Ensure namespace exists (should already exist from above)
|
|
349
|
+
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureSlip44NamespaceBucket).call(this, s, 'eip155');
|
|
350
|
+
// @ts-expect-error - TypeScript doesn't recognize the dynamic namespace access
|
|
351
|
+
s.slip44.eip155[storageKey] = slip44Value;
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
__classPrivateFieldSet(this, _NetworkEnablementController_initialized, true, "f");
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Re-initializes the controller's state.
|
|
360
|
+
*
|
|
361
|
+
* This method forces a fresh initialization even if the controller has already been initialized.
|
|
362
|
+
* It will re-fetch slip44 values for all EIP-155 networks and re-sync the network state.
|
|
363
|
+
* Use this when you need to force a full re-initialization.
|
|
364
|
+
*/
|
|
365
|
+
async reinit() {
|
|
366
|
+
__classPrivateFieldSet(this, _NetworkEnablementController_initialized, false, "f");
|
|
367
|
+
await this.init();
|
|
254
368
|
}
|
|
255
369
|
/**
|
|
256
370
|
* Disables a network for the user.
|
|
@@ -288,10 +402,14 @@ class NetworkEnablementController extends base_controller_1.BaseController {
|
|
|
288
402
|
}
|
|
289
403
|
}
|
|
290
404
|
exports.NetworkEnablementController = NetworkEnablementController;
|
|
291
|
-
_NetworkEnablementController_instances = new WeakSet(), _NetworkEnablementController_ensureNamespaceBucket = function _NetworkEnablementController_ensureNamespaceBucket(state, ns) {
|
|
405
|
+
_NetworkEnablementController_initialized = new WeakMap(), _NetworkEnablementController_instances = new WeakSet(), _NetworkEnablementController_ensureNamespaceBucket = function _NetworkEnablementController_ensureNamespaceBucket(state, ns) {
|
|
292
406
|
if (!state.enabledNetworkMap[ns]) {
|
|
293
407
|
state.enabledNetworkMap[ns] = {};
|
|
294
408
|
}
|
|
409
|
+
}, _NetworkEnablementController_ensureSlip44NamespaceBucket = function _NetworkEnablementController_ensureSlip44NamespaceBucket(state, ns) {
|
|
410
|
+
if (!state.slip44[ns]) {
|
|
411
|
+
state.slip44[ns] = {};
|
|
412
|
+
}
|
|
295
413
|
}, _NetworkEnablementController_isInPopularNetworksMode = function _NetworkEnablementController_isInPopularNetworksMode() {
|
|
296
414
|
// Get current network configurations to check which popular networks exist
|
|
297
415
|
const networkControllerState = this.messenger.call('NetworkController:getState');
|
|
@@ -320,11 +438,41 @@ _NetworkEnablementController_instances = new WeakSet(), _NetworkEnablementContro
|
|
|
320
438
|
delete s.enabledNetworkMap[namespace][storageKey];
|
|
321
439
|
}
|
|
322
440
|
});
|
|
323
|
-
}, _NetworkEnablementController_onAddNetwork =
|
|
441
|
+
}, _NetworkEnablementController_onAddNetwork =
|
|
442
|
+
/**
|
|
443
|
+
* Handles the addition of a new network to the controller.
|
|
444
|
+
*
|
|
445
|
+
* @param chainId - The chain ID to add (Hex or CAIP-2 format)
|
|
446
|
+
*
|
|
447
|
+
* @description
|
|
448
|
+
* - If in popular networks mode (>2 popular networks enabled) AND adding a popular network:
|
|
449
|
+
* - Keep current selection (add but don't enable the new network)
|
|
450
|
+
* - Otherwise:
|
|
451
|
+
* - Switch to the newly added network (disable all others, enable this one)
|
|
452
|
+
* - Fetches and stores slip44 value for EIP-155 networks
|
|
453
|
+
*/
|
|
454
|
+
async function _NetworkEnablementController_onAddNetwork(chainId) {
|
|
324
455
|
const { namespace, storageKey, reference } = (0, utils_2.deriveKeys)(chainId);
|
|
456
|
+
// Fetch slip44 for EIP-155 networks
|
|
457
|
+
let slip44Value = null;
|
|
458
|
+
if (namespace === 'eip155') {
|
|
459
|
+
try {
|
|
460
|
+
// Convert hex chainId to decimal for the API call
|
|
461
|
+
const numericChainId = parseInt(reference);
|
|
462
|
+
slip44Value = await (0, ChainService_1.getSlip44ByChainId)(numericChainId);
|
|
463
|
+
}
|
|
464
|
+
catch (error) {
|
|
465
|
+
console.error(`Failed to fetch slip44 for chainId ${chainId}:`, error);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
325
468
|
this.update((s) => {
|
|
326
|
-
// Ensure the namespace
|
|
469
|
+
// Ensure the namespace buckets exist
|
|
327
470
|
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, s, namespace);
|
|
471
|
+
__classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureSlip44NamespaceBucket).call(this, s, namespace);
|
|
472
|
+
// Add slip44 value if fetched successfully
|
|
473
|
+
if (slip44Value !== null) {
|
|
474
|
+
s.slip44[namespace][storageKey] = slip44Value;
|
|
475
|
+
}
|
|
328
476
|
// Check if popular networks mode is active (>2 popular networks enabled)
|
|
329
477
|
const inPopularNetworksMode = __classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_isInPopularNetworksMode).call(this);
|
|
330
478
|
// Check if the network being added is a popular network
|