@metamask/assets-controllers 47.0.0 → 48.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.
Files changed (162) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/dist/AccountTrackerController.cjs.map +1 -1
  3. package/dist/AccountTrackerController.d.cts +8 -3
  4. package/dist/AccountTrackerController.d.cts.map +1 -1
  5. package/dist/AccountTrackerController.d.mts +8 -3
  6. package/dist/AccountTrackerController.d.mts.map +1 -1
  7. package/dist/AccountTrackerController.mjs.map +1 -1
  8. package/dist/AssetsContractController.cjs +3 -3
  9. package/dist/AssetsContractController.cjs.map +1 -1
  10. package/dist/AssetsContractController.d.cts +3 -3
  11. package/dist/AssetsContractController.d.cts.map +1 -1
  12. package/dist/AssetsContractController.d.mts +3 -3
  13. package/dist/AssetsContractController.d.mts.map +1 -1
  14. package/dist/AssetsContractController.mjs +3 -3
  15. package/dist/AssetsContractController.mjs.map +1 -1
  16. package/dist/CurrencyRateController.cjs.map +1 -1
  17. package/dist/CurrencyRateController.d.cts +2 -2
  18. package/dist/CurrencyRateController.d.cts.map +1 -1
  19. package/dist/CurrencyRateController.d.mts +2 -2
  20. package/dist/CurrencyRateController.d.mts.map +1 -1
  21. package/dist/CurrencyRateController.mjs.map +1 -1
  22. package/dist/MultichainAssetsController/MultichainAssetsController.cjs +324 -0
  23. package/dist/MultichainAssetsController/MultichainAssetsController.cjs.map +1 -0
  24. package/dist/MultichainAssetsController/MultichainAssetsController.d.cts +66 -0
  25. package/dist/MultichainAssetsController/MultichainAssetsController.d.cts.map +1 -0
  26. package/dist/MultichainAssetsController/MultichainAssetsController.d.mts +66 -0
  27. package/dist/MultichainAssetsController/MultichainAssetsController.d.mts.map +1 -0
  28. package/dist/MultichainAssetsController/MultichainAssetsController.mjs +319 -0
  29. package/dist/MultichainAssetsController/MultichainAssetsController.mjs.map +1 -0
  30. package/dist/MultichainAssetsController/index.cjs +7 -0
  31. package/dist/MultichainAssetsController/index.cjs.map +1 -0
  32. package/dist/MultichainAssetsController/index.d.cts +3 -0
  33. package/dist/MultichainAssetsController/index.d.cts.map +1 -0
  34. package/dist/MultichainAssetsController/index.d.mts +3 -0
  35. package/dist/MultichainAssetsController/index.d.mts.map +1 -0
  36. package/dist/MultichainAssetsController/index.mjs +2 -0
  37. package/dist/MultichainAssetsController/index.mjs.map +1 -0
  38. package/dist/MultichainAssetsController/utils.cjs +26 -0
  39. package/dist/MultichainAssetsController/utils.cjs.map +1 -0
  40. package/dist/MultichainAssetsController/utils.d.cts +13 -0
  41. package/dist/MultichainAssetsController/utils.d.cts.map +1 -0
  42. package/dist/MultichainAssetsController/utils.d.mts +13 -0
  43. package/dist/MultichainAssetsController/utils.d.mts.map +1 -0
  44. package/dist/MultichainAssetsController/utils.mjs +22 -0
  45. package/dist/MultichainAssetsController/utils.mjs.map +1 -0
  46. package/dist/MultichainBalancesController/MultichainBalancesController.cjs +30 -65
  47. package/dist/MultichainBalancesController/MultichainBalancesController.cjs.map +1 -1
  48. package/dist/MultichainBalancesController/MultichainBalancesController.d.cts +5 -25
  49. package/dist/MultichainBalancesController/MultichainBalancesController.d.cts.map +1 -1
  50. package/dist/MultichainBalancesController/MultichainBalancesController.d.mts +5 -25
  51. package/dist/MultichainBalancesController/MultichainBalancesController.d.mts.map +1 -1
  52. package/dist/MultichainBalancesController/MultichainBalancesController.mjs +32 -67
  53. package/dist/MultichainBalancesController/MultichainBalancesController.mjs.map +1 -1
  54. package/dist/MultichainBalancesController/constants.cjs +1 -10
  55. package/dist/MultichainBalancesController/constants.cjs.map +1 -1
  56. package/dist/MultichainBalancesController/constants.d.cts +0 -4
  57. package/dist/MultichainBalancesController/constants.d.cts.map +1 -1
  58. package/dist/MultichainBalancesController/constants.d.mts +0 -4
  59. package/dist/MultichainBalancesController/constants.d.mts.map +1 -1
  60. package/dist/MultichainBalancesController/constants.mjs +0 -9
  61. package/dist/MultichainBalancesController/constants.mjs.map +1 -1
  62. package/dist/MultichainBalancesController/index.cjs +1 -4
  63. package/dist/MultichainBalancesController/index.cjs.map +1 -1
  64. package/dist/MultichainBalancesController/index.d.cts +2 -3
  65. package/dist/MultichainBalancesController/index.d.cts.map +1 -1
  66. package/dist/MultichainBalancesController/index.d.mts +2 -3
  67. package/dist/MultichainBalancesController/index.d.mts.map +1 -1
  68. package/dist/MultichainBalancesController/index.mjs +1 -2
  69. package/dist/MultichainBalancesController/index.mjs.map +1 -1
  70. package/dist/MultichainBalancesController/utils.cjs +1 -14
  71. package/dist/MultichainBalancesController/utils.cjs.map +1 -1
  72. package/dist/MultichainBalancesController/utils.d.cts +0 -7
  73. package/dist/MultichainBalancesController/utils.d.cts.map +1 -1
  74. package/dist/MultichainBalancesController/utils.d.mts +0 -7
  75. package/dist/MultichainBalancesController/utils.d.mts.map +1 -1
  76. package/dist/MultichainBalancesController/utils.mjs +1 -13
  77. package/dist/MultichainBalancesController/utils.mjs.map +1 -1
  78. package/dist/NftController.cjs +1 -1
  79. package/dist/NftController.cjs.map +1 -1
  80. package/dist/NftController.d.cts +3 -3
  81. package/dist/NftController.d.cts.map +1 -1
  82. package/dist/NftController.d.mts +3 -3
  83. package/dist/NftController.d.mts.map +1 -1
  84. package/dist/NftController.mjs +1 -1
  85. package/dist/NftController.mjs.map +1 -1
  86. package/dist/NftDetectionController.cjs.map +1 -1
  87. package/dist/NftDetectionController.d.cts +2 -2
  88. package/dist/NftDetectionController.d.cts.map +1 -1
  89. package/dist/NftDetectionController.d.mts +2 -2
  90. package/dist/NftDetectionController.d.mts.map +1 -1
  91. package/dist/NftDetectionController.mjs.map +1 -1
  92. package/dist/RatesController/types.cjs.map +1 -1
  93. package/dist/RatesController/types.d.cts +2 -2
  94. package/dist/RatesController/types.d.cts.map +1 -1
  95. package/dist/RatesController/types.d.mts +2 -2
  96. package/dist/RatesController/types.d.mts.map +1 -1
  97. package/dist/RatesController/types.mjs.map +1 -1
  98. package/dist/TokenBalancesController.cjs.map +1 -1
  99. package/dist/TokenBalancesController.d.cts +6 -4
  100. package/dist/TokenBalancesController.d.cts.map +1 -1
  101. package/dist/TokenBalancesController.d.mts +6 -4
  102. package/dist/TokenBalancesController.d.mts.map +1 -1
  103. package/dist/TokenBalancesController.mjs.map +1 -1
  104. package/dist/TokenDetectionController.cjs +1 -1
  105. package/dist/TokenDetectionController.cjs.map +1 -1
  106. package/dist/TokenDetectionController.d.cts +2 -2
  107. package/dist/TokenDetectionController.d.cts.map +1 -1
  108. package/dist/TokenDetectionController.d.mts +2 -2
  109. package/dist/TokenDetectionController.d.mts.map +1 -1
  110. package/dist/TokenDetectionController.mjs +1 -1
  111. package/dist/TokenDetectionController.mjs.map +1 -1
  112. package/dist/TokenListController.cjs +1 -1
  113. package/dist/TokenListController.cjs.map +1 -1
  114. package/dist/TokenListController.d.cts +3 -3
  115. package/dist/TokenListController.d.cts.map +1 -1
  116. package/dist/TokenListController.d.mts +3 -3
  117. package/dist/TokenListController.d.mts.map +1 -1
  118. package/dist/TokenListController.mjs +1 -1
  119. package/dist/TokenListController.mjs.map +1 -1
  120. package/dist/TokenRatesController.cjs +1 -1
  121. package/dist/TokenRatesController.cjs.map +1 -1
  122. package/dist/TokenRatesController.d.cts +3 -3
  123. package/dist/TokenRatesController.d.cts.map +1 -1
  124. package/dist/TokenRatesController.d.mts +3 -3
  125. package/dist/TokenRatesController.d.mts.map +1 -1
  126. package/dist/TokenRatesController.mjs +1 -1
  127. package/dist/TokenRatesController.mjs.map +1 -1
  128. package/dist/TokensController.cjs +9 -6
  129. package/dist/TokensController.cjs.map +1 -1
  130. package/dist/TokensController.d.cts +3 -3
  131. package/dist/TokensController.d.cts.map +1 -1
  132. package/dist/TokensController.d.mts +3 -3
  133. package/dist/TokensController.d.mts.map +1 -1
  134. package/dist/TokensController.mjs +9 -6
  135. package/dist/TokensController.mjs.map +1 -1
  136. package/dist/index.cjs +4 -3
  137. package/dist/index.cjs.map +1 -1
  138. package/dist/index.d.cts +4 -2
  139. package/dist/index.d.cts.map +1 -1
  140. package/dist/index.d.mts +4 -2
  141. package/dist/index.d.mts.map +1 -1
  142. package/dist/index.mjs +3 -2
  143. package/dist/index.mjs.map +1 -1
  144. package/dist/token-prices-service/codefi-v2.d.cts +1 -1
  145. package/dist/token-prices-service/codefi-v2.d.mts +1 -1
  146. package/package.json +14 -11
  147. package/dist/MultichainBalancesController/BalancesTracker.cjs +0 -122
  148. package/dist/MultichainBalancesController/BalancesTracker.cjs.map +0 -1
  149. package/dist/MultichainBalancesController/BalancesTracker.d.cts +0 -54
  150. package/dist/MultichainBalancesController/BalancesTracker.d.cts.map +0 -1
  151. package/dist/MultichainBalancesController/BalancesTracker.d.mts +0 -54
  152. package/dist/MultichainBalancesController/BalancesTracker.d.mts.map +0 -1
  153. package/dist/MultichainBalancesController/BalancesTracker.mjs +0 -118
  154. package/dist/MultichainBalancesController/BalancesTracker.mjs.map +0 -1
  155. package/dist/MultichainBalancesController/Poller.cjs +0 -45
  156. package/dist/MultichainBalancesController/Poller.cjs.map +0 -1
  157. package/dist/MultichainBalancesController/Poller.d.cts +0 -7
  158. package/dist/MultichainBalancesController/Poller.d.cts.map +0 -1
  159. package/dist/MultichainBalancesController/Poller.d.mts +0 -7
  160. package/dist/MultichainBalancesController/Poller.d.mts.map +0 -1
  161. package/dist/MultichainBalancesController/Poller.mjs +0 -41
  162. package/dist/MultichainBalancesController/Poller.mjs.map +0 -1
