@metamask-previews/assets-controller 0.0.0-preview-8a281087 → 0.0.0-preview-69f51f81
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/data-sources/SnapDataSource.cjs +464 -193
- package/dist/data-sources/SnapDataSource.cjs.map +1 -1
- package/dist/data-sources/SnapDataSource.d.cts +86 -24
- package/dist/data-sources/SnapDataSource.d.cts.map +1 -1
- package/dist/data-sources/SnapDataSource.d.mts +86 -24
- package/dist/data-sources/SnapDataSource.d.mts.map +1 -1
- package/dist/data-sources/SnapDataSource.mjs +458 -191
- package/dist/data-sources/SnapDataSource.mjs.map +1 -1
- package/dist/data-sources/index.cjs +36 -7
- package/dist/data-sources/index.cjs.map +1 -1
- package/dist/data-sources/index.d.cts +1 -1
- package/dist/data-sources/index.d.cts.map +1 -1
- package/dist/data-sources/index.d.mts +1 -1
- package/dist/data-sources/index.d.mts.map +1 -1
- package/dist/data-sources/index.mjs +13 -5
- package/dist/data-sources/index.mjs.map +1 -1
- package/dist/data-sources/initDataSources.cjs +3 -9
- package/dist/data-sources/initDataSources.cjs.map +1 -1
- package/dist/data-sources/initDataSources.d.cts +4 -2
- package/dist/data-sources/initDataSources.d.cts.map +1 -1
- package/dist/data-sources/initDataSources.d.mts +4 -2
- package/dist/data-sources/initDataSources.d.mts.map +1 -1
- package/dist/data-sources/initDataSources.mjs +3 -9
- package/dist/data-sources/initDataSources.mjs.map +1 -1
- package/dist/index.cjs +36 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +13 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -6
|
@@ -10,11 +10,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
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");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var _SnapDataSource_instances, _SnapDataSource_messenger,
|
|
13
|
+
var _SnapDataSource_instances, _SnapDataSource_messenger, _SnapDataSource_snapProvider, _SnapDataSource_subscribeToSnapKeyringEvents, _SnapDataSource_handleSnapBalancesUpdated, _SnapDataSource_registerActionHandlers, _SnapDataSource_getInstalledSnaps, _SnapDataSource_checkSnapAvailabilityOnDemand, _SnapDataSource_checkAllSnapsAvailability, _SnapDataSource_accountSupportsChain, _SnapDataSource_groupChainsBySnap, _SnapDataSource_fetchFromSnap;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.createSnapDataSource = exports.SnapDataSource = exports.extractChainFromAssetId = exports.
|
|
16
|
-
const keyring_snap_client_1 = require("@metamask/keyring-snap-client");
|
|
17
|
-
const snaps_utils_1 = require("@metamask/snaps-utils");
|
|
15
|
+
exports.createSnapDataSource = exports.SnapDataSource = exports.isTronChain = exports.isBitcoinChain = exports.isSolanaChain = exports.extractChainFromAssetId = exports.isSnapSupportedChain = exports.getSnapTypeForChain = exports.SNAP_REGISTRY = exports.ALL_DEFAULT_NETWORKS = exports.DEFAULT_SNAP_POLL_INTERVAL = exports.DEFAULT_TRON_POLL_INTERVAL = exports.DEFAULT_BITCOIN_POLL_INTERVAL = exports.DEFAULT_SOLANA_POLL_INTERVAL = exports.TRON_NILE_HEX = exports.TRON_SHASTA_HEX = exports.TRON_MAINNET_HEX = exports.TRON_NILE = exports.TRON_SHASTA = exports.TRON_MAINNET = exports.BITCOIN_TESTNET = exports.BITCOIN_MAINNET = exports.SOLANA_TESTNET = exports.SOLANA_DEVNET = exports.SOLANA_MAINNET = exports.TRON_CHAIN_PREFIX = exports.BITCOIN_CHAIN_PREFIX = exports.SOLANA_CHAIN_PREFIX = exports.TRON_SNAP_ID = exports.BITCOIN_SNAP_ID = exports.SOLANA_SNAP_ID = exports.SNAP_DATA_SOURCE_NAME = void 0;
|
|
18
16
|
const AbstractDataSource_1 = require("./AbstractDataSource.cjs");
|
|
19
17
|
const logger_1 = require("../logger.cjs");
|
|
20
18
|
const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, 'SnapDataSource');
|
|
@@ -22,31 +20,92 @@ const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, 'SnapDataSo
|
|
|
22
20
|
// CONSTANTS
|
|
23
21
|
// ============================================================================
|
|
24
22
|
exports.SNAP_DATA_SOURCE_NAME = 'SnapDataSource';
|
|
25
|
-
|
|
26
|
-
exports.
|
|
27
|
-
|
|
28
|
-
exports.
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
// Snap IDs
|
|
24
|
+
exports.SOLANA_SNAP_ID = 'npm:@metamask/solana-wallet-snap';
|
|
25
|
+
exports.BITCOIN_SNAP_ID = 'npm:@metamask/bitcoin-wallet-snap';
|
|
26
|
+
exports.TRON_SNAP_ID = 'npm:@metamask/tron-wallet-snap';
|
|
27
|
+
// Chain prefixes for detection
|
|
28
|
+
exports.SOLANA_CHAIN_PREFIX = 'solana:';
|
|
29
|
+
exports.BITCOIN_CHAIN_PREFIX = 'bip122:';
|
|
30
|
+
exports.TRON_CHAIN_PREFIX = 'tron:';
|
|
31
|
+
// Default networks
|
|
32
|
+
exports.SOLANA_MAINNET = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';
|
|
33
|
+
exports.SOLANA_DEVNET = 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1';
|
|
34
|
+
exports.SOLANA_TESTNET = 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z';
|
|
35
|
+
exports.BITCOIN_MAINNET = 'bip122:000000000019d6689c085ae165831e93';
|
|
36
|
+
exports.BITCOIN_TESTNET = 'bip122:000000000933ea01ad0ee984209779ba';
|
|
37
|
+
exports.TRON_MAINNET = 'tron:728126428';
|
|
38
|
+
exports.TRON_SHASTA = 'tron:2494104990';
|
|
39
|
+
exports.TRON_NILE = 'tron:3448148188';
|
|
40
|
+
// Hex format alternatives for Tron
|
|
41
|
+
exports.TRON_MAINNET_HEX = 'tron:0x2b6653dc';
|
|
42
|
+
exports.TRON_SHASTA_HEX = 'tron:0x94a9059e';
|
|
43
|
+
exports.TRON_NILE_HEX = 'tron:0xcd8690dc';
|
|
44
|
+
// Default poll intervals
|
|
45
|
+
exports.DEFAULT_SOLANA_POLL_INTERVAL = 30000; // 30 seconds
|
|
46
|
+
exports.DEFAULT_BITCOIN_POLL_INTERVAL = 60000; // 1 minute
|
|
47
|
+
exports.DEFAULT_TRON_POLL_INTERVAL = 30000; // 30 seconds
|
|
48
|
+
exports.DEFAULT_SNAP_POLL_INTERVAL = 30000; // Default for unknown snaps
|
|
49
|
+
// All default networks
|
|
50
|
+
exports.ALL_DEFAULT_NETWORKS = [
|
|
51
|
+
exports.SOLANA_MAINNET,
|
|
52
|
+
exports.SOLANA_DEVNET,
|
|
53
|
+
exports.SOLANA_TESTNET,
|
|
54
|
+
exports.BITCOIN_MAINNET,
|
|
55
|
+
exports.BITCOIN_TESTNET,
|
|
56
|
+
exports.TRON_MAINNET,
|
|
57
|
+
exports.TRON_SHASTA,
|
|
58
|
+
exports.TRON_NILE,
|
|
59
|
+
exports.TRON_MAINNET_HEX,
|
|
60
|
+
exports.TRON_SHASTA_HEX,
|
|
61
|
+
exports.TRON_NILE_HEX,
|
|
62
|
+
];
|
|
63
|
+
exports.SNAP_REGISTRY = {
|
|
64
|
+
solana: {
|
|
65
|
+
snapId: exports.SOLANA_SNAP_ID,
|
|
66
|
+
chainPrefix: exports.SOLANA_CHAIN_PREFIX,
|
|
67
|
+
pollInterval: exports.DEFAULT_SOLANA_POLL_INTERVAL,
|
|
68
|
+
},
|
|
69
|
+
bitcoin: {
|
|
70
|
+
snapId: exports.BITCOIN_SNAP_ID,
|
|
71
|
+
chainPrefix: exports.BITCOIN_CHAIN_PREFIX,
|
|
72
|
+
pollInterval: exports.DEFAULT_BITCOIN_POLL_INTERVAL,
|
|
73
|
+
},
|
|
74
|
+
tron: {
|
|
75
|
+
snapId: exports.TRON_SNAP_ID,
|
|
76
|
+
chainPrefix: exports.TRON_CHAIN_PREFIX,
|
|
77
|
+
pollInterval: exports.DEFAULT_TRON_POLL_INTERVAL,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
32
80
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* This does basic validation of the caveat, but does not validate the type or
|
|
36
|
-
* value of the namespaces object itself, as this is handled by the
|
|
37
|
-
* `PermissionsController` when the permission is requested.
|
|
81
|
+
* Get the snap type for a chain ID based on its prefix.
|
|
38
82
|
*
|
|
39
|
-
* @param
|
|
40
|
-
* @returns
|
|
83
|
+
* @param chainId - The CAIP-2 chain ID to check.
|
|
84
|
+
* @returns The snap type for the chain, or null if not supported.
|
|
41
85
|
*/
|
|
42
|
-
function
|
|
43
|
-
if (
|
|
44
|
-
return
|
|
86
|
+
function getSnapTypeForChain(chainId) {
|
|
87
|
+
if (chainId.startsWith(exports.SOLANA_CHAIN_PREFIX)) {
|
|
88
|
+
return 'solana';
|
|
45
89
|
}
|
|
46
|
-
|
|
47
|
-
|
|
90
|
+
if (chainId.startsWith(exports.BITCOIN_CHAIN_PREFIX)) {
|
|
91
|
+
return 'bitcoin';
|
|
92
|
+
}
|
|
93
|
+
if (chainId.startsWith(exports.TRON_CHAIN_PREFIX)) {
|
|
94
|
+
return 'tron';
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
exports.getSnapTypeForChain = getSnapTypeForChain;
|
|
99
|
+
/**
|
|
100
|
+
* Check if a chain ID is supported by a snap.
|
|
101
|
+
*
|
|
102
|
+
* @param chainId - The CAIP-2 chain ID to check.
|
|
103
|
+
* @returns True if the chain is supported by a snap.
|
|
104
|
+
*/
|
|
105
|
+
function isSnapSupportedChain(chainId) {
|
|
106
|
+
return getSnapTypeForChain(chainId) !== null;
|
|
48
107
|
}
|
|
49
|
-
exports.
|
|
108
|
+
exports.isSnapSupportedChain = isSnapSupportedChain;
|
|
50
109
|
/**
|
|
51
110
|
* Extract chain ID from a CAIP-19 asset ID.
|
|
52
111
|
* e.g., "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501" -> "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
|
|
@@ -59,9 +118,26 @@ function extractChainFromAssetId(assetId) {
|
|
|
59
118
|
return parts[0];
|
|
60
119
|
}
|
|
61
120
|
exports.extractChainFromAssetId = extractChainFromAssetId;
|
|
121
|
+
// Helper functions for specific chain types
|
|
122
|
+
function isSolanaChain(chainId) {
|
|
123
|
+
return chainId.startsWith(exports.SOLANA_CHAIN_PREFIX);
|
|
124
|
+
}
|
|
125
|
+
exports.isSolanaChain = isSolanaChain;
|
|
126
|
+
function isBitcoinChain(chainId) {
|
|
127
|
+
return chainId.startsWith(exports.BITCOIN_CHAIN_PREFIX);
|
|
128
|
+
}
|
|
129
|
+
exports.isBitcoinChain = isBitcoinChain;
|
|
130
|
+
function isTronChain(chainId) {
|
|
131
|
+
return chainId.startsWith(exports.TRON_CHAIN_PREFIX);
|
|
132
|
+
}
|
|
133
|
+
exports.isTronChain = isTronChain;
|
|
62
134
|
const defaultSnapState = {
|
|
63
|
-
activeChains:
|
|
64
|
-
|
|
135
|
+
activeChains: exports.ALL_DEFAULT_NETWORKS,
|
|
136
|
+
snaps: {
|
|
137
|
+
solana: { version: null, available: false },
|
|
138
|
+
bitcoin: { version: null, available: false },
|
|
139
|
+
tron: { version: null, available: false },
|
|
140
|
+
},
|
|
65
141
|
};
|
|
66
142
|
// ============================================================================
|
|
67
143
|
// SNAP DATA SOURCE
|
|
@@ -70,10 +146,16 @@ const defaultSnapState = {
|
|
|
70
146
|
* Unified Snap data source that routes requests to the appropriate wallet snap
|
|
71
147
|
* based on the chain ID prefix.
|
|
72
148
|
*
|
|
149
|
+
* Supports:
|
|
150
|
+
* - Solana chains (solana:*) → @metamask/solana-wallet-snap
|
|
151
|
+
* - Bitcoin chains (bip122:*) → @metamask/bitcoin-wallet-snap
|
|
152
|
+
* - Tron chains (tron:*) → @metamask/tron-wallet-snap
|
|
153
|
+
*
|
|
73
154
|
* @example
|
|
74
155
|
* ```typescript
|
|
75
156
|
* const snapDataSource = new SnapDataSource({
|
|
76
157
|
* messenger,
|
|
158
|
+
* snapProvider: metamaskProvider,
|
|
77
159
|
* });
|
|
78
160
|
*
|
|
79
161
|
* // Fetch will automatically route to the correct snap
|
|
@@ -85,81 +167,122 @@ const defaultSnapState = {
|
|
|
85
167
|
*/
|
|
86
168
|
class SnapDataSource extends AbstractDataSource_1.AbstractDataSource {
|
|
87
169
|
constructor(options) {
|
|
170
|
+
const configuredNetworks = options.configuredNetworks ?? exports.ALL_DEFAULT_NETWORKS;
|
|
88
171
|
super(exports.SNAP_DATA_SOURCE_NAME, {
|
|
89
172
|
...defaultSnapState,
|
|
90
173
|
...options.state,
|
|
174
|
+
activeChains: configuredNetworks,
|
|
91
175
|
});
|
|
92
176
|
_SnapDataSource_instances.add(this);
|
|
93
177
|
_SnapDataSource_messenger.set(this, void 0);
|
|
94
|
-
|
|
95
|
-
_SnapDataSource_handleSnapBalancesUpdatedBound.set(this, void 0);
|
|
96
|
-
_SnapDataSource_handlePermissionStateChangeBound.set(this, void 0);
|
|
97
|
-
/** Cache of KeyringClient instances per snap ID to avoid re-instantiation */
|
|
98
|
-
_SnapDataSource_keyringClientCache.set(this, new Map());
|
|
178
|
+
_SnapDataSource_snapProvider.set(this, void 0);
|
|
99
179
|
__classPrivateFieldSet(this, _SnapDataSource_messenger, options.messenger, "f");
|
|
100
|
-
|
|
101
|
-
__classPrivateFieldSet(this, _SnapDataSource_handleSnapBalancesUpdatedBound, __classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_handleSnapBalancesUpdated).bind(this), "f");
|
|
102
|
-
__classPrivateFieldSet(this, _SnapDataSource_handlePermissionStateChangeBound, __classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_discoverKeyringSnaps).bind(this), "f");
|
|
180
|
+
__classPrivateFieldSet(this, _SnapDataSource_snapProvider, options.snapProvider, "f");
|
|
103
181
|
__classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_registerActionHandlers).call(this);
|
|
104
|
-
__classPrivateFieldGet(this, _SnapDataSource_instances, "m",
|
|
105
|
-
//
|
|
106
|
-
__classPrivateFieldGet(this, _SnapDataSource_instances, "m",
|
|
182
|
+
__classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_subscribeToSnapKeyringEvents).call(this);
|
|
183
|
+
// Check availability for all snaps on initialization
|
|
184
|
+
__classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_checkAllSnapsAvailability).call(this).catch(() => {
|
|
185
|
+
// Silently ignore availability check failures on init
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get info about all snaps.
|
|
190
|
+
*
|
|
191
|
+
* @returns Record of snap info keyed by snap type.
|
|
192
|
+
*/
|
|
193
|
+
getSnapsInfo() {
|
|
194
|
+
const result = {};
|
|
195
|
+
for (const [snapType, config] of Object.entries(exports.SNAP_REGISTRY)) {
|
|
196
|
+
const state = this.state.snaps[snapType];
|
|
197
|
+
result[snapType] = {
|
|
198
|
+
...config,
|
|
199
|
+
version: state.version,
|
|
200
|
+
available: state.available,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Check if a specific snap is available.
|
|
207
|
+
*
|
|
208
|
+
* @param snapType - The snap type to check (solana, bitcoin, tron).
|
|
209
|
+
* @returns True if the snap is available.
|
|
210
|
+
*/
|
|
211
|
+
isSnapAvailable(snapType) {
|
|
212
|
+
return this.state.snaps[snapType]?.available ?? false;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Force refresh snap availability check.
|
|
216
|
+
*/
|
|
217
|
+
async refreshSnapsStatus() {
|
|
218
|
+
await __classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_checkAllSnapsAvailability).call(this);
|
|
107
219
|
}
|
|
108
220
|
// ============================================================================
|
|
109
|
-
//
|
|
221
|
+
// CHAIN MANAGEMENT
|
|
222
|
+
// ============================================================================
|
|
223
|
+
addNetworks(chainIds) {
|
|
224
|
+
const snapChains = chainIds.filter(isSnapSupportedChain);
|
|
225
|
+
const newChains = snapChains.filter((chain) => !this.state.activeChains.includes(chain));
|
|
226
|
+
if (newChains.length > 0) {
|
|
227
|
+
const updated = [...this.state.activeChains, ...newChains];
|
|
228
|
+
this.updateActiveChains(updated, (updatedChains) => __classPrivateFieldGet(this, _SnapDataSource_messenger, "f").call('AssetsController:activeChainsUpdate', exports.SNAP_DATA_SOURCE_NAME, updatedChains));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
removeNetworks(chainIds) {
|
|
232
|
+
const chainSet = new Set(chainIds);
|
|
233
|
+
const updated = this.state.activeChains.filter((chain) => !chainSet.has(chain));
|
|
234
|
+
if (updated.length !== this.state.activeChains.length) {
|
|
235
|
+
this.updateActiveChains(updated, (updatedChains) => __classPrivateFieldGet(this, _SnapDataSource_messenger, "f").call('AssetsController:activeChainsUpdate', exports.SNAP_DATA_SOURCE_NAME, updatedChains));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// ============================================================================
|
|
239
|
+
// FETCH - Routes to appropriate snap(s)
|
|
110
240
|
// ============================================================================
|
|
111
241
|
async fetch(request) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// Note: chainIds filtering is done by middleware/subscribe before calling fetch
|
|
115
|
-
if (!request?.accounts || !request?.chainIds?.length) {
|
|
242
|
+
// Guard against undefined request or chainIds
|
|
243
|
+
if (!request?.chainIds) {
|
|
116
244
|
return {};
|
|
117
245
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
246
|
+
// Filter to only snap-supported chains
|
|
247
|
+
const snapChains = request.chainIds.filter(isSnapSupportedChain);
|
|
248
|
+
if (snapChains.length === 0) {
|
|
249
|
+
return {};
|
|
250
|
+
}
|
|
251
|
+
// Group chains by snap type
|
|
252
|
+
const chainsBySnap = __classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_groupChainsBySnap).call(this, snapChains);
|
|
253
|
+
// Fetch from each snap in parallel
|
|
254
|
+
const results = await Promise.all(Object.entries(chainsBySnap).map(async ([snapType, chains]) => {
|
|
255
|
+
return __classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_fetchFromSnap).call(this, snapType, {
|
|
256
|
+
...request,
|
|
257
|
+
chainIds: chains,
|
|
258
|
+
});
|
|
259
|
+
}));
|
|
260
|
+
// Merge all results
|
|
261
|
+
const mergedResponse = {};
|
|
262
|
+
for (const result of results) {
|
|
263
|
+
if (result.assetsBalance) {
|
|
264
|
+
mergedResponse.assetsBalance = {
|
|
265
|
+
...mergedResponse.assetsBalance,
|
|
266
|
+
...result.assetsBalance,
|
|
267
|
+
};
|
|
128
268
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
269
|
+
if (result.assetsMetadata) {
|
|
270
|
+
mergedResponse.assetsMetadata = {
|
|
271
|
+
...mergedResponse.assetsMetadata,
|
|
272
|
+
...result.assetsMetadata,
|
|
273
|
+
};
|
|
133
274
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
// If no assets, skip to next account
|
|
140
|
-
if (!accountAssets || accountAssets.length === 0) {
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
// Step 2: Get balances for those specific assets
|
|
144
|
-
const balances = await client.getAccountBalances(accountId, accountAssets);
|
|
145
|
-
// Transform keyring response to DataResponse format
|
|
146
|
-
if (balances && typeof balances === 'object' && results.assetsBalance) {
|
|
147
|
-
for (const [assetId, balance] of Object.entries(balances)) {
|
|
148
|
-
(_a = results.assetsBalance)[accountId] ?? (_a[accountId] = {});
|
|
149
|
-
const accountBalances = results.assetsBalance[accountId];
|
|
150
|
-
if (accountBalances) {
|
|
151
|
-
accountBalances[assetId] = {
|
|
152
|
-
amount: balance.amount,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
275
|
+
if (result.assetsPrice) {
|
|
276
|
+
mergedResponse.assetsPrice = {
|
|
277
|
+
...mergedResponse.assetsPrice,
|
|
278
|
+
...result.assetsPrice,
|
|
279
|
+
};
|
|
157
280
|
}
|
|
158
|
-
|
|
159
|
-
|
|
281
|
+
if (result.errors) {
|
|
282
|
+
mergedResponse.errors = { ...mergedResponse.errors, ...result.errors };
|
|
160
283
|
}
|
|
161
284
|
}
|
|
162
|
-
return
|
|
285
|
+
return mergedResponse;
|
|
163
286
|
}
|
|
164
287
|
// ============================================================================
|
|
165
288
|
// MIDDLEWARE
|
|
@@ -247,19 +370,19 @@ class SnapDataSource extends AbstractDataSource_1.AbstractDataSource {
|
|
|
247
370
|
if (!request?.chainIds) {
|
|
248
371
|
return;
|
|
249
372
|
}
|
|
250
|
-
// Filter to
|
|
251
|
-
const
|
|
252
|
-
if (
|
|
373
|
+
// Filter to only snap-supported chains
|
|
374
|
+
const snapChains = request.chainIds.filter(isSnapSupportedChain);
|
|
375
|
+
if (snapChains.length === 0) {
|
|
253
376
|
return;
|
|
254
377
|
}
|
|
255
378
|
if (isUpdate) {
|
|
256
379
|
const existing = this.activeSubscriptions.get(subscriptionId);
|
|
257
380
|
if (existing) {
|
|
258
|
-
existing.chains =
|
|
381
|
+
existing.chains = snapChains;
|
|
259
382
|
// Do a fetch to get latest data on subscription update
|
|
260
383
|
this.fetch({
|
|
261
384
|
...request,
|
|
262
|
-
chainIds:
|
|
385
|
+
chainIds: snapChains,
|
|
263
386
|
})
|
|
264
387
|
.then(async (fetchResponse) => {
|
|
265
388
|
if (Object.keys(fetchResponse.assetsBalance ?? {}).length > 0) {
|
|
@@ -281,13 +404,13 @@ class SnapDataSource extends AbstractDataSource_1.AbstractDataSource {
|
|
|
281
404
|
cleanup: () => {
|
|
282
405
|
// No timer to clear - we use event-based updates
|
|
283
406
|
},
|
|
284
|
-
chains:
|
|
407
|
+
chains: snapChains,
|
|
285
408
|
});
|
|
286
409
|
// Initial fetch to get current balances
|
|
287
410
|
try {
|
|
288
411
|
const fetchResponse = await this.fetch({
|
|
289
412
|
...request,
|
|
290
|
-
chainIds:
|
|
413
|
+
chainIds: snapChains,
|
|
291
414
|
});
|
|
292
415
|
if (Object.keys(fetchResponse.assetsBalance ?? {}).length > 0) {
|
|
293
416
|
await __classPrivateFieldGet(this, _SnapDataSource_messenger, "f").call('AssetsController:assetsUpdate', fetchResponse, exports.SNAP_DATA_SOURCE_NAME);
|
|
@@ -301,69 +424,53 @@ class SnapDataSource extends AbstractDataSource_1.AbstractDataSource {
|
|
|
301
424
|
// CLEANUP
|
|
302
425
|
// ============================================================================
|
|
303
426
|
destroy() {
|
|
304
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
305
|
-
const messenger = __classPrivateFieldGet(this, _SnapDataSource_messenger, "f");
|
|
306
|
-
// Unsubscribe from snap keyring events
|
|
307
|
-
try {
|
|
308
|
-
messenger.unsubscribe('AccountsController:accountBalancesUpdated', __classPrivateFieldGet(this, _SnapDataSource_handleSnapBalancesUpdatedBound, "f"));
|
|
309
|
-
}
|
|
310
|
-
catch (error) {
|
|
311
|
-
log('Failed to unsubscribe from snap keyring events', { error });
|
|
312
|
-
}
|
|
313
|
-
// Unsubscribe from permission changes
|
|
314
|
-
try {
|
|
315
|
-
messenger.unsubscribe('PermissionController:stateChange', __classPrivateFieldGet(this, _SnapDataSource_handlePermissionStateChangeBound, "f"));
|
|
316
|
-
}
|
|
317
|
-
catch (error) {
|
|
318
|
-
log('Failed to unsubscribe from permission changes', { error });
|
|
319
|
-
}
|
|
320
|
-
// Clean up active subscriptions
|
|
321
427
|
for (const [subscriptionId] of this.activeSubscriptions) {
|
|
322
428
|
this.unsubscribe(subscriptionId).catch(() => {
|
|
323
429
|
// Ignore cleanup errors
|
|
324
430
|
});
|
|
325
431
|
}
|
|
326
|
-
// Clear keyring client cache
|
|
327
|
-
__classPrivateFieldGet(this, _SnapDataSource_keyringClientCache, "f").clear();
|
|
328
432
|
}
|
|
329
433
|
}
|
|
330
434
|
exports.SnapDataSource = SnapDataSource;
|
|
331
|
-
_SnapDataSource_messenger = new WeakMap(),
|
|
332
|
-
//
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
435
|
+
_SnapDataSource_messenger = new WeakMap(), _SnapDataSource_snapProvider = new WeakMap(), _SnapDataSource_instances = new WeakSet(), _SnapDataSource_subscribeToSnapKeyringEvents = function _SnapDataSource_subscribeToSnapKeyringEvents() {
|
|
436
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
437
|
+
const messenger = __classPrivateFieldGet(this, _SnapDataSource_messenger, "f");
|
|
438
|
+
try {
|
|
439
|
+
messenger.subscribe('AccountsController:accountBalancesUpdated', (payload) => {
|
|
440
|
+
__classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_handleSnapBalancesUpdated).call(this, payload);
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
log('Failed to subscribe to snap keyring events', { error });
|
|
445
|
+
}
|
|
339
446
|
}, _SnapDataSource_handleSnapBalancesUpdated = function _SnapDataSource_handleSnapBalancesUpdated(payload) {
|
|
340
447
|
// Transform the snap keyring payload to DataResponse format
|
|
341
|
-
|
|
448
|
+
const response = {
|
|
449
|
+
assetsBalance: {},
|
|
450
|
+
};
|
|
342
451
|
for (const [accountId, assets] of Object.entries(payload.balances)) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
452
|
+
if (response.assetsBalance) {
|
|
453
|
+
response.assetsBalance[accountId] = {};
|
|
454
|
+
for (const [assetId, balance] of Object.entries(assets)) {
|
|
455
|
+
// Only include snap-supported assets (solana, bitcoin, tron)
|
|
456
|
+
if (isSnapSupportedChain(extractChainFromAssetId(assetId))) {
|
|
457
|
+
response.assetsBalance[accountId][assetId] = {
|
|
458
|
+
amount: balance.amount,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
// Remove account if no snap assets
|
|
463
|
+
if (Object.keys(response.assetsBalance[accountId]).length === 0) {
|
|
464
|
+
delete response.assetsBalance[accountId];
|
|
351
465
|
}
|
|
352
|
-
}
|
|
353
|
-
if (accountAssets) {
|
|
354
|
-
assetsBalance ?? (assetsBalance = {});
|
|
355
|
-
assetsBalance[accountId] = accountAssets;
|
|
356
466
|
}
|
|
357
467
|
}
|
|
358
468
|
// Only report if we have snap-related updates
|
|
359
|
-
if (assetsBalance) {
|
|
360
|
-
const response = { assetsBalance };
|
|
469
|
+
if (Object.keys(response.assetsBalance ?? {}).length > 0) {
|
|
361
470
|
__classPrivateFieldGet(this, _SnapDataSource_messenger, "f")
|
|
362
471
|
.call('AssetsController:assetsUpdate', response, exports.SNAP_DATA_SOURCE_NAME)
|
|
363
472
|
.catch(console.error);
|
|
364
473
|
}
|
|
365
|
-
}, _SnapDataSource_isChainSupportedBySnap = function _SnapDataSource_isChainSupportedBySnap(chainId) {
|
|
366
|
-
return this.state.activeChains.includes(chainId);
|
|
367
474
|
}, _SnapDataSource_registerActionHandlers = function _SnapDataSource_registerActionHandlers() {
|
|
368
475
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
369
476
|
const messenger = __classPrivateFieldGet(this, _SnapDataSource_messenger, "f");
|
|
@@ -372,86 +479,250 @@ _SnapDataSource_messenger = new WeakMap(), _SnapDataSource_handleSnapBalancesUpd
|
|
|
372
479
|
messenger.registerActionHandler('SnapDataSource:fetch', async (request) => this.fetch(request));
|
|
373
480
|
messenger.registerActionHandler('SnapDataSource:subscribe', async (request) => this.subscribe(request));
|
|
374
481
|
messenger.registerActionHandler('SnapDataSource:unsubscribe', async (subscriptionId) => this.unsubscribe(subscriptionId));
|
|
375
|
-
},
|
|
482
|
+
}, _SnapDataSource_getInstalledSnaps =
|
|
483
|
+
// ============================================================================
|
|
484
|
+
// SNAP AVAILABILITY
|
|
485
|
+
// ============================================================================
|
|
486
|
+
/**
|
|
487
|
+
* Get all installed snaps from the snap provider.
|
|
488
|
+
*
|
|
489
|
+
* @returns A map of snap IDs to their versions.
|
|
490
|
+
*/
|
|
491
|
+
async function _SnapDataSource_getInstalledSnaps() {
|
|
376
492
|
try {
|
|
377
|
-
|
|
493
|
+
const snaps = await __classPrivateFieldGet(this, _SnapDataSource_snapProvider, "f").request({
|
|
494
|
+
method: 'wallet_getSnaps',
|
|
495
|
+
params: {},
|
|
496
|
+
});
|
|
497
|
+
return snaps;
|
|
378
498
|
}
|
|
379
499
|
catch (error) {
|
|
380
|
-
log('Failed to get
|
|
381
|
-
return
|
|
500
|
+
log('Failed to get installed snaps', error);
|
|
501
|
+
return {};
|
|
382
502
|
}
|
|
383
|
-
},
|
|
503
|
+
}, _SnapDataSource_checkSnapAvailabilityOnDemand =
|
|
504
|
+
/**
|
|
505
|
+
* Check availability for a single snap type on-demand.
|
|
506
|
+
* This is called before each fetch to ensure we have the latest availability status.
|
|
507
|
+
*
|
|
508
|
+
* @param snapType - The snap type to check (solana, bitcoin, tron)
|
|
509
|
+
* @returns True if the snap is available, false otherwise
|
|
510
|
+
*/
|
|
511
|
+
async function _SnapDataSource_checkSnapAvailabilityOnDemand(snapType) {
|
|
512
|
+
const config = exports.SNAP_REGISTRY[snapType];
|
|
513
|
+
const currentState = this.state.snaps[snapType];
|
|
514
|
+
// If already marked as available, return true (snap was found previously)
|
|
515
|
+
if (currentState.available) {
|
|
516
|
+
return true;
|
|
517
|
+
}
|
|
518
|
+
// Check if snap is now available (handles timing issues where snap wasn't ready at init)
|
|
384
519
|
try {
|
|
385
|
-
|
|
520
|
+
const snaps = await __classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_getInstalledSnaps).call(this);
|
|
521
|
+
const snap = snaps[config.snapId];
|
|
522
|
+
if (snap) {
|
|
523
|
+
// Snap is now available - update state
|
|
524
|
+
this.state.snaps[snapType] = {
|
|
525
|
+
version: snap.version,
|
|
526
|
+
available: true,
|
|
527
|
+
};
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
return false;
|
|
386
531
|
}
|
|
387
|
-
catch
|
|
388
|
-
|
|
389
|
-
return undefined;
|
|
532
|
+
catch {
|
|
533
|
+
return false;
|
|
390
534
|
}
|
|
391
|
-
},
|
|
535
|
+
}, _SnapDataSource_checkAllSnapsAvailability = async function _SnapDataSource_checkAllSnapsAvailability() {
|
|
392
536
|
try {
|
|
393
|
-
const
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
537
|
+
const snaps = await __classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_getInstalledSnaps).call(this);
|
|
538
|
+
for (const [snapType, config] of Object.entries(exports.SNAP_REGISTRY)) {
|
|
539
|
+
const snap = snaps[config.snapId];
|
|
540
|
+
if (snap) {
|
|
541
|
+
this.state.snaps[snapType] = {
|
|
542
|
+
version: snap.version,
|
|
543
|
+
available: true,
|
|
544
|
+
};
|
|
401
545
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
if (chainIds) {
|
|
408
|
-
for (const chainId of chainIds) {
|
|
409
|
-
if (!(chainId in chainToSnap)) {
|
|
410
|
-
chainToSnap[chainId] = snap.id;
|
|
411
|
-
supportedChains.push(chainId);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
546
|
+
else {
|
|
547
|
+
this.state.snaps[snapType] = {
|
|
548
|
+
version: null,
|
|
549
|
+
available: false,
|
|
550
|
+
};
|
|
414
551
|
}
|
|
415
552
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
//
|
|
419
|
-
|
|
420
|
-
this.
|
|
421
|
-
|
|
422
|
-
|
|
553
|
+
}
|
|
554
|
+
catch {
|
|
555
|
+
// Mark all snaps as unavailable on error
|
|
556
|
+
for (const snapType of Object.keys(exports.SNAP_REGISTRY)) {
|
|
557
|
+
this.state.snaps[snapType] = {
|
|
558
|
+
version: null,
|
|
559
|
+
available: false,
|
|
560
|
+
};
|
|
423
561
|
}
|
|
424
|
-
|
|
425
|
-
|
|
562
|
+
}
|
|
563
|
+
}, _SnapDataSource_accountSupportsChain = function _SnapDataSource_accountSupportsChain(account, chainId) {
|
|
564
|
+
const scopes = account.scopes ?? [];
|
|
565
|
+
// If no scopes defined, assume it supports the chain (backward compatibility)
|
|
566
|
+
if (scopes.length === 0) {
|
|
567
|
+
return true;
|
|
568
|
+
}
|
|
569
|
+
// Extract namespace and reference from chainId
|
|
570
|
+
const [chainNamespace, chainReference] = chainId.split(':');
|
|
571
|
+
for (const scope of scopes) {
|
|
572
|
+
const [scopeNamespace, scopeReference] = scope.split(':');
|
|
573
|
+
// Check if namespaces match
|
|
574
|
+
if (scopeNamespace !== chainNamespace) {
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
// Wildcard scope (e.g., "solana:0" means all chains in that namespace)
|
|
578
|
+
if (scopeReference === '0') {
|
|
579
|
+
return true;
|
|
580
|
+
}
|
|
581
|
+
// Exact match check
|
|
582
|
+
if (scopeReference === chainReference) {
|
|
583
|
+
return true;
|
|
426
584
|
}
|
|
427
585
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
586
|
+
return false;
|
|
587
|
+
}, _SnapDataSource_groupChainsBySnap = function _SnapDataSource_groupChainsBySnap(chainIds) {
|
|
588
|
+
const groups = {};
|
|
589
|
+
for (const chainId of chainIds) {
|
|
590
|
+
const snapType = getSnapTypeForChain(chainId);
|
|
591
|
+
if (snapType) {
|
|
592
|
+
groups[snapType] ?? (groups[snapType] = []);
|
|
593
|
+
const snapChains = groups[snapType];
|
|
594
|
+
if (snapChains) {
|
|
595
|
+
snapChains.push(chainId);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return groups;
|
|
600
|
+
}, _SnapDataSource_fetchFromSnap = async function _SnapDataSource_fetchFromSnap(snapType, request) {
|
|
601
|
+
var _a;
|
|
602
|
+
const config = exports.SNAP_REGISTRY[snapType];
|
|
603
|
+
// Check snap availability on-demand - handles timing issues where snap
|
|
604
|
+
// wasn't ready during initialization but is now available
|
|
605
|
+
const isAvailable = await __classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_checkSnapAvailabilityOnDemand).call(this, snapType);
|
|
606
|
+
if (!isAvailable) {
|
|
607
|
+
log(`${snapType} snap not available, skipping fetch`);
|
|
608
|
+
// Return errors for these chains so they can fallback to other data sources
|
|
609
|
+
const errors = {};
|
|
610
|
+
for (const chainId of request.chainIds) {
|
|
611
|
+
errors[chainId] = `${snapType} snap not available`;
|
|
612
|
+
}
|
|
613
|
+
return { errors };
|
|
614
|
+
}
|
|
615
|
+
const results = {
|
|
616
|
+
assetsBalance: {},
|
|
617
|
+
assetsMetadata: {},
|
|
618
|
+
};
|
|
619
|
+
// Fetch balances for each account using Keyring API
|
|
620
|
+
// Important: Must first get account assets, then request balances for those specific assets
|
|
621
|
+
for (const account of request.accounts) {
|
|
622
|
+
// Filter to only process accounts that support the chains being fetched
|
|
623
|
+
const accountSupportedChains = request.chainIds.filter((chainId) => __classPrivateFieldGet(this, _SnapDataSource_instances, "m", _SnapDataSource_accountSupportsChain).call(this, account, chainId));
|
|
624
|
+
// Skip accounts that don't support any of the requested chains
|
|
625
|
+
if (accountSupportedChains.length === 0) {
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
const accountId = account.id;
|
|
431
629
|
try {
|
|
432
|
-
|
|
433
|
-
|
|
630
|
+
// Step 1: Get the list of assets for this account
|
|
631
|
+
log(`${snapType} snap calling keyring_listAccountAssets`, {
|
|
632
|
+
snapId: config.snapId,
|
|
633
|
+
accountId,
|
|
634
|
+
});
|
|
635
|
+
const accountAssets = await __classPrivateFieldGet(this, _SnapDataSource_snapProvider, "f").request({
|
|
636
|
+
method: 'wallet_invokeSnap',
|
|
637
|
+
params: {
|
|
638
|
+
snapId: config.snapId,
|
|
639
|
+
request: {
|
|
640
|
+
method: 'keyring_listAccountAssets',
|
|
641
|
+
params: {
|
|
642
|
+
id: accountId, // Account UUID
|
|
643
|
+
},
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
});
|
|
647
|
+
log(`${snapType} snap keyring_listAccountAssets response`, {
|
|
648
|
+
accountId,
|
|
649
|
+
assetCount: accountAssets?.length ?? 0,
|
|
650
|
+
assets: accountAssets,
|
|
651
|
+
});
|
|
652
|
+
// If no assets, skip to next account
|
|
653
|
+
if (!accountAssets || accountAssets.length === 0) {
|
|
654
|
+
log(`${snapType} snap: account has no assets, skipping balance fetch`, {
|
|
655
|
+
accountId,
|
|
656
|
+
});
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
// Step 2: Get balances for those specific assets
|
|
660
|
+
log(`${snapType} snap calling keyring_getAccountBalances`, {
|
|
661
|
+
snapId: config.snapId,
|
|
662
|
+
accountId,
|
|
663
|
+
requestedAssets: accountAssets.length,
|
|
664
|
+
});
|
|
665
|
+
const balances = await __classPrivateFieldGet(this, _SnapDataSource_snapProvider, "f").request({
|
|
666
|
+
method: 'wallet_invokeSnap',
|
|
667
|
+
params: {
|
|
668
|
+
snapId: config.snapId,
|
|
669
|
+
request: {
|
|
670
|
+
method: 'keyring_getAccountBalances',
|
|
671
|
+
params: {
|
|
672
|
+
id: accountId, // Account UUID (the keyring API uses 'id' not 'accountId')
|
|
673
|
+
assets: accountAssets, // Must pass specific asset types from listAccountAssets
|
|
674
|
+
},
|
|
675
|
+
},
|
|
676
|
+
},
|
|
677
|
+
});
|
|
678
|
+
log(`${snapType} snap keyring_getAccountBalances response`, {
|
|
679
|
+
accountId,
|
|
680
|
+
balances,
|
|
681
|
+
balancesType: typeof balances,
|
|
682
|
+
isNull: balances === null,
|
|
683
|
+
isUndefined: balances === undefined,
|
|
684
|
+
assetCount: balances ? Object.keys(balances).length : 0,
|
|
434
685
|
});
|
|
686
|
+
// Transform keyring response to DataResponse format
|
|
687
|
+
// Note: snap may return null/undefined if account doesn't belong to this snap
|
|
688
|
+
if (balances && typeof balances === 'object' && results.assetsBalance) {
|
|
689
|
+
const balanceEntries = Object.entries(balances);
|
|
690
|
+
log(`${snapType} snap processing ${balanceEntries.length} balances for account ${accountId}`);
|
|
691
|
+
for (const [assetId, balance] of balanceEntries) {
|
|
692
|
+
// Initialize account balances if not exists
|
|
693
|
+
(_a = results.assetsBalance)[accountId] ?? (_a[accountId] = {});
|
|
694
|
+
// Store raw balance for this asset
|
|
695
|
+
// Use rawAmount if available (preferred - smallest unit), fall back to amount
|
|
696
|
+
// Note: Snaps should return rawAmount in smallest unit (satoshis, lamports, etc.)
|
|
697
|
+
const accountBalances = results.assetsBalance[accountId];
|
|
698
|
+
if (accountBalances) {
|
|
699
|
+
accountBalances[assetId] = {
|
|
700
|
+
amount: balance.rawAmount ?? balance.amount,
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
else if (!balances) {
|
|
706
|
+
log(`${snapType} snap returned empty/null for account (account may not belong to this snap)`, {
|
|
707
|
+
accountId,
|
|
708
|
+
balances,
|
|
709
|
+
});
|
|
710
|
+
}
|
|
435
711
|
}
|
|
436
|
-
catch {
|
|
437
|
-
//
|
|
712
|
+
catch (error) {
|
|
713
|
+
// This is expected when querying a snap with an account it doesn't manage
|
|
714
|
+
log(`${snapType} snap fetch FAILED for account`, {
|
|
715
|
+
accountId,
|
|
716
|
+
error: error instanceof Error ? error.message : String(error),
|
|
717
|
+
errorStack: error instanceof Error ? error.stack : undefined,
|
|
718
|
+
});
|
|
438
719
|
}
|
|
439
720
|
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
return cachedClient;
|
|
444
|
-
}
|
|
445
|
-
const client = new keyring_snap_client_1.KeyringClient({
|
|
446
|
-
send: async (request) => (await __classPrivateFieldGet(this, _SnapDataSource_messenger, "f").call('SnapController:handleRequest', {
|
|
447
|
-
snapId: snapId,
|
|
448
|
-
origin: 'metamask',
|
|
449
|
-
handler: snaps_utils_1.HandlerType.OnKeyringRequest,
|
|
450
|
-
request,
|
|
451
|
-
})),
|
|
721
|
+
log(`${snapType} snap fetch completed`, {
|
|
722
|
+
chains: request.chainIds.length,
|
|
723
|
+
accountsWithBalances: Object.keys(results.assetsBalance ?? {}).length,
|
|
452
724
|
});
|
|
453
|
-
|
|
454
|
-
return client;
|
|
725
|
+
return results;
|
|
455
726
|
};
|
|
456
727
|
// ============================================================================
|
|
457
728
|
// FACTORY
|