@metamask/assets-controller 9.0.2 → 10.0.0
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 +44 -1
- package/dist/AssetsController.cjs +357 -105
- package/dist/AssetsController.cjs.map +1 -1
- package/dist/AssetsController.d.cts +11 -8
- package/dist/AssetsController.d.cts.map +1 -1
- package/dist/AssetsController.d.mts +11 -8
- package/dist/AssetsController.d.mts.map +1 -1
- package/dist/AssetsController.mjs +357 -105
- package/dist/AssetsController.mjs.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.cjs +15 -2
- package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.d.cts +8 -0
- package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.d.mts +8 -0
- package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.mjs +15 -2
- package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.cjs +236 -149
- package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.cts +15 -0
- package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.mts +15 -0
- package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.mjs +236 -146
- package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -1
- package/dist/data-sources/PriceDataSource.cjs +82 -22
- package/dist/data-sources/PriceDataSource.cjs.map +1 -1
- package/dist/data-sources/PriceDataSource.d.cts +13 -0
- package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
- package/dist/data-sources/PriceDataSource.d.mts +13 -0
- package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
- package/dist/data-sources/PriceDataSource.mjs +83 -23
- package/dist/data-sources/PriceDataSource.mjs.map +1 -1
- package/dist/data-sources/RpcDataSource.cjs +29 -9
- package/dist/data-sources/RpcDataSource.cjs.map +1 -1
- package/dist/data-sources/RpcDataSource.d.cts +5 -0
- package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
- package/dist/data-sources/RpcDataSource.d.mts +5 -0
- package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
- package/dist/data-sources/RpcDataSource.mjs +29 -9
- package/dist/data-sources/RpcDataSource.mjs.map +1 -1
- package/dist/data-sources/SnapDataSource.cjs +2 -2
- package/dist/data-sources/SnapDataSource.cjs.map +1 -1
- package/dist/data-sources/SnapDataSource.mjs +2 -2
- package/dist/data-sources/SnapDataSource.mjs.map +1 -1
- package/dist/index.cjs +3 -1
- 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 +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/middlewares/DetectionMiddleware.cjs +64 -23
- package/dist/middlewares/DetectionMiddleware.cjs.map +1 -1
- package/dist/middlewares/DetectionMiddleware.d.cts +15 -13
- package/dist/middlewares/DetectionMiddleware.d.cts.map +1 -1
- package/dist/middlewares/DetectionMiddleware.d.mts +15 -13
- package/dist/middlewares/DetectionMiddleware.d.mts.map +1 -1
- package/dist/middlewares/DetectionMiddleware.mjs +64 -23
- package/dist/middlewares/DetectionMiddleware.mjs.map +1 -1
- package/dist/middlewares/ParallelMiddleware.cjs +7 -0
- package/dist/middlewares/ParallelMiddleware.cjs.map +1 -1
- package/dist/middlewares/ParallelMiddleware.d.cts.map +1 -1
- package/dist/middlewares/ParallelMiddleware.d.mts.map +1 -1
- package/dist/middlewares/ParallelMiddleware.mjs +7 -0
- package/dist/middlewares/ParallelMiddleware.mjs.map +1 -1
- package/dist/selectors/balance.cjs +191 -8
- package/dist/selectors/balance.cjs.map +1 -1
- package/dist/selectors/balance.d.cts +80 -0
- package/dist/selectors/balance.d.cts.map +1 -1
- package/dist/selectors/balance.d.mts +80 -0
- package/dist/selectors/balance.d.mts.map +1 -1
- package/dist/selectors/balance.mjs +186 -7
- package/dist/selectors/balance.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +20 -4
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +20 -4
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/dist/utils/dedupingBatchFetcher.cjs +168 -0
- package/dist/utils/dedupingBatchFetcher.cjs.map +1 -0
- package/dist/utils/dedupingBatchFetcher.d.cts +72 -0
- package/dist/utils/dedupingBatchFetcher.d.cts.map +1 -0
- package/dist/utils/dedupingBatchFetcher.d.mts +72 -0
- package/dist/utils/dedupingBatchFetcher.d.mts.map +1 -0
- package/dist/utils/dedupingBatchFetcher.mjs +164 -0
- package/dist/utils/dedupingBatchFetcher.mjs.map +1 -0
- package/dist/utils/processAccountActivityBalanceUpdates.cjs +54 -0
- package/dist/utils/processAccountActivityBalanceUpdates.cjs.map +1 -0
- package/dist/utils/processAccountActivityBalanceUpdates.d.cts +13 -0
- package/dist/utils/processAccountActivityBalanceUpdates.d.cts.map +1 -0
- package/dist/utils/processAccountActivityBalanceUpdates.d.mts +13 -0
- package/dist/utils/processAccountActivityBalanceUpdates.d.mts.map +1 -0
- package/dist/utils/processAccountActivityBalanceUpdates.mjs +47 -0
- package/dist/utils/processAccountActivityBalanceUpdates.mjs.map +1 -0
- package/package.json +7 -7
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
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");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
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");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _DedupingBatchFetcher_instances, _DedupingBatchFetcher_fetchBatch, _DedupingBatchFetcher_freshnessTtlMs, _DedupingBatchFetcher_fetchedAt, _DedupingBatchFetcher_inflight, _DedupingBatchFetcher_partition, _DedupingBatchFetcher_isFresh, _DedupingBatchFetcher_startBatchFetch, _DedupingBatchFetcher_joinInflight;
|
|
13
|
+
/**
|
|
14
|
+
* Deduplicates batched fetches by key across two dimensions:
|
|
15
|
+
*
|
|
16
|
+
* 1. **Freshness TTL** — keys fetched within `freshnessTtlMs` are skipped
|
|
17
|
+
* entirely. Note the freshness window only starts once a fetch *completes*,
|
|
18
|
+
* so it does not cover requests that are still in flight.
|
|
19
|
+
* 2. **Inflight coalescing** — if a fetch is already in progress for a key,
|
|
20
|
+
* concurrent callers join the existing promise instead of issuing a new
|
|
21
|
+
* request. This covers the request-in-flight window the freshness TTL
|
|
22
|
+
* structurally cannot.
|
|
23
|
+
*
|
|
24
|
+
* Both layers are per-key, so a call for a partially-overlapping set of keys
|
|
25
|
+
* reuses the fresh/inflight keys and only fetches the genuinely-missing ones.
|
|
26
|
+
*
|
|
27
|
+
* The fetch is batched: all stale, not-inflight keys from a single `fetch()`
|
|
28
|
+
* call are passed to `fetchBatch` together, then split into per-key results so
|
|
29
|
+
* each key can be joined independently.
|
|
30
|
+
*/
|
|
31
|
+
export class DedupingBatchFetcher {
|
|
32
|
+
constructor(options) {
|
|
33
|
+
_DedupingBatchFetcher_instances.add(this);
|
|
34
|
+
_DedupingBatchFetcher_fetchBatch.set(this, void 0);
|
|
35
|
+
_DedupingBatchFetcher_freshnessTtlMs.set(this, void 0);
|
|
36
|
+
/** Tracks the last successful fetch time per key (freshness gating). */
|
|
37
|
+
_DedupingBatchFetcher_fetchedAt.set(this, new Map());
|
|
38
|
+
/**
|
|
39
|
+
* Per-key inflight fetch promises. Each resolves to the value, or `undefined`
|
|
40
|
+
* if the batch failed or returned no data for that key.
|
|
41
|
+
*/
|
|
42
|
+
_DedupingBatchFetcher_inflight.set(this, new Map());
|
|
43
|
+
__classPrivateFieldSet(this, _DedupingBatchFetcher_fetchBatch, options.fetchBatch, "f");
|
|
44
|
+
__classPrivateFieldSet(this, _DedupingBatchFetcher_freshnessTtlMs, options.freshnessTtlMs, "f");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Minimum age (ms) before a key is re-fetched.
|
|
48
|
+
*
|
|
49
|
+
* @returns The current freshness TTL in milliseconds.
|
|
50
|
+
*/
|
|
51
|
+
get freshnessTtlMs() {
|
|
52
|
+
return __classPrivateFieldGet(this, _DedupingBatchFetcher_freshnessTtlMs, "f");
|
|
53
|
+
}
|
|
54
|
+
set freshnessTtlMs(ms) {
|
|
55
|
+
__classPrivateFieldSet(this, _DedupingBatchFetcher_freshnessTtlMs, ms, "f");
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Fetch values for the given keys, deduplicating against fresh and inflight
|
|
59
|
+
* fetches.
|
|
60
|
+
*
|
|
61
|
+
* @param keys - The keys to fetch.
|
|
62
|
+
* @returns Values keyed by key. Only contains entries for keys that were
|
|
63
|
+
* actually fetched (or joined from inflight) and had a value.
|
|
64
|
+
*/
|
|
65
|
+
async fetch(keys) {
|
|
66
|
+
const { staleKeys, inflightKeys } = __classPrivateFieldGet(this, _DedupingBatchFetcher_instances, "m", _DedupingBatchFetcher_partition).call(this, keys);
|
|
67
|
+
if (staleKeys.length === 0 && inflightKeys.length === 0) {
|
|
68
|
+
return {};
|
|
69
|
+
}
|
|
70
|
+
// Start a fetch for stale keys and join any fetches already in progress.
|
|
71
|
+
const batchPromise = staleKeys.length > 0 ? __classPrivateFieldGet(this, _DedupingBatchFetcher_instances, "m", _DedupingBatchFetcher_startBatchFetch).call(this, staleKeys) : undefined;
|
|
72
|
+
const values = await __classPrivateFieldGet(this, _DedupingBatchFetcher_instances, "m", _DedupingBatchFetcher_joinInflight).call(this, inflightKeys);
|
|
73
|
+
if (batchPromise) {
|
|
74
|
+
Object.assign(values, await batchPromise);
|
|
75
|
+
}
|
|
76
|
+
return values;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Clear the freshness cache, forcing the next fetch to re-request every key
|
|
80
|
+
* regardless of TTL. Does not affect inflight fetches.
|
|
81
|
+
*/
|
|
82
|
+
invalidate() {
|
|
83
|
+
__classPrivateFieldGet(this, _DedupingBatchFetcher_fetchedAt, "f").clear();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Clear freshness for specific keys only, forcing the next fetch to
|
|
87
|
+
* re-request those keys regardless of TTL. Does not affect inflight fetches.
|
|
88
|
+
*
|
|
89
|
+
* @param keys - Keys to mark stale.
|
|
90
|
+
*/
|
|
91
|
+
invalidateKeys(keys) {
|
|
92
|
+
for (const key of keys) {
|
|
93
|
+
__classPrivateFieldGet(this, _DedupingBatchFetcher_fetchedAt, "f").delete(key);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Clear all freshness and inflight state. */
|
|
97
|
+
destroy() {
|
|
98
|
+
__classPrivateFieldGet(this, _DedupingBatchFetcher_fetchedAt, "f").clear();
|
|
99
|
+
__classPrivateFieldGet(this, _DedupingBatchFetcher_inflight, "f").clear();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
_DedupingBatchFetcher_fetchBatch = new WeakMap(), _DedupingBatchFetcher_freshnessTtlMs = new WeakMap(), _DedupingBatchFetcher_fetchedAt = new WeakMap(), _DedupingBatchFetcher_inflight = new WeakMap(), _DedupingBatchFetcher_instances = new WeakSet(), _DedupingBatchFetcher_partition = function _DedupingBatchFetcher_partition(keys) {
|
|
103
|
+
const now = Date.now();
|
|
104
|
+
const staleKeys = [];
|
|
105
|
+
const inflightKeys = [];
|
|
106
|
+
for (const key of keys) {
|
|
107
|
+
if (__classPrivateFieldGet(this, _DedupingBatchFetcher_instances, "m", _DedupingBatchFetcher_isFresh).call(this, key, now)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (__classPrivateFieldGet(this, _DedupingBatchFetcher_inflight, "f").has(key)) {
|
|
111
|
+
inflightKeys.push(key);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
staleKeys.push(key);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return { staleKeys, inflightKeys };
|
|
118
|
+
}, _DedupingBatchFetcher_isFresh = function _DedupingBatchFetcher_isFresh(key, now) {
|
|
119
|
+
const fetchedAt = __classPrivateFieldGet(this, _DedupingBatchFetcher_fetchedAt, "f").get(key);
|
|
120
|
+
return fetchedAt !== undefined && now - fetchedAt < __classPrivateFieldGet(this, _DedupingBatchFetcher_freshnessTtlMs, "f");
|
|
121
|
+
}, _DedupingBatchFetcher_startBatchFetch = function _DedupingBatchFetcher_startBatchFetch(staleKeys) {
|
|
122
|
+
const batchPromise = __classPrivateFieldGet(this, _DedupingBatchFetcher_fetchBatch, "f").call(this, staleKeys).then((values) => {
|
|
123
|
+
const fetchedAt = Date.now();
|
|
124
|
+
for (const key of staleKeys) {
|
|
125
|
+
__classPrivateFieldGet(this, _DedupingBatchFetcher_fetchedAt, "f").set(key, fetchedAt);
|
|
126
|
+
}
|
|
127
|
+
return values;
|
|
128
|
+
});
|
|
129
|
+
for (const key of staleKeys) {
|
|
130
|
+
const perKey = batchPromise.then((values) => values[key], () => undefined);
|
|
131
|
+
__classPrivateFieldGet(this, _DedupingBatchFetcher_inflight, "f").set(key, perKey);
|
|
132
|
+
}
|
|
133
|
+
// Clean up inflight entries once the batch settles (success or failure).
|
|
134
|
+
// Rejection is already surfaced to the caller via the returned batchPromise.
|
|
135
|
+
batchPromise
|
|
136
|
+
.finally(() => {
|
|
137
|
+
for (const key of staleKeys) {
|
|
138
|
+
__classPrivateFieldGet(this, _DedupingBatchFetcher_inflight, "f").delete(key);
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
.catch(() => undefined);
|
|
142
|
+
return batchPromise;
|
|
143
|
+
}, _DedupingBatchFetcher_joinInflight =
|
|
144
|
+
/**
|
|
145
|
+
* Join the inflight fetches for the given keys and collect their values. Keys
|
|
146
|
+
* whose inflight fetch produced no value are omitted.
|
|
147
|
+
*
|
|
148
|
+
* @param inflightKeys - Keys whose fetches are already in progress.
|
|
149
|
+
* @returns Values keyed by key.
|
|
150
|
+
*/
|
|
151
|
+
async function _DedupingBatchFetcher_joinInflight(inflightKeys) {
|
|
152
|
+
const values = {};
|
|
153
|
+
const results = await Promise.all(inflightKeys.map(async (key) => {
|
|
154
|
+
const value = await __classPrivateFieldGet(this, _DedupingBatchFetcher_inflight, "f").get(key);
|
|
155
|
+
return [key, value];
|
|
156
|
+
}));
|
|
157
|
+
for (const [key, value] of results) {
|
|
158
|
+
if (value !== undefined) {
|
|
159
|
+
values[key] = value;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return values;
|
|
163
|
+
};
|
|
164
|
+
//# sourceMappingURL=dedupingBatchFetcher.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedupingBatchFetcher.mjs","sourceRoot":"","sources":["../../src/utils/dedupingBatchFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Executes the underlying batched fetch for a set of keys. Only keys that have\n * a value need to be present in the returned record; keys the source had no\n * data for are simply omitted (they are still marked fresh — see\n * {@link DedupingBatchFetcher.fetch}).\n *\n * @param keys - The keys to fetch (already filtered to stale, not-inflight keys).\n * @returns The fetched values keyed by key.\n */\nexport type BatchFetchFn<Key extends string, Value> = (\n keys: Key[],\n) => Promise<Record<Key, Value>>;\n\nexport type DedupingBatchFetcherOptions<Key extends string, Value> = {\n /** Performs the actual batched fetch for stale, not-inflight keys. */\n fetchBatch: BatchFetchFn<Key, Value>;\n /**\n * Minimum age (ms) before a key is considered stale and re-fetched. Keys\n * fetched more recently than this are skipped entirely.\n */\n freshnessTtlMs: number;\n};\n\n/**\n * Deduplicates batched fetches by key across two dimensions:\n *\n * 1. **Freshness TTL** — keys fetched within `freshnessTtlMs` are skipped\n * entirely. Note the freshness window only starts once a fetch *completes*,\n * so it does not cover requests that are still in flight.\n * 2. **Inflight coalescing** — if a fetch is already in progress for a key,\n * concurrent callers join the existing promise instead of issuing a new\n * request. This covers the request-in-flight window the freshness TTL\n * structurally cannot.\n *\n * Both layers are per-key, so a call for a partially-overlapping set of keys\n * reuses the fresh/inflight keys and only fetches the genuinely-missing ones.\n *\n * The fetch is batched: all stale, not-inflight keys from a single `fetch()`\n * call are passed to `fetchBatch` together, then split into per-key results so\n * each key can be joined independently.\n */\nexport class DedupingBatchFetcher<Key extends string, Value> {\n readonly #fetchBatch: BatchFetchFn<Key, Value>;\n\n #freshnessTtlMs: number;\n\n /** Tracks the last successful fetch time per key (freshness gating). */\n readonly #fetchedAt = new Map<Key, number>();\n\n /**\n * Per-key inflight fetch promises. Each resolves to the value, or `undefined`\n * if the batch failed or returned no data for that key.\n */\n readonly #inflight = new Map<Key, Promise<Value | undefined>>();\n\n constructor(options: DedupingBatchFetcherOptions<Key, Value>) {\n this.#fetchBatch = options.fetchBatch;\n this.#freshnessTtlMs = options.freshnessTtlMs;\n }\n\n /**\n * Minimum age (ms) before a key is re-fetched.\n *\n * @returns The current freshness TTL in milliseconds.\n */\n get freshnessTtlMs(): number {\n return this.#freshnessTtlMs;\n }\n\n set freshnessTtlMs(ms: number) {\n this.#freshnessTtlMs = ms;\n }\n\n /**\n * Fetch values for the given keys, deduplicating against fresh and inflight\n * fetches.\n *\n * @param keys - The keys to fetch.\n * @returns Values keyed by key. Only contains entries for keys that were\n * actually fetched (or joined from inflight) and had a value.\n */\n async fetch(keys: Key[]): Promise<Record<Key, Value>> {\n const { staleKeys, inflightKeys } = this.#partition(keys);\n\n if (staleKeys.length === 0 && inflightKeys.length === 0) {\n return {} as Record<Key, Value>;\n }\n\n // Start a fetch for stale keys and join any fetches already in progress.\n const batchPromise =\n staleKeys.length > 0 ? this.#startBatchFetch(staleKeys) : undefined;\n const values = await this.#joinInflight(inflightKeys);\n\n if (batchPromise) {\n Object.assign(values, await batchPromise);\n }\n\n return values;\n }\n\n /**\n * Clear the freshness cache, forcing the next fetch to re-request every key\n * regardless of TTL. Does not affect inflight fetches.\n */\n invalidate(): void {\n this.#fetchedAt.clear();\n }\n\n /**\n * Clear freshness for specific keys only, forcing the next fetch to\n * re-request those keys regardless of TTL. Does not affect inflight fetches.\n *\n * @param keys - Keys to mark stale.\n */\n invalidateKeys(keys: Key[]): void {\n for (const key of keys) {\n this.#fetchedAt.delete(key);\n }\n }\n\n /** Clear all freshness and inflight state. */\n destroy(): void {\n this.#fetchedAt.clear();\n this.#inflight.clear();\n }\n\n /**\n * Split keys into those that need a fresh fetch and those already being\n * fetched by another caller. Keys still within the freshness TTL are dropped.\n *\n * @param keys - The keys to classify.\n * @returns `staleKeys` (need fetching) and `inflightKeys` (join existing fetch).\n */\n #partition(keys: Key[]): { staleKeys: Key[]; inflightKeys: Key[] } {\n const now = Date.now();\n const staleKeys: Key[] = [];\n const inflightKeys: Key[] = [];\n\n for (const key of keys) {\n if (this.#isFresh(key, now)) {\n continue;\n }\n if (this.#inflight.has(key)) {\n inflightKeys.push(key);\n } else {\n staleKeys.push(key);\n }\n }\n\n return { staleKeys, inflightKeys };\n }\n\n /**\n * Returns true if the key's last fetch is still within the freshness TTL.\n *\n * @param key - The key to check.\n * @param now - Current timestamp (avoids repeated clock reads).\n * @returns True if the key was fetched within the freshness TTL.\n */\n #isFresh(key: Key, now: number): boolean {\n const fetchedAt = this.#fetchedAt.get(key);\n return fetchedAt !== undefined && now - fetchedAt < this.#freshnessTtlMs;\n }\n\n /**\n * Launch a batch fetch and register a per-key inflight promise for each key\n * so concurrent callers can join. On success, all requested keys are marked\n * fresh — including keys the source returned no value for, since the absence\n * of a value is itself a valid answer that should not be re-asked until the\n * TTL expires. A failed batch leaves keys stale so they are retried.\n *\n * @param staleKeys - Keys to fetch (none of which are already inflight).\n * @returns The batch fetch promise.\n */\n #startBatchFetch(staleKeys: Key[]): Promise<Record<Key, Value>> {\n const batchPromise = this.#fetchBatch(staleKeys).then((values) => {\n const fetchedAt = Date.now();\n for (const key of staleKeys) {\n this.#fetchedAt.set(key, fetchedAt);\n }\n return values;\n });\n\n for (const key of staleKeys) {\n const perKey = batchPromise.then(\n (values) => values[key],\n () => undefined,\n );\n this.#inflight.set(key, perKey);\n }\n\n // Clean up inflight entries once the batch settles (success or failure).\n // Rejection is already surfaced to the caller via the returned batchPromise.\n batchPromise\n .finally(() => {\n for (const key of staleKeys) {\n this.#inflight.delete(key);\n }\n })\n .catch(() => undefined);\n\n return batchPromise;\n }\n\n /**\n * Join the inflight fetches for the given keys and collect their values. Keys\n * whose inflight fetch produced no value are omitted.\n *\n * @param inflightKeys - Keys whose fetches are already in progress.\n * @returns Values keyed by key.\n */\n async #joinInflight(inflightKeys: Key[]): Promise<Record<Key, Value>> {\n const values = {} as Record<Key, Value>;\n\n const results = await Promise.all(\n inflightKeys.map(async (key) => {\n const value = await this.#inflight.get(key);\n return [key, value] as const;\n }),\n );\n\n for (const [key, value] of results) {\n if (value !== undefined) {\n values[key] = value;\n }\n }\n\n return values;\n }\n}\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
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.processAccountActivityBalanceUpdates = void 0;
|
|
7
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
8
|
+
/**
|
|
9
|
+
* Convert AccountActivityMessage balance updates into a {@link DataResponse}
|
|
10
|
+
* for AssetsController (same shape as BackendWebsocketDataSource).
|
|
11
|
+
*
|
|
12
|
+
* @param updates - Balance updates from account-activity websocket payload.
|
|
13
|
+
* @param accountId - Internal account UUID.
|
|
14
|
+
* @param getAssetType - Resolver for asset metadata type.
|
|
15
|
+
* @returns DataResponse with merge mode when balances are present.
|
|
16
|
+
*/
|
|
17
|
+
function processAccountActivityBalanceUpdates(updates, accountId, getAssetType) {
|
|
18
|
+
const assetsBalance = Object.create(null);
|
|
19
|
+
assetsBalance[accountId] = Object.create(null);
|
|
20
|
+
const assetsMetadata = Object.create(null);
|
|
21
|
+
for (const update of updates) {
|
|
22
|
+
const { asset, postBalance } = update;
|
|
23
|
+
if (!asset || !postBalance) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const assetId = asset.type;
|
|
27
|
+
if (asset.decimals === undefined) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const rawBalanceStr = postBalance.amount.startsWith('0x')
|
|
31
|
+
? BigInt(postBalance.amount).toString()
|
|
32
|
+
: postBalance.amount;
|
|
33
|
+
const humanReadableAmount = new bignumber_js_1.default(rawBalanceStr)
|
|
34
|
+
.dividedBy(new bignumber_js_1.default(10).pow(asset.decimals))
|
|
35
|
+
.toFixed();
|
|
36
|
+
assetsBalance[accountId][assetId] = {
|
|
37
|
+
amount: humanReadableAmount,
|
|
38
|
+
};
|
|
39
|
+
assetsMetadata[assetId] = {
|
|
40
|
+
type: getAssetType(assetId),
|
|
41
|
+
symbol: asset.unit,
|
|
42
|
+
name: asset.unit,
|
|
43
|
+
decimals: asset.decimals,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const response = { updateMode: 'merge' };
|
|
47
|
+
if (Object.keys(assetsBalance[accountId]).length > 0) {
|
|
48
|
+
response.assetsBalance = assetsBalance;
|
|
49
|
+
response.assetsInfo = assetsMetadata;
|
|
50
|
+
}
|
|
51
|
+
return response;
|
|
52
|
+
}
|
|
53
|
+
exports.processAccountActivityBalanceUpdates = processAccountActivityBalanceUpdates;
|
|
54
|
+
//# sourceMappingURL=processAccountActivityBalanceUpdates.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processAccountActivityBalanceUpdates.cjs","sourceRoot":"","sources":["../../src/utils/processAccountActivityBalanceUpdates.ts"],"names":[],"mappings":";;;;;;AACA,gEAAuC;AASvC;;;;;;;;GAQG;AACH,SAAgB,oCAAoC,CAClD,OAAwB,EACxB,SAAiB,EACjB,YAAoE;IAEpE,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAGvC,CAAC;IACF,aAAa,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAG5C,CAAC;IACF,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAGxC,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;QAEtC,IAAI,CAAC,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;YAC3B,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAqB,CAAC;QAE5C,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACjC,SAAS;QACX,CAAC;QAED,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;YACvD,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;YACvC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;QAEvB,MAAM,mBAAmB,GAAG,IAAI,sBAAW,CAAC,aAAa,CAAC;aACvD,SAAS,CAAC,IAAI,sBAAW,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;aAClD,OAAO,EAAE,CAAC;QAEb,aAAa,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG;YAClC,MAAM,EAAE,mBAAmB;SAC5B,CAAC;QAEF,cAAc,CAAC,OAAO,CAAC,GAAG;YACxB,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC;YAC3B,MAAM,EAAE,KAAK,CAAC,IAAI;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAiB,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;IACvD,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrD,QAAQ,CAAC,aAAa,GAAG,aAAa,CAAC;QACvC,QAAQ,CAAC,UAAU,GAAG,cAAc,CAAC;IACvC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AA1DD,oFA0DC","sourcesContent":["import type { BalanceUpdate } from '@metamask/core-backend';\nimport BigNumberJS from 'bignumber.js';\n\nimport type {\n AssetBalance,\n AssetMetadata,\n Caip19AssetId,\n DataResponse,\n} from '../types';\n\n/**\n * Convert AccountActivityMessage balance updates into a {@link DataResponse}\n * for AssetsController (same shape as BackendWebsocketDataSource).\n *\n * @param updates - Balance updates from account-activity websocket payload.\n * @param accountId - Internal account UUID.\n * @param getAssetType - Resolver for asset metadata type.\n * @returns DataResponse with merge mode when balances are present.\n */\nexport function processAccountActivityBalanceUpdates(\n updates: BalanceUpdate[],\n accountId: string,\n getAssetType: (assetId: Caip19AssetId) => 'native' | 'erc20' | 'spl',\n): DataResponse {\n const assetsBalance = Object.create(null) as Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n >;\n assetsBalance[accountId] = Object.create(null) as Record<\n Caip19AssetId,\n AssetBalance\n >;\n const assetsMetadata = Object.create(null) as Record<\n Caip19AssetId,\n AssetMetadata\n >;\n\n for (const update of updates) {\n const { asset, postBalance } = update;\n\n if (!asset || !postBalance) {\n continue;\n }\n\n const assetId = asset.type as Caip19AssetId;\n\n if (asset.decimals === undefined) {\n continue;\n }\n\n const rawBalanceStr = postBalance.amount.startsWith('0x')\n ? BigInt(postBalance.amount).toString()\n : postBalance.amount;\n\n const humanReadableAmount = new BigNumberJS(rawBalanceStr)\n .dividedBy(new BigNumberJS(10).pow(asset.decimals))\n .toFixed();\n\n assetsBalance[accountId][assetId] = {\n amount: humanReadableAmount,\n };\n\n assetsMetadata[assetId] = {\n type: getAssetType(assetId),\n symbol: asset.unit,\n name: asset.unit,\n decimals: asset.decimals,\n };\n }\n\n const response: DataResponse = { updateMode: 'merge' };\n if (Object.keys(assetsBalance[accountId]).length > 0) {\n response.assetsBalance = assetsBalance;\n response.assetsInfo = assetsMetadata;\n }\n\n return response;\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BalanceUpdate } from "@metamask/core-backend";
|
|
2
|
+
import type { Caip19AssetId, DataResponse } from "../types.cjs";
|
|
3
|
+
/**
|
|
4
|
+
* Convert AccountActivityMessage balance updates into a {@link DataResponse}
|
|
5
|
+
* for AssetsController (same shape as BackendWebsocketDataSource).
|
|
6
|
+
*
|
|
7
|
+
* @param updates - Balance updates from account-activity websocket payload.
|
|
8
|
+
* @param accountId - Internal account UUID.
|
|
9
|
+
* @param getAssetType - Resolver for asset metadata type.
|
|
10
|
+
* @returns DataResponse with merge mode when balances are present.
|
|
11
|
+
*/
|
|
12
|
+
export declare function processAccountActivityBalanceUpdates(updates: BalanceUpdate[], accountId: string, getAssetType: (assetId: Caip19AssetId) => 'native' | 'erc20' | 'spl'): DataResponse;
|
|
13
|
+
//# sourceMappingURL=processAccountActivityBalanceUpdates.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processAccountActivityBalanceUpdates.d.cts","sourceRoot":"","sources":["../../src/utils/processAccountActivityBalanceUpdates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,+BAA+B;AAG5D,OAAO,KAAK,EAGV,aAAa,EACb,YAAY,EACb,qBAAiB;AAElB;;;;;;;;GAQG;AACH,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,aAAa,EAAE,EACxB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,QAAQ,GAAG,OAAO,GAAG,KAAK,GACnE,YAAY,CAsDd"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BalanceUpdate } from "@metamask/core-backend";
|
|
2
|
+
import type { Caip19AssetId, DataResponse } from "../types.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Convert AccountActivityMessage balance updates into a {@link DataResponse}
|
|
5
|
+
* for AssetsController (same shape as BackendWebsocketDataSource).
|
|
6
|
+
*
|
|
7
|
+
* @param updates - Balance updates from account-activity websocket payload.
|
|
8
|
+
* @param accountId - Internal account UUID.
|
|
9
|
+
* @param getAssetType - Resolver for asset metadata type.
|
|
10
|
+
* @returns DataResponse with merge mode when balances are present.
|
|
11
|
+
*/
|
|
12
|
+
export declare function processAccountActivityBalanceUpdates(updates: BalanceUpdate[], accountId: string, getAssetType: (assetId: Caip19AssetId) => 'native' | 'erc20' | 'spl'): DataResponse;
|
|
13
|
+
//# sourceMappingURL=processAccountActivityBalanceUpdates.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processAccountActivityBalanceUpdates.d.mts","sourceRoot":"","sources":["../../src/utils/processAccountActivityBalanceUpdates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,+BAA+B;AAG5D,OAAO,KAAK,EAGV,aAAa,EACb,YAAY,EACb,qBAAiB;AAElB;;;;;;;;GAQG;AACH,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,aAAa,EAAE,EACxB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,QAAQ,GAAG,OAAO,GAAG,KAAK,GACnE,YAAY,CAsDd"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import BigNumberJS from "bignumber.js";
|
|
2
|
+
/**
|
|
3
|
+
* Convert AccountActivityMessage balance updates into a {@link DataResponse}
|
|
4
|
+
* for AssetsController (same shape as BackendWebsocketDataSource).
|
|
5
|
+
*
|
|
6
|
+
* @param updates - Balance updates from account-activity websocket payload.
|
|
7
|
+
* @param accountId - Internal account UUID.
|
|
8
|
+
* @param getAssetType - Resolver for asset metadata type.
|
|
9
|
+
* @returns DataResponse with merge mode when balances are present.
|
|
10
|
+
*/
|
|
11
|
+
export function processAccountActivityBalanceUpdates(updates, accountId, getAssetType) {
|
|
12
|
+
const assetsBalance = Object.create(null);
|
|
13
|
+
assetsBalance[accountId] = Object.create(null);
|
|
14
|
+
const assetsMetadata = Object.create(null);
|
|
15
|
+
for (const update of updates) {
|
|
16
|
+
const { asset, postBalance } = update;
|
|
17
|
+
if (!asset || !postBalance) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const assetId = asset.type;
|
|
21
|
+
if (asset.decimals === undefined) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const rawBalanceStr = postBalance.amount.startsWith('0x')
|
|
25
|
+
? BigInt(postBalance.amount).toString()
|
|
26
|
+
: postBalance.amount;
|
|
27
|
+
const humanReadableAmount = new BigNumberJS(rawBalanceStr)
|
|
28
|
+
.dividedBy(new BigNumberJS(10).pow(asset.decimals))
|
|
29
|
+
.toFixed();
|
|
30
|
+
assetsBalance[accountId][assetId] = {
|
|
31
|
+
amount: humanReadableAmount,
|
|
32
|
+
};
|
|
33
|
+
assetsMetadata[assetId] = {
|
|
34
|
+
type: getAssetType(assetId),
|
|
35
|
+
symbol: asset.unit,
|
|
36
|
+
name: asset.unit,
|
|
37
|
+
decimals: asset.decimals,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const response = { updateMode: 'merge' };
|
|
41
|
+
if (Object.keys(assetsBalance[accountId]).length > 0) {
|
|
42
|
+
response.assetsBalance = assetsBalance;
|
|
43
|
+
response.assetsInfo = assetsMetadata;
|
|
44
|
+
}
|
|
45
|
+
return response;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=processAccountActivityBalanceUpdates.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processAccountActivityBalanceUpdates.mjs","sourceRoot":"","sources":["../../src/utils/processAccountActivityBalanceUpdates.ts"],"names":[],"mappings":"AACA,OAAO,WAAW,qBAAqB;AASvC;;;;;;;;GAQG;AACH,MAAM,UAAU,oCAAoC,CAClD,OAAwB,EACxB,SAAiB,EACjB,YAAoE;IAEpE,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAGvC,CAAC;IACF,aAAa,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAG5C,CAAC;IACF,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAGxC,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;QAEtC,IAAI,CAAC,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;YAC3B,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAqB,CAAC;QAE5C,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACjC,SAAS;QACX,CAAC;QAED,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;YACvD,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;YACvC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;QAEvB,MAAM,mBAAmB,GAAG,IAAI,WAAW,CAAC,aAAa,CAAC;aACvD,SAAS,CAAC,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;aAClD,OAAO,EAAE,CAAC;QAEb,aAAa,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG;YAClC,MAAM,EAAE,mBAAmB;SAC5B,CAAC;QAEF,cAAc,CAAC,OAAO,CAAC,GAAG;YACxB,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC;YAC3B,MAAM,EAAE,KAAK,CAAC,IAAI;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAiB,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;IACvD,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrD,QAAQ,CAAC,aAAa,GAAG,aAAa,CAAC;QACvC,QAAQ,CAAC,UAAU,GAAG,cAAc,CAAC;IACvC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import type { BalanceUpdate } from '@metamask/core-backend';\nimport BigNumberJS from 'bignumber.js';\n\nimport type {\n AssetBalance,\n AssetMetadata,\n Caip19AssetId,\n DataResponse,\n} from '../types';\n\n/**\n * Convert AccountActivityMessage balance updates into a {@link DataResponse}\n * for AssetsController (same shape as BackendWebsocketDataSource).\n *\n * @param updates - Balance updates from account-activity websocket payload.\n * @param accountId - Internal account UUID.\n * @param getAssetType - Resolver for asset metadata type.\n * @returns DataResponse with merge mode when balances are present.\n */\nexport function processAccountActivityBalanceUpdates(\n updates: BalanceUpdate[],\n accountId: string,\n getAssetType: (assetId: Caip19AssetId) => 'native' | 'erc20' | 'spl',\n): DataResponse {\n const assetsBalance = Object.create(null) as Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n >;\n assetsBalance[accountId] = Object.create(null) as Record<\n Caip19AssetId,\n AssetBalance\n >;\n const assetsMetadata = Object.create(null) as Record<\n Caip19AssetId,\n AssetMetadata\n >;\n\n for (const update of updates) {\n const { asset, postBalance } = update;\n\n if (!asset || !postBalance) {\n continue;\n }\n\n const assetId = asset.type as Caip19AssetId;\n\n if (asset.decimals === undefined) {\n continue;\n }\n\n const rawBalanceStr = postBalance.amount.startsWith('0x')\n ? BigInt(postBalance.amount).toString()\n : postBalance.amount;\n\n const humanReadableAmount = new BigNumberJS(rawBalanceStr)\n .dividedBy(new BigNumberJS(10).pow(asset.decimals))\n .toFixed();\n\n assetsBalance[accountId][assetId] = {\n amount: humanReadableAmount,\n };\n\n assetsMetadata[assetId] = {\n type: getAssetType(assetId),\n symbol: asset.unit,\n name: asset.unit,\n decimals: asset.decimals,\n };\n }\n\n const response: DataResponse = { updateMode: 'merge' };\n if (Object.keys(assetsBalance[accountId]).length > 0) {\n response.assetsBalance = assetsBalance;\n response.assetsInfo = assetsMetadata;\n }\n\n return response;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask/assets-controller",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0",
|
|
4
4
|
"description": "Tracks assets balances/prices and handles token detection across all digital assets",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|
|
@@ -56,14 +56,14 @@
|
|
|
56
56
|
"@ethereumjs/util": "^9.1.0",
|
|
57
57
|
"@ethersproject/abi": "^5.7.0",
|
|
58
58
|
"@ethersproject/providers": "^5.7.0",
|
|
59
|
-
"@metamask/account-tree-controller": "^7.5.
|
|
60
|
-
"@metamask/accounts-controller": "^39.0.
|
|
61
|
-
"@metamask/assets-controllers": "^109.2.
|
|
59
|
+
"@metamask/account-tree-controller": "^7.5.3",
|
|
60
|
+
"@metamask/accounts-controller": "^39.0.3",
|
|
61
|
+
"@metamask/assets-controllers": "^109.2.2",
|
|
62
62
|
"@metamask/base-controller": "^9.1.0",
|
|
63
63
|
"@metamask/client-controller": "^1.0.1",
|
|
64
64
|
"@metamask/controller-utils": "^12.3.0",
|
|
65
|
-
"@metamask/core-backend": "^6.
|
|
66
|
-
"@metamask/keyring-api": "^23.
|
|
65
|
+
"@metamask/core-backend": "^6.4.0",
|
|
66
|
+
"@metamask/keyring-api": "^23.3.0",
|
|
67
67
|
"@metamask/keyring-controller": "^27.1.0",
|
|
68
68
|
"@metamask/keyring-internal-api": "^11.0.1",
|
|
69
69
|
"@metamask/keyring-snap-client": "^9.0.2",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"@metamask/preferences-controller": "^23.1.0",
|
|
77
77
|
"@metamask/snaps-controllers": "^19.0.0",
|
|
78
78
|
"@metamask/snaps-utils": "^12.1.2",
|
|
79
|
-
"@metamask/transaction-controller": "^68.
|
|
79
|
+
"@metamask/transaction-controller": "^68.2.0",
|
|
80
80
|
"@metamask/utils": "^11.11.0",
|
|
81
81
|
"async-mutex": "^0.5.0",
|
|
82
82
|
"bignumber.js": "^9.1.2",
|