@@ -4,13 +4,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
4
4
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
5
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
6
  };
7
- var __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_listMultichainAccounts, _MultichainBalancesController_listAccounts, _MultichainBalancesController_getAccount, _MultichainBalancesController_updateBalance, _MultichainBalancesController_isNonEvmAccount, _MultichainBalancesController_handleOnAccountAdded, _MultichainBalancesController_handleOnAccountRemoved, _MultichainBalancesController_getBalances, _MultichainBalancesController_getClient;
7
+ var _MultichainBalancesController_instances, _MultichainBalancesController_listMultichainAccounts, _MultichainBalancesController_listAccounts, _MultichainBalancesController_getAccount, _MultichainBalancesController_isNonEvmAccount, _MultichainBalancesController_handleOnAccountAdded, _MultichainBalancesController_handleOnAccountBalancesUpdated, _MultichainBalancesController_handleOnAccountRemoved, _MultichainBalancesController_getBalances, _MultichainBalancesController_getClient;
14
8
  Object.defineProperty(exports, "__esModule", { value: true });
15
9
  exports.MultichainBalancesController = exports.getDefaultMultichainBalancesControllerState = void 0;
16
10
  const base_controller_1 = require("@metamask/base-controller");
@@ -61,28 +55,15 @@ class MultichainBalancesController extends base_controller_1.BaseController {
61
55
  },
62
56
  });
63
57
  _MultichainBalancesController_instances.add(this);
64
- _MultichainBalancesController_tracker.set(this, void 0);
65
- __classPrivateFieldSet(this, _MultichainBalancesController_tracker, new _1.BalancesTracker(async (accountId) => await __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_updateBalance).call(this, accountId)), "f");
66
- // Register all non-EVM accounts into the tracker
58
+ // Fetch initial balances for all non-EVM accounts
67
59
  for (const account of __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_listAccounts).call(this)) {
68
- if (__classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_isNonEvmAccount).call(this, account)) {
69
- __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").track(account.id, (0, utils_1.getBlockTimeForAccount)(account.type));
70
- }
60
+ this.updateBalance(account.id).catch((error) => {
61
+ console.error(`Failed to fetch initial balance for account ${account.id}:`, error);
62
+ });
71
63
  }
72
64
  this.messagingSystem.subscribe('AccountsController:accountAdded', (account) => __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_handleOnAccountAdded).call(this, account));
73
65
  this.messagingSystem.subscribe('AccountsController:accountRemoved', (account) => __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_handleOnAccountRemoved).call(this, account));
74
- }
75
- /**
76
- * Starts the polling process.
77
- */
78
- start() {
79
- __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").start();
80
- }
81
- /**
82
- * Stops the polling process.
83
- */
84
- stop() {
85
- __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").stop();
66
+ this.messagingSystem.subscribe('AccountsController:accountBalancesUpdated', (balanceUpdate) => __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_handleOnAccountBalancesUpdated).call(this, balanceUpdate));
86
67
  }
87
68
  /**
88
69
  * Updates the balances of one account. This method doesn't return
@@ -91,20 +72,24 @@ class MultichainBalancesController extends base_controller_1.BaseController {
91
72
  * @param accountId - The account ID.
92
73
  */
93
74
  async updateBalance(accountId) {
94
- // NOTE: No need to track the account here, since we start tracking those when
95
- // the "AccountsController:accountAdded" is fired.
96
- await __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").updateBalance(accountId);
97
- }
98
- /**
99
- * Updates the balances of all supported accounts. This method doesn't return
100
- * anything, but it updates the state of the controller.
101
- */
102
- async updateBalances() {
103
- await __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").updateBalances();
75
+ try {
76
+ const account = __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getAccount).call(this, accountId);
77
+ if (account.metadata.snap) {
78
+ const scope = (0, utils_1.getScopeForAccount)(account);
79
+ const assetTypes = _1.NETWORK_ASSETS_MAP[scope];
80
+ const accountBalance = await __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getBalances).call(this, account.id, account.metadata.snap.id, assetTypes);
81
+ this.update((state) => {
82
+ state.balances[accountId] = accountBalance;
83
+ });
84
+ }
85
+ }
86
+ catch (error) {
87
+ console.error(`Failed to fetch balances for account ${accountId}:`, error);
88
+ }
104
89
  }
