@metamask-previews/assets-controllers 45.1.1-preview-175f4f5d → 45.1.1-preview-e1a582c9

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.
Files changed (57) hide show
  1. package/dist/MultichainBalancesController/BalancesTracker.cjs +117 -0
  2. package/dist/MultichainBalancesController/BalancesTracker.cjs.map +1 -0
  3. package/dist/MultichainBalancesController/BalancesTracker.d.cts +54 -0
  4. package/dist/MultichainBalancesController/BalancesTracker.d.cts.map +1 -0
  5. package/dist/MultichainBalancesController/BalancesTracker.d.mts +54 -0
  6. package/dist/MultichainBalancesController/BalancesTracker.d.mts.map +1 -0
  7. package/dist/MultichainBalancesController/BalancesTracker.mjs +113 -0
  8. package/dist/MultichainBalancesController/BalancesTracker.mjs.map +1 -0
  9. package/dist/MultichainBalancesController/MultichainBalancesController.cjs +203 -0
  10. package/dist/MultichainBalancesController/MultichainBalancesController.cjs.map +1 -0
  11. package/dist/MultichainBalancesController/MultichainBalancesController.d.cts +89 -0
  12. package/dist/MultichainBalancesController/MultichainBalancesController.d.cts.map +1 -0
  13. package/dist/MultichainBalancesController/MultichainBalancesController.d.mts +89 -0
  14. package/dist/MultichainBalancesController/MultichainBalancesController.d.mts.map +1 -0
  15. package/dist/MultichainBalancesController/MultichainBalancesController.mjs +201 -0
  16. package/dist/MultichainBalancesController/MultichainBalancesController.mjs.map +1 -0
  17. package/dist/MultichainBalancesController/Poller.cjs +42 -0
  18. package/dist/MultichainBalancesController/Poller.cjs.map +1 -0
  19. package/dist/MultichainBalancesController/Poller.d.cts +7 -0
  20. package/dist/MultichainBalancesController/Poller.d.cts.map +1 -0
  21. package/dist/MultichainBalancesController/Poller.d.mts +7 -0
  22. package/dist/MultichainBalancesController/Poller.d.mts.map +1 -0
  23. package/dist/MultichainBalancesController/Poller.mjs +38 -0
  24. package/dist/MultichainBalancesController/Poller.mjs.map +1 -0
  25. package/dist/MultichainBalancesController/constants.cjs +45 -0
  26. package/dist/MultichainBalancesController/constants.cjs.map +1 -0
  27. package/dist/MultichainBalancesController/constants.d.cts +29 -0
  28. package/dist/MultichainBalancesController/constants.d.cts.map +1 -0
  29. package/dist/MultichainBalancesController/constants.d.mts +29 -0
  30. package/dist/MultichainBalancesController/constants.d.mts.map +1 -0
  31. package/dist/MultichainBalancesController/constants.mjs +43 -0
  32. package/dist/MultichainBalancesController/constants.mjs.map +1 -0
  33. package/dist/MultichainBalancesController/index.cjs +13 -0
  34. package/dist/MultichainBalancesController/index.cjs.map +1 -0
  35. package/dist/MultichainBalancesController/index.d.cts +5 -0
  36. package/dist/MultichainBalancesController/index.d.cts.map +1 -0
  37. package/dist/MultichainBalancesController/index.d.mts +5 -0
  38. package/dist/MultichainBalancesController/index.d.mts.map +1 -0
  39. package/dist/MultichainBalancesController/index.mjs +4 -0
  40. package/dist/MultichainBalancesController/index.mjs.map +1 -0
  41. package/dist/MultichainBalancesController/utils.cjs +60 -0
  42. package/dist/MultichainBalancesController/utils.cjs.map +1 -0
  43. package/dist/MultichainBalancesController/utils.d.cts +29 -0
  44. package/dist/MultichainBalancesController/utils.d.cts.map +1 -0
  45. package/dist/MultichainBalancesController/utils.d.mts +29 -0
  46. package/dist/MultichainBalancesController/utils.d.mts.map +1 -0
  47. package/dist/MultichainBalancesController/utils.mjs +55 -0
  48. package/dist/MultichainBalancesController/utils.mjs.map +1 -0
  49. package/dist/index.cjs +9 -1
  50. package/dist/index.cjs.map +1 -1
  51. package/dist/index.d.cts +2 -0
  52. package/dist/index.d.cts.map +1 -1
  53. package/dist/index.d.mts +2 -0
  54. package/dist/index.d.mts.map +1 -1
  55. package/dist/index.mjs +3 -0
  56. package/dist/index.mjs.map +1 -1
  57. package/package.json +5 -1
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ 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");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
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
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _BalancesTracker_poller, _BalancesTracker_updateBalance, _BalancesTracker_balances;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.BalancesTracker = void 0;
16
+ const Poller_1 = require("./Poller.cjs");
17
+ const BALANCES_TRACKING_INTERVAL = 30 * 1000; // Every 30s in milliseconds.
18
+ class BalancesTracker {
19
+ constructor(updateBalanceCallback) {
20
+ _BalancesTracker_poller.set(this, void 0);
21
+ _BalancesTracker_updateBalance.set(this, void 0);
22
+ _BalancesTracker_balances.set(this, {});
23
+ __classPrivateFieldSet(this, _BalancesTracker_updateBalance, updateBalanceCallback, "f");
24
+ __classPrivateFieldSet(this, _BalancesTracker_poller, new Poller_1.Poller(this.updateBalances, BALANCES_TRACKING_INTERVAL), "f");
25
+ }
26
+ /**
27
+ * Starts the tracking process.
28
+ */
29
+ start() {
30
+ __classPrivateFieldGet(this, _BalancesTracker_poller, "f").start();
31
+ }
32
+ /**
33
+ * Stops the tracking process.
34
+ */
35
+ stop() {
36
+ __classPrivateFieldGet(this, _BalancesTracker_poller, "f").stop();
37
+ }
38
+ /**
39
+ * Checks if an account ID is being tracked.
40
+ *
41
+ * @param accountId - The account ID.
42
+ * @returns True if the account is being tracker, false otherwise.
43
+ */
44
+ isTracked(accountId) {
45
+ return accountId in __classPrivateFieldGet(this, _BalancesTracker_balances, "f");
46
+ }
47
+ /**
48
+ * Asserts that an account ID is being tracked.
49
+ *
50
+ * @param accountId - The account ID.
51
+ * @throws If the account ID is not being tracked.
52
+ */
53
+ assertBeingTracked(accountId) {
54
+ if (!this.isTracked(accountId)) {
55
+ throw new Error(`Account is not being tracked: ${accountId}`);
56
+ }
57
+ }
58
+ /**
59
+ * Starts tracking a new account ID. This method has no effect on already tracked
60
+ * accounts.
61
+ *
62
+ * @param accountId - The account ID.
63
+ * @param blockTime - The block time (used when refreshing the account balances).
64
+ */
65
+ track(accountId, blockTime) {
66
+ // Do not overwrite current info if already being tracked!
67
+ if (!this.isTracked(accountId)) {
68
+ __classPrivateFieldGet(this, _BalancesTracker_balances, "f")[accountId] = {
69
+ lastUpdated: 0,
70
+ blockTime,
71
+ };
72
+ }
73
+ }
74
+ /**
75
+ * Stops tracking a tracked account ID.
76
+ *
77
+ * @param accountId - The account ID.
78
+ * @throws If the account ID is not being tracked.
79
+ */
80
+ untrack(accountId) {
81
+ this.assertBeingTracked(accountId);
82
+ delete __classPrivateFieldGet(this, _BalancesTracker_balances, "f")[accountId];
83
+ }
84
+ /**
85
+ * Update the balances for a tracked account ID.
86
+ *
87
+ * @param accountId - The account ID.
88
+ * @throws If the account ID is not being tracked.
89
+ */
90
+ async updateBalance(accountId) {
91
+ this.assertBeingTracked(accountId);
92
+ // We check if the balance is outdated (by comparing to the block time associated
93
+ // with this kind of account).
94
+ //
95
+ // This might not be super accurate, but we could probably compute this differently
96
+ // and try to sync with the "real block time"!
97
+ const info = __classPrivateFieldGet(this, _BalancesTracker_balances, "f")[accountId];
98
+ const isOutdated = Date.now() - info.lastUpdated >= info.blockTime;
99
+ const hasNoBalanceYet = info.lastUpdated === 0;
100
+ if (hasNoBalanceYet || isOutdated) {
101
+ await __classPrivateFieldGet(this, _BalancesTracker_updateBalance, "f").call(this, accountId);
102
+ __classPrivateFieldGet(this, _BalancesTracker_balances, "f")[accountId].lastUpdated = Date.now();
103
+ }
104
+ }
105
+ /**
106
+ * Update the balances of all tracked accounts (only if the balances
107
+ * is considered outdated).
108
+ */
109
+ async updateBalances() {
110
+ await Promise.allSettled(Object.keys(__classPrivateFieldGet(this, _BalancesTracker_balances, "f")).map(async (accountId) => {
111
+ await this.updateBalance(accountId);
112
+ }));
113
+ }
114
+ }
115
+ exports.BalancesTracker = BalancesTracker;
116
+ _BalancesTracker_poller = new WeakMap(), _BalancesTracker_updateBalance = new WeakMap(), _BalancesTracker_balances = new WeakMap();
117
+ //# sourceMappingURL=BalancesTracker.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BalancesTracker.cjs","sourceRoot":"","sources":["../../src/MultichainBalancesController/BalancesTracker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,yCAAkC;AAOlC,MAAM,0BAA0B,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,6BAA6B;AAE3E,MAAa,eAAe;IAO1B,YAAY,qBAA2D;QANvE,0CAAgB;QAEhB,iDAAqD;QAErD,oCAAyC,EAAE,EAAC;QAG1C,uBAAA,IAAI,kCAAkB,qBAAqB,MAAA,CAAC;QAE5C,uBAAA,IAAI,2BAAW,IAAI,eAAM,CAAC,IAAI,CAAC,cAAc,EAAE,0BAA0B,CAAC,MAAA,CAAC;IAC7E,CAAC;IAED;;OAEG;IACH,KAAK;QACH,uBAAA,IAAI,+BAAQ,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,uBAAA,IAAI,+BAAQ,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAC,SAAiB;QACzB,OAAO,SAAS,IAAI,uBAAA,IAAI,iCAAU,CAAC;IACrC,CAAC;IAED;;;;;OAKG;IACH,kBAAkB,CAAC,SAAiB;QAClC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;YAC9B,MAAM,IAAI,KAAK,CAAC,iCAAiC,SAAS,EAAE,CAAC,CAAC;SAC/D;IACH,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,SAAiB,EAAE,SAAiB;QACxC,0DAA0D;QAC1D,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;YAC9B,uBAAA,IAAI,iCAAU,CAAC,SAAS,CAAC,GAAG;gBAC1B,WAAW,EAAE,CAAC;gBACd,SAAS;aACV,CAAC;SACH;IACH,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,SAAiB;QACvB,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QACnC,OAAO,uBAAA,IAAI,iCAAU,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,aAAa,CAAC,SAAiB;QACnC,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QAEnC,iFAAiF;QACjF,8BAA8B;QAC9B,EAAE;QACF,mFAAmF;QACnF,8CAA8C;QAC9C,MAAM,IAAI,GAAG,uBAAA,IAAI,iCAAU,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC;QACnE,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,KAAK,CAAC,CAAC;QAC/C,IAAI,eAAe,IAAI,UAAU,EAAE;YACjC,MAAM,uBAAA,IAAI,sCAAe,MAAnB,IAAI,EAAgB,SAAS,CAAC,CAAC;YACrC,uBAAA,IAAI,iCAAU,CAAC,SAAS,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;SACpD;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,cAAc;QAClB,MAAM,OAAO,CAAC,UAAU,CACtB,MAAM,CAAC,IAAI,CAAC,uBAAA,IAAI,iCAAU,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;YAClD,MAAM,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QACtC,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;CACF;AA/GD,0CA+GC","sourcesContent":["import { Poller } from './Poller';\n\ntype BalanceInfo = {\n lastUpdated: number;\n blockTime: number;\n};\n\nconst BALANCES_TRACKING_INTERVAL = 30 * 1000; // Every 30s in milliseconds.\n\nexport class BalancesTracker {\n #poller: Poller;\n\n #updateBalance: (accountId: string) => Promise<void>;\n\n #balances: Record<string, BalanceInfo> = {};\n\n constructor(updateBalanceCallback: (accountId: string) => Promise<void>) {\n this.#updateBalance = updateBalanceCallback;\n\n this.#poller = new Poller(this.updateBalances, BALANCES_TRACKING_INTERVAL);\n }\n\n /**\n * Starts the tracking process.\n */\n start(): void {\n this.#poller.start();\n }\n\n /**\n * Stops the tracking process.\n */\n stop(): void {\n this.#poller.stop();\n }\n\n /**\n * Checks if an account ID is being tracked.\n *\n * @param accountId - The account ID.\n * @returns True if the account is being tracker, false otherwise.\n */\n isTracked(accountId: string) {\n return accountId in this.#balances;\n }\n\n /**\n * Asserts that an account ID is being tracked.\n *\n * @param accountId - The account ID.\n * @throws If the account ID is not being tracked.\n */\n assertBeingTracked(accountId: string) {\n if (!this.isTracked(accountId)) {\n throw new Error(`Account is not being tracked: ${accountId}`);\n }\n }\n\n /**\n * Starts tracking a new account ID. This method has no effect on already tracked\n * accounts.\n *\n * @param accountId - The account ID.\n * @param blockTime - The block time (used when refreshing the account balances).\n */\n track(accountId: string, blockTime: number) {\n // Do not overwrite current info if already being tracked!\n if (!this.isTracked(accountId)) {\n this.#balances[accountId] = {\n lastUpdated: 0,\n blockTime,\n };\n }\n }\n\n /**\n * Stops tracking a tracked account ID.\n *\n * @param accountId - The account ID.\n * @throws If the account ID is not being tracked.\n */\n untrack(accountId: string) {\n this.assertBeingTracked(accountId);\n delete this.#balances[accountId];\n }\n\n /**\n * Update the balances for a tracked account ID.\n *\n * @param accountId - The account ID.\n * @throws If the account ID is not being tracked.\n */\n async updateBalance(accountId: string) {\n this.assertBeingTracked(accountId);\n\n // We check if the balance is outdated (by comparing to the block time associated\n // with this kind of account).\n //\n // This might not be super accurate, but we could probably compute this differently\n // and try to sync with the \"real block time\"!\n const info = this.#balances[accountId];\n const isOutdated = Date.now() - info.lastUpdated >= info.blockTime;\n const hasNoBalanceYet = info.lastUpdated === 0;\n if (hasNoBalanceYet || isOutdated) {\n await this.#updateBalance(accountId);\n this.#balances[accountId].lastUpdated = Date.now();\n }\n }\n\n /**\n * Update the balances of all tracked accounts (only if the balances\n * is considered outdated).\n */\n async updateBalances() {\n await Promise.allSettled(\n Object.keys(this.#balances).map(async (accountId) => {\n await this.updateBalance(accountId);\n }),\n );\n }\n}\n"]}
@@ -0,0 +1,54 @@
1
+ export declare class BalancesTracker {
2
+ #private;
3
+ constructor(updateBalanceCallback: (accountId: string) => Promise<void>);
4
+ /**
5
+ * Starts the tracking process.
6
+ */
7
+ start(): void;
8
+ /**
9
+ * Stops the tracking process.
10
+ */
11
+ stop(): void;
12
+ /**
13
+ * Checks if an account ID is being tracked.
14
+ *
15
+ * @param accountId - The account ID.
16
+ * @returns True if the account is being tracker, false otherwise.
17
+ */
18
+ isTracked(accountId: string): boolean;
19
+ /**
20
+ * Asserts that an account ID is being tracked.
21
+ *
22
+ * @param accountId - The account ID.
23
+ * @throws If the account ID is not being tracked.
24
+ */
25
+ assertBeingTracked(accountId: string): void;
26
+ /**
27
+ * Starts tracking a new account ID. This method has no effect on already tracked
28
+ * accounts.
29
+ *
30
+ * @param accountId - The account ID.
31
+ * @param blockTime - The block time (used when refreshing the account balances).
32
+ */
33
+ track(accountId: string, blockTime: number): void;
34
+ /**
35
+ * Stops tracking a tracked account ID.
36
+ *
37
+ * @param accountId - The account ID.
38
+ * @throws If the account ID is not being tracked.
39
+ */
40
+ untrack(accountId: string): void;
41
+ /**
42
+ * Update the balances for a tracked account ID.
43
+ *
44
+ * @param accountId - The account ID.
45
+ * @throws If the account ID is not being tracked.
46
+ */
47
+ updateBalance(accountId: string): Promise<void>;
48
+ /**
49
+ * Update the balances of all tracked accounts (only if the balances
50
+ * is considered outdated).
51
+ */
52
+ updateBalances(): Promise<void>;
53
+ }
54
+ //# sourceMappingURL=BalancesTracker.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BalancesTracker.d.cts","sourceRoot":"","sources":["../../src/MultichainBalancesController/BalancesTracker.ts"],"names":[],"mappings":"AASA,qBAAa,eAAe;;gBAOd,qBAAqB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC;IAMvE;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;;;;OAKG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM;IAI3B;;;;;OAKG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM;IAMpC;;;;;;OAMG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAU1C;;;;;OAKG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM;IAKzB;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM;IAiBrC;;;OAGG;IACG,cAAc;CAOrB"}
@@ -0,0 +1,54 @@
1
+ export declare class BalancesTracker {
2
+ #private;
3
+ constructor(updateBalanceCallback: (accountId: string) => Promise<void>);
4
+ /**
5
+ * Starts the tracking process.
6
+ */
7
+ start(): void;
8
+ /**
9
+ * Stops the tracking process.
10
+ */
11
+ stop(): void;
12
+ /**
13
+ * Checks if an account ID is being tracked.
14
+ *
15
+ * @param accountId - The account ID.
16
+ * @returns True if the account is being tracker, false otherwise.
17
+ */
18
+ isTracked(accountId: string): boolean;
19
+ /**
20
+ * Asserts that an account ID is being tracked.
21
+ *
22
+ * @param accountId - The account ID.
23
+ * @throws If the account ID is not being tracked.
24
+ */
25
+ assertBeingTracked(accountId: string): void;
26
+ /**
27
+ * Starts tracking a new account ID. This method has no effect on already tracked
28
+ * accounts.
29
+ *
30
+ * @param accountId - The account ID.
31
+ * @param blockTime - The block time (used when refreshing the account balances).
32
+ */
33
+ track(accountId: string, blockTime: number): void;
34
+ /**
35
+ * Stops tracking a tracked account ID.
36
+ *
37
+ * @param accountId - The account ID.
38
+ * @throws If the account ID is not being tracked.
39
+ */
40
+ untrack(accountId: string): void;
41
+ /**
42
+ * Update the balances for a tracked account ID.
43
+ *
44
+ * @param accountId - The account ID.
45
+ * @throws If the account ID is not being tracked.
46
+ */
47
+ updateBalance(accountId: string): Promise<void>;
48
+ /**
49
+ * Update the balances of all tracked accounts (only if the balances
50
+ * is considered outdated).
51
+ */
52
+ updateBalances(): Promise<void>;
53
+ }
54
+ //# sourceMappingURL=BalancesTracker.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BalancesTracker.d.mts","sourceRoot":"","sources":["../../src/MultichainBalancesController/BalancesTracker.ts"],"names":[],"mappings":"AASA,qBAAa,eAAe;;gBAOd,qBAAqB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC;IAMvE;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;;;;OAKG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM;IAI3B;;;;;OAKG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM;IAMpC;;;;;;OAMG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAU1C;;;;;OAKG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM;IAKzB;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM;IAiBrC;;;OAGG;IACG,cAAc;CAOrB"}
@@ -0,0 +1,113 @@
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 _BalancesTracker_poller, _BalancesTracker_updateBalance, _BalancesTracker_balances;
13
+ import { Poller } from "./Poller.mjs";
14
+ const BALANCES_TRACKING_INTERVAL = 30 * 1000; // Every 30s in milliseconds.
15
+ export class BalancesTracker {
16
+ constructor(updateBalanceCallback) {
17
+ _BalancesTracker_poller.set(this, void 0);
18
+ _BalancesTracker_updateBalance.set(this, void 0);
19
+ _BalancesTracker_balances.set(this, {});
20
+ __classPrivateFieldSet(this, _BalancesTracker_updateBalance, updateBalanceCallback, "f");
21
+ __classPrivateFieldSet(this, _BalancesTracker_poller, new Poller(this.updateBalances, BALANCES_TRACKING_INTERVAL), "f");
22
+ }
23
+ /**
24
+ * Starts the tracking process.
25
+ */
26
+ start() {
27
+ __classPrivateFieldGet(this, _BalancesTracker_poller, "f").start();
28
+ }
29
+ /**
30
+ * Stops the tracking process.
31
+ */
32
+ stop() {
33
+ __classPrivateFieldGet(this, _BalancesTracker_poller, "f").stop();
34
+ }
35
+ /**
36
+ * Checks if an account ID is being tracked.
37
+ *
38
+ * @param accountId - The account ID.
39
+ * @returns True if the account is being tracker, false otherwise.
40
+ */
41
+ isTracked(accountId) {
42
+ return accountId in __classPrivateFieldGet(this, _BalancesTracker_balances, "f");
43
+ }
44
+ /**
45
+ * Asserts that an account ID is being tracked.
46
+ *
47
+ * @param accountId - The account ID.
48
+ * @throws If the account ID is not being tracked.
49
+ */
50
+ assertBeingTracked(accountId) {
51
+ if (!this.isTracked(accountId)) {
52
+ throw new Error(`Account is not being tracked: ${accountId}`);
53
+ }
54
+ }
55
+ /**
56
+ * Starts tracking a new account ID. This method has no effect on already tracked
57
+ * accounts.
58
+ *
59
+ * @param accountId - The account ID.
60
+ * @param blockTime - The block time (used when refreshing the account balances).
61
+ */
62
+ track(accountId, blockTime) {
63
+ // Do not overwrite current info if already being tracked!
64
+ if (!this.isTracked(accountId)) {
65
+ __classPrivateFieldGet(this, _BalancesTracker_balances, "f")[accountId] = {
66
+ lastUpdated: 0,
67
+ blockTime,
68
+ };
69
+ }
70
+ }
71
+ /**
72
+ * Stops tracking a tracked account ID.
73
+ *
74
+ * @param accountId - The account ID.
75
+ * @throws If the account ID is not being tracked.
76
+ */
77
+ untrack(accountId) {
78
+ this.assertBeingTracked(accountId);
79
+ delete __classPrivateFieldGet(this, _BalancesTracker_balances, "f")[accountId];
80
+ }
81
+ /**
82
+ * Update the balances for a tracked account ID.
83
+ *
84
+ * @param accountId - The account ID.
85
+ * @throws If the account ID is not being tracked.
86
+ */
87
+ async updateBalance(accountId) {
88
+ this.assertBeingTracked(accountId);
89
+ // We check if the balance is outdated (by comparing to the block time associated
90
+ // with this kind of account).
91
+ //
92
+ // This might not be super accurate, but we could probably compute this differently
93
+ // and try to sync with the "real block time"!
94
+ const info = __classPrivateFieldGet(this, _BalancesTracker_balances, "f")[accountId];
95
+ const isOutdated = Date.now() - info.lastUpdated >= info.blockTime;
96
+ const hasNoBalanceYet = info.lastUpdated === 0;
97
+ if (hasNoBalanceYet || isOutdated) {
98
+ await __classPrivateFieldGet(this, _BalancesTracker_updateBalance, "f").call(this, accountId);
99
+ __classPrivateFieldGet(this, _BalancesTracker_balances, "f")[accountId].lastUpdated = Date.now();
100
+ }
101
+ }
102
+ /**
103
+ * Update the balances of all tracked accounts (only if the balances
104
+ * is considered outdated).
105
+ */
106
+ async updateBalances() {
107
+ await Promise.allSettled(Object.keys(__classPrivateFieldGet(this, _BalancesTracker_balances, "f")).map(async (accountId) => {
108
+ await this.updateBalance(accountId);
109
+ }));
110
+ }
111
+ }
112
+ _BalancesTracker_poller = new WeakMap(), _BalancesTracker_updateBalance = new WeakMap(), _BalancesTracker_balances = new WeakMap();
113
+ //# sourceMappingURL=BalancesTracker.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BalancesTracker.mjs","sourceRoot":"","sources":["../../src/MultichainBalancesController/BalancesTracker.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,qBAAiB;AAOlC,MAAM,0BAA0B,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,6BAA6B;AAE3E,MAAM,OAAO,eAAe;IAO1B,YAAY,qBAA2D;QANvE,0CAAgB;QAEhB,iDAAqD;QAErD,oCAAyC,EAAE,EAAC;QAG1C,uBAAA,IAAI,kCAAkB,qBAAqB,MAAA,CAAC;QAE5C,uBAAA,IAAI,2BAAW,IAAI,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,0BAA0B,CAAC,MAAA,CAAC;IAC7E,CAAC;IAED;;OAEG;IACH,KAAK;QACH,uBAAA,IAAI,+BAAQ,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,uBAAA,IAAI,+BAAQ,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAC,SAAiB;QACzB,OAAO,SAAS,IAAI,uBAAA,IAAI,iCAAU,CAAC;IACrC,CAAC;IAED;;;;;OAKG;IACH,kBAAkB,CAAC,SAAiB;QAClC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;YAC9B,MAAM,IAAI,KAAK,CAAC,iCAAiC,SAAS,EAAE,CAAC,CAAC;SAC/D;IACH,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,SAAiB,EAAE,SAAiB;QACxC,0DAA0D;QAC1D,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;YAC9B,uBAAA,IAAI,iCAAU,CAAC,SAAS,CAAC,GAAG;gBAC1B,WAAW,EAAE,CAAC;gBACd,SAAS;aACV,CAAC;SACH;IACH,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,SAAiB;QACvB,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QACnC,OAAO,uBAAA,IAAI,iCAAU,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,aAAa,CAAC,SAAiB;QACnC,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QAEnC,iFAAiF;QACjF,8BAA8B;QAC9B,EAAE;QACF,mFAAmF;QACnF,8CAA8C;QAC9C,MAAM,IAAI,GAAG,uBAAA,IAAI,iCAAU,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC;QACnE,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,KAAK,CAAC,CAAC;QAC/C,IAAI,eAAe,IAAI,UAAU,EAAE;YACjC,MAAM,uBAAA,IAAI,sCAAe,MAAnB,IAAI,EAAgB,SAAS,CAAC,CAAC;YACrC,uBAAA,IAAI,iCAAU,CAAC,SAAS,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;SACpD;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,cAAc;QAClB,MAAM,OAAO,CAAC,UAAU,CACtB,MAAM,CAAC,IAAI,CAAC,uBAAA,IAAI,iCAAU,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;YAClD,MAAM,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QACtC,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { Poller } from './Poller';\n\ntype BalanceInfo = {\n lastUpdated: number;\n blockTime: number;\n};\n\nconst BALANCES_TRACKING_INTERVAL = 30 * 1000; // Every 30s in milliseconds.\n\nexport class BalancesTracker {\n #poller: Poller;\n\n #updateBalance: (accountId: string) => Promise<void>;\n\n #balances: Record<string, BalanceInfo> = {};\n\n constructor(updateBalanceCallback: (accountId: string) => Promise<void>) {\n this.#updateBalance = updateBalanceCallback;\n\n this.#poller = new Poller(this.updateBalances, BALANCES_TRACKING_INTERVAL);\n }\n\n /**\n * Starts the tracking process.\n */\n start(): void {\n this.#poller.start();\n }\n\n /**\n * Stops the tracking process.\n */\n stop(): void {\n this.#poller.stop();\n }\n\n /**\n * Checks if an account ID is being tracked.\n *\n * @param accountId - The account ID.\n * @returns True if the account is being tracker, false otherwise.\n */\n isTracked(accountId: string) {\n return accountId in this.#balances;\n }\n\n /**\n * Asserts that an account ID is being tracked.\n *\n * @param accountId - The account ID.\n * @throws If the account ID is not being tracked.\n */\n assertBeingTracked(accountId: string) {\n if (!this.isTracked(accountId)) {\n throw new Error(`Account is not being tracked: ${accountId}`);\n }\n }\n\n /**\n * Starts tracking a new account ID. This method has no effect on already tracked\n * accounts.\n *\n * @param accountId - The account ID.\n * @param blockTime - The block time (used when refreshing the account balances).\n */\n track(accountId: string, blockTime: number) {\n // Do not overwrite current info if already being tracked!\n if (!this.isTracked(accountId)) {\n this.#balances[accountId] = {\n lastUpdated: 0,\n blockTime,\n };\n }\n }\n\n /**\n * Stops tracking a tracked account ID.\n *\n * @param accountId - The account ID.\n * @throws If the account ID is not being tracked.\n */\n untrack(accountId: string) {\n this.assertBeingTracked(accountId);\n delete this.#balances[accountId];\n }\n\n /**\n * Update the balances for a tracked account ID.\n *\n * @param accountId - The account ID.\n * @throws If the account ID is not being tracked.\n */\n async updateBalance(accountId: string) {\n this.assertBeingTracked(accountId);\n\n // We check if the balance is outdated (by comparing to the block time associated\n // with this kind of account).\n //\n // This might not be super accurate, but we could probably compute this differently\n // and try to sync with the \"real block time\"!\n const info = this.#balances[accountId];\n const isOutdated = Date.now() - info.lastUpdated >= info.blockTime;\n const hasNoBalanceYet = info.lastUpdated === 0;\n if (hasNoBalanceYet || isOutdated) {\n await this.#updateBalance(accountId);\n this.#balances[accountId].lastUpdated = Date.now();\n }\n }\n\n /**\n * Update the balances of all tracked accounts (only if the balances\n * is considered outdated).\n */\n async updateBalances() {\n await Promise.allSettled(\n Object.keys(this.#balances).map(async (accountId) => {\n await this.updateBalance(accountId);\n }),\n );\n }\n}\n"]}
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
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
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
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 _MultichainBalancesController_instances, _MultichainBalancesController_tracker, _MultichainBalancesController_networkAssetsMap, _MultichainBalancesController_trackAccount, _MultichainBalancesController_listMultichainAccounts, _MultichainBalancesController_listAccounts, _MultichainBalancesController_getAccount, _MultichainBalancesController_updateBalance, _MultichainBalancesController_isNonEvmAccount, _MultichainBalancesController_handleOnAccountAdded, _MultichainBalancesController_handleOnAccountRemoved, _MultichainBalancesController_getBalances, _MultichainBalancesController_getClient;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.MultichainBalancesController = exports.defaultState = void 0;
16
+ const base_controller_1 = require("@metamask/base-controller");
17
+ const keyring_api_1 = require("@metamask/keyring-api");
18
+ const snaps_utils_1 = require("@metamask/snaps-utils");
19
+ const _1 = require("./index.cjs");
20
+ const utils_1 = require("./utils.cjs");
21
+ const controllerName = 'MultichainBalancesController';
22
+ /**
23
+ * Default state of the {@link MultichainBalancesController}.
24
+ */
25
+ exports.defaultState = { balances: {} };
26
+ /**
27
+ * {@link multichainBalancesController}'s metadata.
28
+ *
29
+ * This allows us to choose if fields of the state should be persisted or not
30
+ * using the `persist` flag; and if they can be sent to Sentry or not, using
31
+ * the `anonymous` flag.
32
+ */
33
+ const multichainBalancesControllerMetadata = {
34
+ balances: {
35
+ persist: true,
36
+ anonymous: false,
37
+ },
38
+ };
39
+ /**
40
+ * The MultichainBalancesController is responsible for fetching and caching account
41
+ * balances.
42
+ */
43
+ class MultichainBalancesController extends base_controller_1.BaseController {
44
+ constructor({ messenger, state, }) {
45
+ super({
46
+ messenger,
47
+ name: controllerName,
48
+ metadata: multichainBalancesControllerMetadata,
49
+ state: {
50
+ ...exports.defaultState,
51
+ ...state,
52
+ },
53
+ });
54
+ _MultichainBalancesController_instances.add(this);
55
+ _MultichainBalancesController_tracker.set(this, void 0);
56
+ // As a temporary solution, we are using a map to store the assets
57
+ // that are hardcoded in the module. In the future, this mapping
58
+ // should be dynamic to allow a client to register and unregister assets
59
+ _MultichainBalancesController_networkAssetsMap.set(this, _1.NETWORK_ASSETS_MAP);
60
+ __classPrivateFieldSet(this, _MultichainBalancesController_tracker, new _1.BalancesTracker(async (accountId) => await __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_updateBalance).call(this, accountId)), "f");
61
+ // Register all non-EVM accounts into the tracker
62
+ for (const account of __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_listAccounts).call(this)) {
63
+ __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_trackAccount).call(this, account);
64
+ }
65
+ this.messagingSystem.subscribe('AccountsController:accountAdded', (account) => __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_handleOnAccountAdded).call(this, account));
66
+ this.messagingSystem.subscribe('AccountsController:accountRemoved', (account) => __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_handleOnAccountRemoved).call(this, account));
67
+ }
68
+ /**
69
+ * Starts the polling process.
70
+ */
71
+ start() {
72
+ __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").start();
73
+ }
74
+ /**
75
+ * Stops the polling process.
76
+ */
77
+ stop() {
78
+ __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").stop();
79
+ }
80
+ /**
81
+ * Updates the balances of one account. This method doesn't return
82
+ * anything, but it updates the state of the controller.
83
+ *
84
+ * @param accountId - The account ID.
85
+ */
86
+ async updateBalance(accountId) {
87
+ // NOTE: No need to track the account here, since we start tracking those when
88
+ // the "AccountsController:accountAdded" is fired.
89
+ await __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").updateBalance(accountId);
90
+ }
91
+ /**
92
+ * Updates the balances of all supported accounts. This method doesn't return
93
+ * anything, but it updates the state of the controller.
94
+ */
95
+ async updateBalances() {
96
+ await __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").updateBalances();
97
+ }
98
+ }
99
+ exports.MultichainBalancesController = MultichainBalancesController;
100
+ _MultichainBalancesController_tracker = new WeakMap(), _MultichainBalancesController_networkAssetsMap = new WeakMap(), _MultichainBalancesController_instances = new WeakSet(), _MultichainBalancesController_trackAccount = function _MultichainBalancesController_trackAccount(account) {
101
+ if (!__classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_isNonEvmAccount).call(this, account)) {
102
+ // Nothing to do here for EVM accounts
103
+ return;
104
+ }
105
+ const updateTime =
106
+ // @ts-expect-error - For the moment we are only tracking non-EVM accounts and this is
107
+ // checked with the method `#isNonEvmAccount`. We can ignore this error since
108
+ // eip155:eoa and eip155:erc4337 account type balances are not tracked here.
109
+ _1.BALANCE_UPDATE_INTERVALS[__classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getAccount).call(this, account.id).type];
110
+ __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").track(account.id, updateTime);
111
+ }, _MultichainBalancesController_listMultichainAccounts = function _MultichainBalancesController_listMultichainAccounts() {
112
+ return this.messagingSystem.call('AccountsController:listMultichainAccounts');
113
+ }, _MultichainBalancesController_listAccounts = function _MultichainBalancesController_listAccounts() {
114
+ const accounts = __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_listMultichainAccounts).call(this);
115
+ return accounts.filter((account) => __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_isNonEvmAccount).call(this, account));
116
+ }, _MultichainBalancesController_getAccount = function _MultichainBalancesController_getAccount(accountId) {
117
+ const account = __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_listMultichainAccounts).call(this).find((multichainAccount) => multichainAccount.id === accountId);
118
+ if (!account) {
119
+ throw new Error(`Unknown account: ${accountId}`);
120
+ }
121
+ if (!__classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_isNonEvmAccount).call(this, account)) {
122
+ throw new Error(`Account is not a non-EVM account: ${accountId}`);
123
+ }
124
+ return account;
125
+ }, _MultichainBalancesController_updateBalance =
126
+ /**
127
+ * Updates the balances of one account. This method doesn't return
128
+ * anything, but it updates the state of the controller.
129
+ *
130
+ * @param accountId - The account ID.
131
+ */
132
+ async function _MultichainBalancesController_updateBalance(accountId) {
133
+ const account = __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getAccount).call(this, accountId);
134
+ const partialState = { balances: {} };
135
+ const scope = (0, utils_1.getScopeForAddress)(account);
136
+ const assetsList = __classPrivateFieldGet(this, _MultichainBalancesController_networkAssetsMap, "f")[scope];
137
+ if (account.metadata.snap) {
138
+ partialState.balances[account.id] = await __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getBalances).call(this, account.id, account.metadata.snap.id, assetsList);
139
+ }
140
+ this.update((state) => ({
141
+ ...state,
142
+ balances: {
143
+ ...state.balances,
144
+ ...partialState.balances,
145
+ },
146
+ }));
147
+ }, _MultichainBalancesController_isNonEvmAccount = function _MultichainBalancesController_isNonEvmAccount(account) {
148
+ return (!(0, keyring_api_1.isEvmAccountType)(account.type) &&
149
+ // Non-EVM accounts are backed by a Snap for now
150
+ account.metadata.snap !== undefined);
151
+ }, _MultichainBalancesController_handleOnAccountAdded =
152
+ /**
153
+ * Handles changes when a new account has been added.
154
+ *
155
+ * @param account - The new account being added.
156
+ */
157
+ async function _MultichainBalancesController_handleOnAccountAdded(account) {
158
+ __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_trackAccount).call(this, account);
159
+ // NOTE: Unfortunately, we cannot update the balance right away here, because
160
+ // messenger's events are running synchronously and fetching the balance is
161
+ // asynchronous.
162
+ // Updating the balance here would resume at some point but the event emitter
163
+ // will not `await` this (so we have no real control "when" the balance will
164
+ // really be updated), see:
165
+ // - https://github.com/MetaMask/core/blob/v213.0.0/packages/accounts-controller/src/AccountsController.ts#L1036-L1039
166
+ }, _MultichainBalancesController_handleOnAccountRemoved =
167
+ /**
168
+ * Handles changes when a new account has been removed.
169
+ *
170
+ * @param accountId - The account ID being removed.
171
+ */
172
+ async function _MultichainBalancesController_handleOnAccountRemoved(accountId) {
173
+ if (__classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").isTracked(accountId)) {
174
+ __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").untrack(accountId);
175
+ }
176
+ if (accountId in this.state.balances) {
177
+ this.update((state) => {
178
+ delete state.balances[accountId];
179
+ return state;
180
+ });
181
+ }
182
+ }, _MultichainBalancesController_getBalances =
183
+ /**
184
+ * Get the balances for an account.
185
+ *
186
+ * @param accountId - ID of the account to get balances for.
187
+ * @param snapId - ID of the Snap which manages the account.
188
+ * @param assetTypes - Array of asset types to get balances for.
189
+ * @returns A map of asset types to balances.
190
+ */
191
+ async function _MultichainBalancesController_getBalances(accountId, snapId, assetTypes) {
192
+ return await __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getClient).call(this, snapId).getAccountBalances(accountId, assetTypes);
193
+ }, _MultichainBalancesController_getClient = function _MultichainBalancesController_getClient(snapId) {
194
+ return new keyring_api_1.KeyringClient({
195
+ send: async (request) => (await this.messagingSystem.call('SnapController:handleRequest', {
196
+ snapId: snapId,
197
+ origin: 'metamask',
198
+ handler: snaps_utils_1.HandlerType.OnKeyringRequest,
199
+ request,
200
+ })),
201
+ });
202
+ };
203
+ //# sourceMappingURL=MultichainBalancesController.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MultichainBalancesController.cjs","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n} from '@metamask/accounts-controller';\nimport {\n BaseController,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport {\n KeyringClient,\n type Balance,\n type CaipAssetType,\n type InternalAccount,\n isEvmAccountType,\n} from '@metamask/keyring-api';\nimport type { HandleSnapRequest } from '@metamask/snaps-controllers';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\nimport type { Draft } from 'immer';\n\nimport {\n BalancesTracker,\n BALANCE_UPDATE_INTERVALS,\n NETWORK_ASSETS_MAP,\n} from '.';\nimport { getScopeForAddress } from './utils';\n\nconst controllerName = 'MultichainBalancesController';\n\n/**\n * State used by the {@link MultichainBalancesController} to cache account balances.\n */\nexport type MultichainBalancesControllerState = {\n balances: {\n [account: string]: {\n [asset: string]: {\n amount: string;\n unit: string;\n };\n };\n };\n};\n\n/**\n * Default state of the {@link MultichainBalancesController}.\n */\nexport const defaultState: MultichainBalancesControllerState = { balances: {} };\n\n/**\n * Returns the state of the {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n MultichainBalancesControllerState\n >;\n\n/**\n * Updates the balances of all supported accounts in {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerUpdateBalancesAction = {\n type: `${typeof controllerName}:updateBalances`;\n handler: MultichainBalancesController['updateBalances'];\n};\n\n/**\n * Event emitted when the state of the {@link MultichainBalancesController} changes.\n */\nexport type MultichainBalancesControllerStateChange =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainBalancesControllerState\n >;\n\n/**\n * Actions exposed by the {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerActions =\n | MultichainBalancesControllerGetStateAction\n | MultichainBalancesControllerUpdateBalancesAction;\n\n/**\n * Events emitted by {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerEvents =\n MultichainBalancesControllerStateChange;\n\n/**\n * Actions that this controller is allowed to call.\n */\nexport type AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\nexport type AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent;\n\n/**\n * Messenger type for the MultichainBalancesController.\n */\nexport type MultichainBalancesControllerMessenger =\n RestrictedControllerMessenger<\n typeof controllerName,\n MultichainBalancesControllerActions | AllowedActions,\n MultichainBalancesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n >;\n\n/**\n * {@link multichainBalancesController}'s metadata.\n *\n * This allows us to choose if fields of the state should be persisted or not\n * using the `persist` flag; and if they can be sent to Sentry or not, using\n * the `anonymous` flag.\n */\nconst multichainBalancesControllerMetadata = {\n balances: {\n persist: true,\n anonymous: false,\n },\n};\n\n/**\n * The MultichainBalancesController is responsible for fetching and caching account\n * balances.\n */\nexport class MultichainBalancesController extends BaseController<\n typeof controllerName,\n MultichainBalancesControllerState,\n MultichainBalancesControllerMessenger\n> {\n readonly #tracker: BalancesTracker;\n\n // As a temporary solution, we are using a map to store the assets\n // that are hardcoded in the module. In the future, this mapping\n // should be dynamic to allow a client to register and unregister assets\n readonly #networkAssetsMap: Record<string, string[]> = NETWORK_ASSETS_MAP;\n\n constructor({\n messenger,\n state,\n }: {\n messenger: MultichainBalancesControllerMessenger;\n state: MultichainBalancesControllerState;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: multichainBalancesControllerMetadata,\n state: {\n ...defaultState,\n ...state,\n },\n });\n\n this.#tracker = new BalancesTracker(\n async (accountId: string) => await this.#updateBalance(accountId),\n );\n\n // Register all non-EVM accounts into the tracker\n for (const account of this.#listAccounts()) {\n this.#trackAccount(account);\n }\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountAdded',\n (account) => this.#handleOnAccountAdded(account),\n );\n this.messagingSystem.subscribe(\n 'AccountsController:accountRemoved',\n (account) => this.#handleOnAccountRemoved(account),\n );\n }\n\n /**\n * Starts the polling process.\n */\n start(): void {\n this.#tracker.start();\n }\n\n /**\n * Stops the polling process.\n */\n stop(): void {\n this.#tracker.stop();\n }\n\n /**\n * Tracks an account to get its balances.\n *\n * @param account - The account to track.\n */\n #trackAccount(account: InternalAccount): void {\n if (!this.#isNonEvmAccount(account)) {\n // Nothing to do here for EVM accounts\n return;\n }\n\n const updateTime =\n // @ts-expect-error - For the moment we are only tracking non-EVM accounts and this is\n // checked with the method `#isNonEvmAccount`. We can ignore this error since\n // eip155:eoa and eip155:erc4337 account type balances are not tracked here.\n BALANCE_UPDATE_INTERVALS[this.#getAccount(account.id).type];\n this.#tracker.track(account.id, updateTime);\n }\n\n /**\n * Lists the multichain accounts coming from the `AccountsController`.\n *\n * @returns A list of multichain accounts.\n */\n #listMultichainAccounts(): InternalAccount[] {\n return this.messagingSystem.call(\n 'AccountsController:listMultichainAccounts',\n );\n }\n\n /**\n * Lists the accounts that we should get balances for.\n *\n * Currently, we only get balances for non-EVM accounts.\n *\n * @returns A list of accounts that we should get balances for.\n */\n #listAccounts(): InternalAccount[] {\n const accounts = this.#listMultichainAccounts();\n\n return accounts.filter((account) => this.#isNonEvmAccount(account));\n }\n\n /**\n * Get a non-EVM account from its ID.\n *\n * @param accountId - The account ID.\n * @returns The non-EVM account.\n */\n #getAccount(accountId: string): InternalAccount {\n const account: InternalAccount | undefined =\n this.#listMultichainAccounts().find(\n (multichainAccount) => multichainAccount.id === accountId,\n );\n\n if (!account) {\n throw new Error(`Unknown account: ${accountId}`);\n }\n if (!this.#isNonEvmAccount(account)) {\n throw new Error(`Account is not a non-EVM account: ${accountId}`);\n }\n return account;\n }\n\n /**\n * Updates the balances of one account. This method doesn't return\n * anything, but it updates the state of the controller.\n *\n * @param accountId - The account ID.\n */\n async #updateBalance(accountId: string) {\n const account = this.#getAccount(accountId);\n const partialState: MultichainBalancesControllerState = { balances: {} };\n\n const scope = getScopeForAddress(account);\n const assetsList = this.#networkAssetsMap[scope];\n\n if (account.metadata.snap) {\n partialState.balances[account.id] = await this.#getBalances(\n account.id,\n account.metadata.snap.id,\n assetsList,\n );\n }\n\n this.update((state: Draft<MultichainBalancesControllerState>) => ({\n ...state,\n balances: {\n ...state.balances,\n ...partialState.balances,\n },\n }));\n }\n\n /**\n * Updates the balances of one account. This method doesn't return\n * anything, but it updates the state of the controller.\n *\n * @param accountId - The account ID.\n */\n async updateBalance(accountId: string) {\n // NOTE: No need to track the account here, since we start tracking those when\n // the \"AccountsController:accountAdded\" is fired.\n await this.#tracker.updateBalance(accountId);\n }\n\n /**\n * Updates the balances of all supported accounts. This method doesn't return\n * anything, but it updates the state of the controller.\n */\n async updateBalances() {\n await this.#tracker.updateBalances();\n }\n\n /**\n * Checks for non-EVM accounts.\n *\n * @param account - The new account to be checked.\n * @returns True if the account is a non-EVM account, false otherwise.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) &&\n // Non-EVM accounts are backed by a Snap for now\n account.metadata.snap !== undefined\n );\n }\n\n /**\n * Handles changes when a new account has been added.\n *\n * @param account - The new account being added.\n */\n async #handleOnAccountAdded(account: InternalAccount) {\n this.#trackAccount(account);\n // NOTE: Unfortunately, we cannot update the balance right away here, because\n // messenger's events are running synchronously and fetching the balance is\n // asynchronous.\n // Updating the balance here would resume at some point but the event emitter\n // will not `await` this (so we have no real control \"when\" the balance will\n // really be updated), see:\n // - https://github.com/MetaMask/core/blob/v213.0.0/packages/accounts-controller/src/AccountsController.ts#L1036-L1039\n }\n\n /**\n * Handles changes when a new account has been removed.\n *\n * @param accountId - The account ID being removed.\n */\n async #handleOnAccountRemoved(accountId: string) {\n if (this.#tracker.isTracked(accountId)) {\n this.#tracker.untrack(accountId);\n }\n\n if (accountId in this.state.balances) {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n delete state.balances[accountId];\n return state;\n });\n }\n }\n\n /**\n * Get the balances for an account.\n *\n * @param accountId - ID of the account to get balances for.\n * @param snapId - ID of the Snap which manages the account.\n * @param assetTypes - Array of asset types to get balances for.\n * @returns A map of asset types to balances.\n */\n async #getBalances(\n accountId: string,\n snapId: string,\n assetTypes: CaipAssetType[],\n ): Promise<Record<CaipAssetType, Balance>> {\n return await this.#getClient(snapId).getAccountBalances(\n accountId,\n assetTypes,\n );\n }\n\n /**\n * Gets a `KeyringClient` for a Snap.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getClient(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) =>\n (await this.messagingSystem.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n })) as Promise<Json>,\n });\n }\n}\n"]}