105
90
  }
106
91
  exports.MultichainBalancesController = MultichainBalancesController;
107
- _MultichainBalancesController_tracker = new WeakMap(), _MultichainBalancesController_instances = new WeakSet(), _MultichainBalancesController_listMultichainAccounts = function _MultichainBalancesController_listMultichainAccounts() {
92
+ _MultichainBalancesController_instances = new WeakSet(), _MultichainBalancesController_listMultichainAccounts = function _MultichainBalancesController_listMultichainAccounts() {
108
93
  return this.messagingSystem.call('AccountsController:listMultichainAccounts');
109
94
  }, _MultichainBalancesController_listAccounts = function _MultichainBalancesController_listAccounts() {
110
95
  const accounts = __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_listMultichainAccounts).call(this);
@@ -115,23 +100,6 @@ _MultichainBalancesController_tracker = new WeakMap(), _MultichainBalancesContro
115
100
  throw new Error(`Unknown account: ${accountId}`);
116
101
  }
117
102
  return account;
118
- }, _MultichainBalancesController_updateBalance =
119
- /**
120
- * Updates the balances of one account. This method doesn't return
121
- * anything, but it updates the state of the controller.
122
- *
123
- * @param accountId - The account ID.
124
- */
125
- async function _MultichainBalancesController_updateBalance(accountId) {
126
- const account = __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getAccount).call(this, accountId);
127
- if (account.metadata.snap) {
128
- const scope = (0, utils_1.getScopeForAccount)(account);
129
- const assetTypes = _1.NETWORK_ASSETS_MAP[scope];
130
- const accountBalance = await __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getBalances).call(this, account.id, account.metadata.snap.id, assetTypes);
131
- this.update((state) => {
132
- state.balances[accountId] = accountBalance;
133
- });
134
- }
135
103
  }, _MultichainBalancesController_isNonEvmAccount = function _MultichainBalancesController_isNonEvmAccount(account) {
136
104
  return (!(0, keyring_api_1.isEvmAccountType)(account.type) &&
137
105
  // Non-EVM accounts are backed by a Snap for now
@@ -144,17 +112,17 @@ async function _MultichainBalancesController_updateBalance(accountId) {
144
112
  */
145
113
  async function _MultichainBalancesController_handleOnAccountAdded(account) {
146
114
  if (!__classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_isNonEvmAccount).call(this, account)) {
147
- // Nothing to do here for EVM accounts
148
115
  return;
149
116
  }
150
- __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").track(account.id, (0, utils_1.getBlockTimeForAccount)(account.type));
151
- // NOTE: Unfortunately, we cannot update the balance right away here, because
152
- // messenger's events are running synchronously and fetching the balance is
153
- // asynchronous.
154
- // Updating the balance here would resume at some point but the event emitter
155
- // will not `await` this (so we have no real control "when" the balance will
156
- // really be updated), see:
157
- // - https://github.com/MetaMask/core/blob/v213.0.0/packages/accounts-controller/src/AccountsController.ts#L1036-L1039
117
+ await this.updateBalance(account.id);
118
+ }, _MultichainBalancesController_handleOnAccountBalancesUpdated = function _MultichainBalancesController_handleOnAccountBalancesUpdated(balanceUpdate) {
119
+ this.update((state) => {
120
+ Object.entries(balanceUpdate.balances).forEach(([accountId, assetBalances]) => {
121
+ if (accountId in state.balances) {
122
+ Object.assign(state.balances[accountId], assetBalances);
123
+ }
124
+ });
125
+ });
158
126
  }, _MultichainBalancesController_handleOnAccountRemoved =
159
127
  /**
160
128
  * Handles changes when a new account has been removed.
@@ -162,9 +130,6 @@ async function _MultichainBalancesController_handleOnAccountAdded(account) {
162
130
  * @param accountId - The account ID being removed.
163
131
  */
164
132
  async function _MultichainBalancesController_handleOnAccountRemoved(accountId) {
165
- if (__classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").isTracked(accountId)) {
166
- __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").untrack(accountId);
167
- }
168
133
  if (accountId in this.state.balances) {
169
134
  this.update((state) => {
170
135
  delete state.balances[accountId];
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainBalancesController.cjs","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAKA,+DAKmC;AACnC,uDAAyD;AAGzD,uEAA8D;AAG9D,uDAAoD;AAIpD,kCAAwD;AACxD,uCAAqE;AAErE,MAAM,cAAc,GAAG,8BAA8B,CAAC;AAgBtD;;;;;;;GAOG;AACH,SAAgB,2CAA2C;IACzD,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAC1B,CAAC;AAFD,kGAEC;AAmED;;;;;;GAMG;AACH,MAAM,0BAA0B,GAAG;IACjC,QAAQ,EAAE;QACR,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,KAAK;KACjB;CACF,CAAC;AAEF;;;GAGG;AACH,MAAa,4BAA6B,SAAQ,gCAIjD;IAGC,YAAY,EACV,SAAS,EACT,KAAK,GAAG,EAAE,GAIX;QACC,KAAK,CAAC;YACJ,SAAS;YACT,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,0BAA0B;YACpC,KAAK,EAAE;gBACL,GAAG,2CAA2C,EAAE;gBAChD,GAAG,KAAK;aACT;SACF,CAAC,CAAC;;QAjBL,wDAA0B;QAmBxB,uBAAA,IAAI,yCAAY,IAAI,kBAAe,CACjC,KAAK,EAAE,SAAiB,EAAE,EAAE,CAAC,MAAM,uBAAA,IAAI,4FAAe,MAAnB,IAAI,EAAgB,SAAS,CAAC,CAClE,MAAA,CAAC;QAEF,iDAAiD;QACjD,KAAK,MAAM,OAAO,IAAI,uBAAA,IAAI,2FAAc,MAAlB,IAAI,CAAgB,EAAE;YAC1C,IAAI,uBAAA,IAAI,8FAAiB,MAArB,IAAI,EAAkB,OAAO,CAAC,EAAE;gBAClC,uBAAA,IAAI,6CAAS,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,IAAA,8BAAsB,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;aACvE;SACF;QAED,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,iCAAiC,EACjC,CAAC,OAAO,EAAE,EAAE,CAAC,uBAAA,IAAI,mGAAsB,MAA1B,IAAI,EAAuB,OAAO,CAAC,CACjD,CAAC;QACF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,mCAAmC,EACnC,CAAC,OAAO,EAAE,EAAE,CAAC,uBAAA,IAAI,qGAAwB,MAA5B,IAAI,EAAyB,OAAO,CAAC,CACnD,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK;QACH,uBAAA,IAAI,6CAAS,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,uBAAA,IAAI,6CAAS,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,aAAa,CAAC,SAAiB;QACnC,8EAA8E;QAC9E,kDAAkD;QAClD,MAAM,uBAAA,IAAI,6CAAS,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,cAAc;QAClB,MAAM,uBAAA,IAAI,6CAAS,CAAC,cAAc,EAAE,CAAC;IACvC,CAAC;CA4JF;AAzOD,oEAyOC;;IApJG,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAC9B,2CAA2C,CAC5C,CAAC;AACJ,CAAC;IAQC,MAAM,QAAQ,GAAG,uBAAA,IAAI,qGAAwB,MAA5B,IAAI,CAA0B,CAAC;IAEhD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,uBAAA,IAAI,8FAAiB,MAArB,IAAI,EAAkB,OAAO,CAAC,CAAC,CAAC;AACtE,CAAC,+FAQW,SAAiB;IAC3B,MAAM,OAAO,GAAgC,uBAAA,IAAI,2FAAc,MAAlB,IAAI,CAAgB,CAAC,IAAI,CACpE,CAAC,iBAAiB,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,KAAK,SAAS,CAC1D,CAAC;IAEF,IAAI,CAAC,OAAO,EAAE;QACZ,MAAM,IAAI,KAAK,CAAC,oBAAoB,SAAS,EAAE,CAAC,CAAC;KAClD;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AAEH,KAAK,sDAAgB,SAAiB;IACpC,MAAM,OAAO,GAAG,uBAAA,IAAI,yFAAY,MAAhB,IAAI,EAAa,SAAS,CAAC,CAAC;IAE5C,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE;QACzB,MAAM,KAAK,GAAG,IAAA,0BAAkB,EAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,UAAU,GAAG,qBAAkB,CAAC,KAAK,CAAC,CAAC;QAE7C,MAAM,cAAc,GAAG,MAAM,uBAAA,IAAI,0FAAa,MAAjB,IAAI,EAC/B,OAAO,CAAC,EAAE,EACV,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,EACxB,UAAU,CACX,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,CAAC,KAA+C,EAAE,EAAE;YAC9D,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,cAAc,CAAC;QAC7C,CAAC,CAAC,CAAC;KACJ;AACH,CAAC,yGAQgB,OAAwB;IACvC,OAAO,CACL,CAAC,IAAA,8BAAgB,EAAC,OAAO,CAAC,IAAI,CAAC;QAC/B,gDAAgD;QAChD,OAAO,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS,CACpC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,KAAK,6DAAuB,OAAwB;IAClD,IAAI,CAAC,uBAAA,IAAI,8FAAiB,MAArB,IAAI,EAAkB,OAAO,CAAC,EAAE;QACnC,sCAAsC;QACtC,OAAO;KACR;IAED,uBAAA,IAAI,6CAAS,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,IAAA,8BAAsB,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACtE,6EAA6E;IAC7E,2EAA2E;IAC3E,gBAAgB;IAChB,6EAA6E;IAC7E,4EAA4E;IAC5E,2BAA2B;IAC3B,sHAAsH;AACxH,CAAC;AAED;;;;GAIG;AACH,KAAK,+DAAyB,SAAiB;IAC7C,IAAI,uBAAA,IAAI,6CAAS,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;QACtC,uBAAA,IAAI,6CAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;KAClC;IAED,IAAI,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE;QACpC,IAAI,CAAC,MAAM,CAAC,CAAC,KAA+C,EAAE,EAAE;YAC9D,OAAO,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;KACJ;AACH,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,oDACH,SAAiB,EACjB,MAAc,EACd,UAA2B;IAE3B,OAAO,MAAM,uBAAA,IAAI,wFAAW,MAAf,IAAI,EAAY,MAAM,CAAC,CAAC,kBAAkB,CACrD,SAAS,EACT,UAAU,CACX,CAAC;AACJ,CAAC,6FAQU,MAAc;IACvB,OAAO,IAAI,mCAAa,CAAC;QACvB,IAAI,EAAE,KAAK,EAAE,OAAuB,EAAE,EAAE,CACtC,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,8BAA8B,EAAE;YAC/D,MAAM,EAAE,MAAgB;YACxB,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,yBAAW,CAAC,gBAAgB;YACrC,OAAO;SACR,CAAC,CAAkB;KACvB,CAAC,CAAC;AACL,CAAC","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 { isEvmAccountType } from '@metamask/keyring-api';\nimport type { Balance, CaipAssetType } from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\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 { BalancesTracker, NETWORK_ASSETS_MAP } from '.';\nimport { getScopeForAccount, getBlockTimeForAccount } 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 * Constructs the default {@link MultichainBalancesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainBalancesController} state.\n */\nexport function getDefaultMultichainBalancesControllerState(): MultichainBalancesControllerState {\n return { balances: {} };\n}\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.\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 */\ntype AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype 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 balancesControllerMetadata = {\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 #tracker: BalancesTracker;\n\n constructor({\n messenger,\n state = {},\n }: {\n messenger: MultichainBalancesControllerMessenger;\n state?: Partial<MultichainBalancesControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: balancesControllerMetadata,\n state: {\n ...getDefaultMultichainBalancesControllerState(),\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 if (this.#isNonEvmAccount(account)) {\n this.#tracker.track(account.id, getBlockTimeForAccount(account.type));\n }\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 * 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): Promise<void> {\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(): Promise<void> {\n await this.#tracker.updateBalances();\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 * @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 = this.#listAccounts().find(\n (multichainAccount) => multichainAccount.id === accountId,\n );\n\n if (!account) {\n throw new Error(`Unknown account: ${accountId}`);\n }\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\n async #updateBalance(accountId: string) {\n const account = this.#getAccount(accountId);\n\n if (account.metadata.snap) {\n const scope = getScopeForAccount(account);\n const assetTypes = NETWORK_ASSETS_MAP[scope];\n\n const accountBalance = await this.#getBalances(\n account.id,\n account.metadata.snap.id,\n assetTypes,\n );\n\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n state.balances[accountId] = accountBalance;\n });\n }\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): Promise<void> {\n if (!this.#isNonEvmAccount(account)) {\n // Nothing to do here for EVM accounts\n return;\n }\n\n this.#tracker.track(account.id, getBlockTimeForAccount(account.type));\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): Promise<void> {\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 });\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"]}
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 AccountsControllerAccountBalancesUpdatesEvent,\n} from '@metamask/accounts-controller';\nimport {\n BaseController,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n Balance,\n CaipAssetType,\n AccountBalancesUpdatedEventPayload,\n} from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\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 { NETWORK_ASSETS_MAP } from '.';\nimport { getScopeForAccount } 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 * Constructs the default {@link MultichainBalancesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainBalancesController} state.\n */\nexport function getDefaultMultichainBalancesControllerState(): MultichainBalancesControllerState {\n return { balances: {} };\n}\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 * 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\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 */\ntype AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent\n | AccountsControllerAccountBalancesUpdatesEvent;\n/**\n * Messenger type for the MultichainBalancesController.\n */\nexport type MultichainBalancesControllerMessenger = RestrictedMessenger<\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 balancesControllerMetadata = {\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 constructor({\n messenger,\n state = {},\n }: {\n messenger: MultichainBalancesControllerMessenger;\n state?: Partial<MultichainBalancesControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: balancesControllerMetadata,\n state: {\n ...getDefaultMultichainBalancesControllerState(),\n ...state,\n },\n });\n\n // Fetch initial balances for all non-EVM accounts\n for (const account of this.#listAccounts()) {\n this.updateBalance(account.id).catch((error) => {\n console.error(\n `Failed to fetch initial balance for account ${account.id}:`,\n error,\n );\n });\n }\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountAdded',\n (account: InternalAccount) => this.#handleOnAccountAdded(account),\n );\n this.messagingSystem.subscribe(\n 'AccountsController:accountRemoved',\n (account: string) => this.#handleOnAccountRemoved(account),\n );\n this.messagingSystem.subscribe(\n 'AccountsController:accountBalancesUpdated',\n (balanceUpdate: AccountBalancesUpdatedEventPayload) =>\n this.#handleOnAccountBalancesUpdated(balanceUpdate),\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): Promise<void> {\n try {\n const account = this.#getAccount(accountId);\n\n if (account.metadata.snap) {\n const scope = getScopeForAccount(account);\n const assetTypes = NETWORK_ASSETS_MAP[scope];\n\n const accountBalance = await this.#getBalances(\n account.id,\n account.metadata.snap.id,\n assetTypes,\n );\n\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n state.balances[accountId] = accountBalance;\n });\n }\n } catch (error) {\n console.error(\n `Failed to fetch balances for account ${accountId}:`,\n error,\n );\n }\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 * @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 = this.#listAccounts().find(\n (multichainAccount) => multichainAccount.id === accountId,\n );\n\n if (!account) {\n throw new Error(`Unknown account: ${accountId}`);\n }\n\n return account;\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): Promise<void> {\n if (!this.#isNonEvmAccount(account)) {\n return;\n }\n\n await this.updateBalance(account.id);\n }\n\n /**\n * Handles balance updates received from the AccountsController.\n *\n * @param balanceUpdate - The balance update event containing new balances.\n */\n #handleOnAccountBalancesUpdated(\n balanceUpdate: AccountBalancesUpdatedEventPayload,\n ): void {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n Object.entries(balanceUpdate.balances).forEach(\n ([accountId, assetBalances]) => {\n if (accountId in state.balances) {\n Object.assign(state.balances[accountId], assetBalances);\n }\n },\n );\n });\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): Promise<void> {\n if (accountId in this.state.balances) {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n delete state.balances[accountId];\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"]}
@@ -1,5 +1,5 @@
1
- import type { AccountsControllerAccountAddedEvent, AccountsControllerAccountRemovedEvent, AccountsControllerListMultichainAccountsAction } from "@metamask/accounts-controller";
2
- import { BaseController, type ControllerGetStateAction, type ControllerStateChangeEvent, type RestrictedControllerMessenger } from "@metamask/base-controller";
1
+ import type { AccountsControllerAccountAddedEvent, AccountsControllerAccountRemovedEvent, AccountsControllerListMultichainAccountsAction, AccountsControllerAccountBalancesUpdatesEvent } from "@metamask/accounts-controller";
2
+ import { BaseController, type ControllerGetStateAction, type ControllerStateChangeEvent, type RestrictedMessenger } from "@metamask/base-controller";
3
3
  import type { HandleSnapRequest } from "@metamask/snaps-controllers";
4
4
  declare const controllerName = "MultichainBalancesController";
5
5
  /**
@@ -28,13 +28,6 @@ export declare function getDefaultMultichainBalancesControllerState(): Multichai
28
28
  * Returns the state of the {@link MultichainBalancesController}.
29
29
  */
30
30
  export type MultichainBalancesControllerGetStateAction = ControllerGetStateAction<typeof controllerName, MultichainBalancesControllerState>;
31
- /**
32
- * Updates the balances of all supported accounts.
33
- */
34
- export type MultichainBalancesControllerUpdateBalancesAction = {
35
- type: `${typeof controllerName}:updateBalances`;
36
- handler: MultichainBalancesController['updateBalances'];
37
- };
38
31
  /**
39
32
  * Event emitted when the state of the {@link MultichainBalancesController} changes.
40
33
  */
@@ -42,7 +35,7 @@ export type MultichainBalancesControllerStateChange = ControllerStateChangeEvent
42
35
  /**
43
36
  * Actions exposed by the {@link MultichainBalancesController}.
44
37
  */
45
- export type MultichainBalancesControllerActions = MultichainBalancesControllerGetStateAction | MultichainBalancesControllerUpdateBalancesAction;
38
+ export type MultichainBalancesControllerActions = MultichainBalancesControllerGetStateAction;
46
39
  /**
47
40
  * Events emitted by {@link MultichainBalancesController}.
48
41
  */
@@ -54,11 +47,11 @@ type AllowedActions = HandleSnapRequest | AccountsControllerListMultichainAccoun
54
47
  /**
55
48
  * Events that this controller is allowed to subscribe.
56
49
  */
57
- type AllowedEvents = AccountsControllerAccountAddedEvent | AccountsControllerAccountRemovedEvent;
50
+ type AllowedEvents = AccountsControllerAccountAddedEvent | AccountsControllerAccountRemovedEvent | AccountsControllerAccountBalancesUpdatesEvent;
58
51
  /**
59
52
  * Messenger type for the MultichainBalancesController.
60
53
  */
61
- export type MultichainBalancesControllerMessenger = RestrictedControllerMessenger<typeof controllerName, MultichainBalancesControllerActions | AllowedActions, MultichainBalancesControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
54
+ export type MultichainBalancesControllerMessenger = RestrictedMessenger<typeof controllerName, MultichainBalancesControllerActions | AllowedActions, MultichainBalancesControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
62
55
  /**
63
56
  * The MultichainBalancesController is responsible for fetching and caching account
64
57
  * balances.
@@ -69,14 +62,6 @@ export declare class MultichainBalancesController extends BaseController<typeof
69
62
  messenger: MultichainBalancesControllerMessenger;
70
63
  state?: Partial<MultichainBalancesControllerState>;
71
64
  });
72
- /**
73
- * Starts the polling process.
74
- */
75
- start(): void;
76
- /**
77
- * Stops the polling process.
78
- */
79
- stop(): void;
80
65
  /**
81
66
  * Updates the balances of one account. This method doesn't return
82
67
  * anything, but it updates the state of the controller.
@@ -84,11 +69,6 @@ export declare class MultichainBalancesController extends BaseController<typeof
84
69
  * @param accountId - The account ID.
85
70
  */
86
71
  updateBalance(accountId: string): Promise<void>;
87
- /**
88
- * Updates the balances of all supported accounts. This method doesn't return
89
- * anything, but it updates the state of the controller.
90
- */
91
- updateBalances(): Promise<void>;
92
72
  }
93
73
  export {};
94
74
  //# sourceMappingURL=MultichainBalancesController.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainBalancesController.d.cts","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mCAAmC,EACnC,qCAAqC,EACrC,8CAA8C,EAC/C,sCAAsC;AACvC,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,6BAA6B,EACnC,kCAAkC;AAKnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,oCAAoC;AASrE,QAAA,MAAM,cAAc,iCAAiC,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,EAAE;QACR,CAAC,OAAO,EAAE,MAAM,GAAG;YACjB,CAAC,KAAK,EAAE,MAAM,GAAG;gBACf,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE,MAAM,CAAC;aACd,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,2CAA2C,IAAI,iCAAiC,CAE/F;AAED;;GAEG;AACH,MAAM,MAAM,0CAA0C,GACpD,wBAAwB,CACtB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,gDAAgD,GAAG;IAC7D,IAAI,EAAE,GAAG,OAAO,cAAc,iBAAiB,CAAC;IAChD,OAAO,EAAE,4BAA4B,CAAC,gBAAgB,CAAC,CAAC;CACzD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uCAAuC,GACjD,0BAA0B,CACxB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC3C,0CAA0C,GAC1C,gDAAgD,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,kCAAkC,GAC5C,uCAAuC,CAAC;AAE1C;;GAEG;AACH,KAAK,cAAc,GACf,iBAAiB,GACjB,8CAA8C,CAAC;AAEnD;;GAEG;AACH,KAAK,aAAa,GACd,mCAAmC,GACnC,qCAAqC,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAC/C,6BAA6B,CAC3B,OAAO,cAAc,EACrB,mCAAmC,GAAG,cAAc,EACpD,kCAAkC,GAAG,aAAa,EAClD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAgBJ;;;GAGG;AACH,qBAAa,4BAA6B,SAAQ,cAAc,CAC9D,OAAO,cAAc,EACrB,iCAAiC,EACjC,qCAAqC,CACtC;;gBAGa,EACV,SAAS,EACT,KAAU,GACX,EAAE;QACD,SAAS,EAAE,qCAAqC,CAAC;QACjD,KAAK,CAAC,EAAE,OAAO,CAAC,iCAAiC,CAAC,CAAC;KACpD;IAgCD;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrD;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;CA8JtC"}
1
+ {"version":3,"file":"MultichainBalancesController.d.cts","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mCAAmC,EACnC,qCAAqC,EACrC,8CAA8C,EAC9C,6CAA6C,EAC9C,sCAAsC;AACvC,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACzB,kCAAkC;AASnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,oCAAoC;AASrE,QAAA,MAAM,cAAc,iCAAiC,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,EAAE;QACR,CAAC,OAAO,EAAE,MAAM,GAAG;YACjB,CAAC,KAAK,EAAE,MAAM,GAAG;gBACf,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE,MAAM,CAAC;aACd,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,2CAA2C,IAAI,iCAAiC,CAE/F;AAED;;GAEG;AACH,MAAM,MAAM,0CAA0C,GACpD,wBAAwB,CACtB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,uCAAuC,GACjD,0BAA0B,CACxB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC7C,0CAA0C,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,kCAAkC,GAC5C,uCAAuC,CAAC;AAE1C;;GAEG;AACH,KAAK,cAAc,GACf,iBAAiB,GACjB,8CAA8C,CAAC;AAEnD;;GAEG;AACH,KAAK,aAAa,GACd,mCAAmC,GACnC,qCAAqC,GACrC,6CAA6C,CAAC;AAClD;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAAG,mBAAmB,CACrE,OAAO,cAAc,EACrB,mCAAmC,GAAG,cAAc,EACpD,kCAAkC,GAAG,aAAa,EAClD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAgBF;;;GAGG;AACH,qBAAa,4BAA6B,SAAQ,cAAc,CAC9D,OAAO,cAAc,EACrB,iCAAiC,EACjC,qCAAqC,CACtC;;gBACa,EACV,SAAS,EACT,KAAU,GACX,EAAE;QACD,SAAS,EAAE,qCAAqC,CAAC;QACjD,KAAK,CAAC,EAAE,OAAO,CAAC,iCAAiC,CAAC,CAAC;KACpD;IAoCD;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAiKtD"}
@@ -1,5 +1,5 @@
1
- import type { AccountsControllerAccountAddedEvent, AccountsControllerAccountRemovedEvent, AccountsControllerListMultichainAccountsAction } from "@metamask/accounts-controller";
2
- import { BaseController, type ControllerGetStateAction, type ControllerStateChangeEvent, type RestrictedControllerMessenger } from "@metamask/base-controller";
1
+ import type { AccountsControllerAccountAddedEvent, AccountsControllerAccountRemovedEvent, AccountsControllerListMultichainAccountsAction, AccountsControllerAccountBalancesUpdatesEvent } from "@metamask/accounts-controller";
2
+ import { BaseController, type ControllerGetStateAction, type ControllerStateChangeEvent, type RestrictedMessenger } from "@metamask/base-controller";
3
3
  import type { HandleSnapRequest } from "@metamask/snaps-controllers";
4
4
  declare const controllerName = "MultichainBalancesController";
5
5
  /**
@@ -28,13 +28,6 @@ export declare function getDefaultMultichainBalancesControllerState(): Multichai
28
28
  * Returns the state of the {@link MultichainBalancesController}.
29
29
  */
30
30
  export type MultichainBalancesControllerGetStateAction = ControllerGetStateAction<typeof controllerName, MultichainBalancesControllerState>;
31
- /**
32
- * Updates the balances of all supported accounts.
33
- */
34
- export type MultichainBalancesControllerUpdateBalancesAction = {
35
- type: `${typeof controllerName}:updateBalances`;
36
- handler: MultichainBalancesController['updateBalances'];
37
- };
38
31
  /**
39
32
  * Event emitted when the state of the {@link MultichainBalancesController} changes.
40
33
  */
@@ -42,7 +35,7 @@ export type MultichainBalancesControllerStateChange = ControllerStateChangeEvent
42
35
  /**
43
36
  * Actions exposed by the {@link MultichainBalancesController}.
44
37
  */
45
- export type MultichainBalancesControllerActions = MultichainBalancesControllerGetStateAction | MultichainBalancesControllerUpdateBalancesAction;
38
+ export type MultichainBalancesControllerActions = MultichainBalancesControllerGetStateAction;
46
39
  /**
47
40
  * Events emitted by {@link MultichainBalancesController}.
48
41
  */
@@ -54,11 +47,11 @@ type AllowedActions = HandleSnapRequest | AccountsControllerListMultichainAccoun
54
47
  /**
55
48
  * Events that this controller is allowed to subscribe.
56
49
  */
57
- type AllowedEvents = AccountsControllerAccountAddedEvent | AccountsControllerAccountRemovedEvent;
50
+ type AllowedEvents = AccountsControllerAccountAddedEvent | AccountsControllerAccountRemovedEvent | AccountsControllerAccountBalancesUpdatesEvent;
58
51
  /**
59
52
  * Messenger type for the MultichainBalancesController.
60
53
  */
61
- export type MultichainBalancesControllerMessenger = RestrictedControllerMessenger<typeof controllerName, MultichainBalancesControllerActions | AllowedActions, MultichainBalancesControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
54
+ export type MultichainBalancesControllerMessenger = RestrictedMessenger<typeof controllerName, MultichainBalancesControllerActions | AllowedActions, MultichainBalancesControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
62
55
  /**
63
56
  * The MultichainBalancesController is responsible for fetching and caching account
64
57
  * balances.
@@ -69,14 +62,6 @@ export declare class MultichainBalancesController extends BaseController<typeof
69
62
  messenger: MultichainBalancesControllerMessenger;
70
63
  state?: Partial<MultichainBalancesControllerState>;
71
64
  });
72
- /**
73
- * Starts the polling process.
74
- */
75
- start(): void;
76
- /**
77
- * Stops the polling process.
78
- */
79
- stop(): void;
80
65
  /**
81
66
  * Updates the balances of one account. This method doesn't return
82
67
  * anything, but it updates the state of the controller.
@@ -84,11 +69,6 @@ export declare class MultichainBalancesController extends BaseController<typeof
84
69
  * @param accountId - The account ID.
85
70
  */
86
71
  updateBalance(accountId: string): Promise<void>;
87
- /**
88
- * Updates the balances of all supported accounts. This method doesn't return
89
- * anything, but it updates the state of the controller.
90
- */
91
- updateBalances(): Promise<void>;
92
72
  }
93
73
  export {};
94
74
  //# sourceMappingURL=MultichainBalancesController.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainBalancesController.d.mts","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mCAAmC,EACnC,qCAAqC,EACrC,8CAA8C,EAC/C,sCAAsC;AACvC,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,6BAA6B,EACnC,kCAAkC;AAKnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,oCAAoC;AASrE,QAAA,MAAM,cAAc,iCAAiC,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,EAAE;QACR,CAAC,OAAO,EAAE,MAAM,GAAG;YACjB,CAAC,KAAK,EAAE,MAAM,GAAG;gBACf,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE,MAAM,CAAC;aACd,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,2CAA2C,IAAI,iCAAiC,CAE/F;AAED;;GAEG;AACH,MAAM,MAAM,0CAA0C,GACpD,wBAAwB,CACtB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,gDAAgD,GAAG;IAC7D,IAAI,EAAE,GAAG,OAAO,cAAc,iBAAiB,CAAC;IAChD,OAAO,EAAE,4BAA4B,CAAC,gBAAgB,CAAC,CAAC;CACzD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uCAAuC,GACjD,0BAA0B,CACxB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC3C,0CAA0C,GAC1C,gDAAgD,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,kCAAkC,GAC5C,uCAAuC,CAAC;AAE1C;;GAEG;AACH,KAAK,cAAc,GACf,iBAAiB,GACjB,8CAA8C,CAAC;AAEnD;;GAEG;AACH,KAAK,aAAa,GACd,mCAAmC,GACnC,qCAAqC,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAC/C,6BAA6B,CAC3B,OAAO,cAAc,EACrB,mCAAmC,GAAG,cAAc,EACpD,kCAAkC,GAAG,aAAa,EAClD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAgBJ;;;GAGG;AACH,qBAAa,4BAA6B,SAAQ,cAAc,CAC9D,OAAO,cAAc,EACrB,iCAAiC,EACjC,qCAAqC,CACtC;;gBAGa,EACV,SAAS,EACT,KAAU,GACX,EAAE;QACD,SAAS,EAAE,qCAAqC,CAAC;QACjD,KAAK,CAAC,EAAE,OAAO,CAAC,iCAAiC,CAAC,CAAC;KACpD;IAgCD;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrD;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;CA8JtC"}
1
+ {"version":3,"file":"MultichainBalancesController.d.mts","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mCAAmC,EACnC,qCAAqC,EACrC,8CAA8C,EAC9C,6CAA6C,EAC9C,sCAAsC;AACvC,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACzB,kCAAkC;AASnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,oCAAoC;AASrE,QAAA,MAAM,cAAc,iCAAiC,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,EAAE;QACR,CAAC,OAAO,EAAE,MAAM,GAAG;YACjB,CAAC,KAAK,EAAE,MAAM,GAAG;gBACf,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE,MAAM,CAAC;aACd,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,2CAA2C,IAAI,iCAAiC,CAE/F;AAED;;GAEG;AACH,MAAM,MAAM,0CAA0C,GACpD,wBAAwB,CACtB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,uCAAuC,GACjD,0BAA0B,CACxB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC7C,0CAA0C,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,kCAAkC,GAC5C,uCAAuC,CAAC;AAE1C;;GAEG;AACH,KAAK,cAAc,GACf,iBAAiB,GACjB,8CAA8C,CAAC;AAEnD;;GAEG;AACH,KAAK,aAAa,GACd,mCAAmC,GACnC,qCAAqC,GACrC,6CAA6C,CAAC;AAClD;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAAG,mBAAmB,CACrE,OAAO,cAAc,EACrB,mCAAmC,GAAG,cAAc,EACpD,kCAAkC,GAAG,aAAa,EAClD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAgBF;;;GAGG;AACH,qBAAa,4BAA6B,SAAQ,cAAc,CAC9D,OAAO,cAAc,EACrB,iCAAiC,EACjC,qCAAqC,CACtC;;gBACa,EACV,SAAS,EACT,KAAU,GACX,EAAE;QACD,SAAS,EAAE,qCAAqC,CAAC;QACjD,KAAK,CAAC,EAAE,OAAO,CAAC,iCAAiC,CAAC,CAAC;KACpD;IAoCD;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAiKtD"}
@@ -3,19 +3,13 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
3
3
  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");
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
7
- if (kind === "m") throw new TypeError("Private method is not writable");
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
9
- 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");
10
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
- };
12
- var _MultichainBalancesController_instances, _MultichainBalancesController_tracker, _MultichainBalancesController_listMultichainAccounts, _MultichainBalancesController_listAccounts, _MultichainBalancesController_getAccount, _MultichainBalancesController_updateBalance, _MultichainBalancesController_isNonEvmAccount, _MultichainBalancesController_handleOnAccountAdded, _MultichainBalancesController_handleOnAccountRemoved, _MultichainBalancesController_getBalances, _MultichainBalancesController_getClient;
6
+ var _MultichainBalancesController_instances, _MultichainBalancesController_listMultichainAccounts, _MultichainBalancesController_listAccounts, _MultichainBalancesController_getAccount, _MultichainBalancesController_isNonEvmAccount, _MultichainBalancesController_handleOnAccountAdded, _MultichainBalancesController_handleOnAccountBalancesUpdated, _MultichainBalancesController_handleOnAccountRemoved, _MultichainBalancesController_getBalances, _MultichainBalancesController_getClient;
13
7
  import { BaseController } from "@metamask/base-controller";
14
8
  import { isEvmAccountType } from "@metamask/keyring-api";
15
9
  import { KeyringClient } from "@metamask/keyring-snap-client";
16
10
  import { HandlerType } from "@metamask/snaps-utils";
17
- import { BalancesTracker, NETWORK_ASSETS_MAP } from "./index.mjs";
18
- import { getScopeForAccount, getBlockTimeForAccount } from "./utils.mjs";
11
+ import { NETWORK_ASSETS_MAP } from "./index.mjs";
12
+ import { getScopeForAccount } from "./utils.mjs";
19
13
  const controllerName = 'MultichainBalancesController';
20
14
  /**
21
15
  * Constructs the default {@link MultichainBalancesController} state. This allows
@@ -57,28 +51,15 @@ export class MultichainBalancesController extends BaseController {
57
51
  },
58
52
  });
59
53
  _MultichainBalancesController_instances.add(this);
60
- _MultichainBalancesController_tracker.set(this, void 0);
61
- __classPrivateFieldSet(this, _MultichainBalancesController_tracker, new BalancesTracker(async (accountId) => await __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_updateBalance).call(this, accountId)), "f");
62
- // Register all non-EVM accounts into the tracker
54
+ // Fetch initial balances for all non-EVM accounts
63
55
  for (const account of __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_listAccounts).call(this)) {
64
- if (__classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_isNonEvmAccount).call(this, account)) {
65
- __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").track(account.id, getBlockTimeForAccount(account.type));
66
- }
56
+ this.updateBalance(account.id).catch((error) => {
57
+ console.error(`Failed to fetch initial balance for account ${account.id}:`, error);
58
+ });
67
59
  }
68
60
  this.messagingSystem.subscribe('AccountsController:accountAdded', (account) => __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_handleOnAccountAdded).call(this, account));
69
61
  this.messagingSystem.subscribe('AccountsController:accountRemoved', (account) => __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_handleOnAccountRemoved).call(this, account));
70
- }
71
- /**
72
- * Starts the polling process.
73
- */
74
- start() {
75
- __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").start();
76
- }
77
- /**
78
- * Stops the polling process.
79
- */
80
- stop() {
81
- __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").stop();
62
+ this.messagingSystem.subscribe('AccountsController:accountBalancesUpdated', (balanceUpdate) => __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_handleOnAccountBalancesUpdated).call(this, balanceUpdate));
82
63
  }
83
64
  /**
84
65
  * Updates the balances of one account. This method doesn't return
@@ -87,19 +68,23 @@ export class MultichainBalancesController extends BaseController {
87
68
  * @param accountId - The account ID.
88
69
  */
89
70
  async updateBalance(accountId) {
90
- // NOTE: No need to track the account here, since we start tracking those when
91
- // the "AccountsController:accountAdded" is fired.
92
- await __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").updateBalance(accountId);
93
- }
94
- /**
95
- * Updates the balances of all supported accounts. This method doesn't return
96
- * anything, but it updates the state of the controller.
97
- */
98
- async updateBalances() {
99
- await __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").updateBalances();
71
+ try {
72
+ const account = __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getAccount).call(this, accountId);
73
+ if (account.metadata.snap) {
74
+ const scope = getScopeForAccount(account);
75
+ const assetTypes = NETWORK_ASSETS_MAP[scope];
76
+ const accountBalance = await __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getBalances).call(this, account.id, account.metadata.snap.id, assetTypes);
77
+ this.update((state) => {
78
+ state.balances[accountId] = accountBalance;
79
+ });
80
+ }
81
+ }
82
+ catch (error) {
83
+ console.error(`Failed to fetch balances for account ${accountId}:`, error);
84
+ }
100
85
  }
101
86
  }
102
- _MultichainBalancesController_tracker = new WeakMap(), _MultichainBalancesController_instances = new WeakSet(), _MultichainBalancesController_listMultichainAccounts = function _MultichainBalancesController_listMultichainAccounts() {
87
+ _MultichainBalancesController_instances = new WeakSet(), _MultichainBalancesController_listMultichainAccounts = function _MultichainBalancesController_listMultichainAccounts() {
103
88
  return this.messagingSystem.call('AccountsController:listMultichainAccounts');
104
89
  }, _MultichainBalancesController_listAccounts = function _MultichainBalancesController_listAccounts() {
105
90
  const accounts = __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_listMultichainAccounts).call(this);
@@ -110,23 +95,6 @@ _MultichainBalancesController_tracker = new WeakMap(), _MultichainBalancesContro
110
95
  throw new Error(`Unknown account: ${accountId}`);
111
96
  }
112
97
  return account;
113
- }, _MultichainBalancesController_updateBalance =
114
- /**
115
- * Updates the balances of one account. This method doesn't return
116
- * anything, but it updates the state of the controller.
117
- *
118
- * @param accountId - The account ID.
119
- */
120
- async function _MultichainBalancesController_updateBalance(accountId) {
121
- const account = __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getAccount).call(this, accountId);
122
- if (account.metadata.snap) {
123
- const scope = getScopeForAccount(account);
124
- const assetTypes = NETWORK_ASSETS_MAP[scope];
125
- const accountBalance = await __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getBalances).call(this, account.id, account.metadata.snap.id, assetTypes);
126
- this.update((state) => {
127
- state.balances[accountId] = accountBalance;
128
- });
129
- }
130
98
  }, _MultichainBalancesController_isNonEvmAccount = function _MultichainBalancesController_isNonEvmAccount(account) {
131
99
  return (!isEvmAccountType(account.type) &&
132
100
  // Non-EVM accounts are backed by a Snap for now
@@ -139,17 +107,17 @@ async function _MultichainBalancesController_updateBalance(accountId) {
139
107
  */
140
108
  async function _MultichainBalancesController_handleOnAccountAdded(account) {
141
109
  if (!__classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_isNonEvmAccount).call(this, account)) {
142
- // Nothing to do here for EVM accounts
143
110
  return;
144
111
  }
145
- __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").track(account.id, getBlockTimeForAccount(account.type));
146
- // NOTE: Unfortunately, we cannot update the balance right away here, because
147
- // messenger's events are running synchronously and fetching the balance is
148
- // asynchronous.
149
- // Updating the balance here would resume at some point but the event emitter
150
- // will not `await` this (so we have no real control "when" the balance will
151
- // really be updated), see:
152
- // - https://github.com/MetaMask/core/blob/v213.0.0/packages/accounts-controller/src/AccountsController.ts#L1036-L1039
112
+ await this.updateBalance(account.id);
113
+ }, _MultichainBalancesController_handleOnAccountBalancesUpdated = function _MultichainBalancesController_handleOnAccountBalancesUpdated(balanceUpdate) {
114
+ this.update((state) => {
115
+ Object.entries(balanceUpdate.balances).forEach(([accountId, assetBalances]) => {
116
+ if (accountId in state.balances) {
117
+ Object.assign(state.balances[accountId], assetBalances);
118
+ }
119
+ });
120
+ });
153
121
  }, _MultichainBalancesController_handleOnAccountRemoved =
154
122
  /**
155
123
  * Handles changes when a new account has been removed.
@@ -157,9 +125,6 @@ async function _MultichainBalancesController_handleOnAccountAdded(account) {
157
125
  * @param accountId - The account ID being removed.
158
126
  */
159
127
  async function _MultichainBalancesController_handleOnAccountRemoved(accountId) {
160
- if (__classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").isTracked(accountId)) {
161
- __classPrivateFieldGet(this, _MultichainBalancesController_tracker, "f").untrack(accountId);
162
- }
163
128
  if (accountId in this.state.balances) {
164
129
  this.update((state) => {
165
130
  delete state.balances[accountId];
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainBalancesController.mjs","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 { isEvmAccountType } from '@metamask/keyring-api';\nimport type { Balance, CaipAssetType } from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\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 { BalancesTracker, NETWORK_ASSETS_MAP } from '.';\nimport { getScopeForAccount, getBlockTimeForAccount } 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 * Constructs the default {@link MultichainBalancesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainBalancesController} state.\n */\nexport function getDefaultMultichainBalancesControllerState(): MultichainBalancesControllerState {\n return { balances: {} };\n}\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.\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 */\ntype AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype 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 balancesControllerMetadata = {\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 #tracker: BalancesTracker;\n\n constructor({\n messenger,\n state = {},\n }: {\n messenger: MultichainBalancesControllerMessenger;\n state?: Partial<MultichainBalancesControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: balancesControllerMetadata,\n state: {\n ...getDefaultMultichainBalancesControllerState(),\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 if (this.#isNonEvmAccount(account)) {\n this.#tracker.track(account.id, getBlockTimeForAccount(account.type));\n }\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 * 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): Promise<void> {\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(): Promise<void> {\n await this.#tracker.updateBalances();\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 * @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 = this.#listAccounts().find(\n (multichainAccount) => multichainAccount.id === accountId,\n );\n\n if (!account) {\n throw new Error(`Unknown account: ${accountId}`);\n }\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\n async #updateBalance(accountId: string) {\n const account = this.#getAccount(accountId);\n\n if (account.metadata.snap) {\n const scope = getScopeForAccount(account);\n const assetTypes = NETWORK_ASSETS_MAP[scope];\n\n const accountBalance = await this.#getBalances(\n account.id,\n account.metadata.snap.id,\n assetTypes,\n );\n\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n state.balances[accountId] = accountBalance;\n });\n }\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): Promise<void> {\n if (!this.#isNonEvmAccount(account)) {\n // Nothing to do here for EVM accounts\n return;\n }\n\n this.#tracker.track(account.id, getBlockTimeForAccount(account.type));\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): Promise<void> {\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 });\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"]}
1
+ {"version":3,"file":"MultichainBalancesController.mjs","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerAccountBalancesUpdatesEvent,\n} from '@metamask/accounts-controller';\nimport {\n BaseController,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n Balance,\n CaipAssetType,\n AccountBalancesUpdatedEventPayload,\n} from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\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 { NETWORK_ASSETS_MAP } from '.';\nimport { getScopeForAccount } 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 * Constructs the default {@link MultichainBalancesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainBalancesController} state.\n */\nexport function getDefaultMultichainBalancesControllerState(): MultichainBalancesControllerState {\n return { balances: {} };\n}\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 * 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\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 */\ntype AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent\n | AccountsControllerAccountBalancesUpdatesEvent;\n/**\n * Messenger type for the MultichainBalancesController.\n */\nexport type MultichainBalancesControllerMessenger = RestrictedMessenger<\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 balancesControllerMetadata = {\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 constructor({\n messenger,\n state = {},\n }: {\n messenger: MultichainBalancesControllerMessenger;\n state?: Partial<MultichainBalancesControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: balancesControllerMetadata,\n state: {\n ...getDefaultMultichainBalancesControllerState(),\n ...state,\n },\n });\n\n // Fetch initial balances for all non-EVM accounts\n for (const account of this.#listAccounts()) {\n this.updateBalance(account.id).catch((error) => {\n console.error(\n `Failed to fetch initial balance for account ${account.id}:`,\n error,\n );\n });\n }\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountAdded',\n (account: InternalAccount) => this.#handleOnAccountAdded(account),\n );\n this.messagingSystem.subscribe(\n 'AccountsController:accountRemoved',\n (account: string) => this.#handleOnAccountRemoved(account),\n );\n this.messagingSystem.subscribe(\n 'AccountsController:accountBalancesUpdated',\n (balanceUpdate: AccountBalancesUpdatedEventPayload) =>\n this.#handleOnAccountBalancesUpdated(balanceUpdate),\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): Promise<void> {\n try {\n const account = this.#getAccount(accountId);\n\n if (account.metadata.snap) {\n const scope = getScopeForAccount(account);\n const assetTypes = NETWORK_ASSETS_MAP[scope];\n\n const accountBalance = await this.#getBalances(\n account.id,\n account.metadata.snap.id,\n assetTypes,\n );\n\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n state.balances[accountId] = accountBalance;\n });\n }\n } catch (error) {\n console.error(\n `Failed to fetch balances for account ${accountId}:`,\n error,\n );\n }\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 * @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 = this.#listAccounts().find(\n (multichainAccount) => multichainAccount.id === accountId,\n );\n\n if (!account) {\n throw new Error(`Unknown account: ${accountId}`);\n }\n\n return account;\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): Promise<void> {\n if (!this.#isNonEvmAccount(account)) {\n return;\n }\n\n await this.updateBalance(account.id);\n }\n\n /**\n * Handles balance updates received from the AccountsController.\n *\n * @param balanceUpdate - The balance update event containing new balances.\n */\n #handleOnAccountBalancesUpdated(\n balanceUpdate: AccountBalancesUpdatedEventPayload,\n ): void {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n Object.entries(balanceUpdate.balances).forEach(\n ([accountId, assetBalances]) => {\n if (accountId in state.balances) {\n Object.assign(state.balances[accountId], assetBalances);\n }\n },\n );\n });\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): Promise<void> {\n if (accountId in this.state.balances) {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n delete state.balances[accountId];\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"]}