Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: upgrade assets-controllers to v38.2.0 #27629

Merged
merged 12 commits into from
Oct 10, 2024
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
diff --git a/dist/assetsUtil.cjs b/dist/assetsUtil.cjs
index e90a1b6767bc8ac54b7a4d580035cf5db6861dca..2662df7869e9079f9379c4dd1ded40b5af4e71f2 100644
--- a/dist/assetsUtil.cjs
+++ b/dist/assetsUtil.cjs
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }
exports.fetchTokenContractExchangeRates = exports.reduceInBatchesSerially = exports.divideIntoBatches = exports.ethersBigNumberToBN = exports.addUrlProtocolPrefix = exports.getFormattedIpfsUrl = exports.getIpfsCIDv1AndPath = exports.removeIpfsProtocolPrefix = exports.isTokenListSupportedForNetwork = exports.isTokenDetectionSupportedForNetwork = exports.SupportedTokenDetectionNetworks = exports.formatIconUrlWithProxy = exports.formatAggregatorNames = exports.hasNewCollectionFields = exports.compareNftMetadata = exports.TOKEN_PRICES_BATCH_SIZE = void 0;
const controller_utils_1 = require("@metamask/controller-utils");
const utils_1 = require("@metamask/utils");
@@ -221,7 +222,7 @@ async function getIpfsCIDv1AndPath(ipfsUrl) {
const index = url.indexOf('/');
const cid = index !== -1 ? url.substring(0, index) : url;
const path = index !== -1 ? url.substring(index) : undefined;
- const { CID } = await import("multiformats");
+ const { CID } = await Promise.resolve().then(() => _interopRequireWildcard(require("multiformats")));
Copy link
Contributor

@MajorLift MajorLift Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The await import() call being left in there was intentional. Not only is await import() available to commonjs in node v12+, passing an ESM-only module like multiformats into require also crashes node or otherwise may cause undefined behavior.

The import call causing failed test runs is also expected, because dynamic import is only available behind a NODE_OPTIONS=--experimental-vm-modules flag. This is why we've added that to all of our core test scripts (https://github.com/MetaMask/core/blob/main/packages/assets-controllers/package.json#L44-L47). We'll probably need to do the same in extension and mobile.

I guess the question here is whether we can be sure that _interopRequireWildcard is actually executing the CID import correctly, or if it's masking broken behavior.

Another question would be how to handle similar scenarios (upstream ESM-only modules) going forward. Consistently using await import() is the only way that makes sense to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MajorLift thnx a lot for looking into this 🙏 I have added some logs with this current patch and it looks like its working fine, its able to fetch CID and display the NFT media;

Without the patch, i can see the error __import__ is not defined in console again and its not displaying the images correctly;
Screenshot 2024-10-07 at 19 05 08

Thanks for referencing the related test script update on core 🙏 this is not only related to tests, correct? since im able to see the error when running the app locally?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The browser uses only ESM, so that's a really weird error message. Maybe it's coming from selenium or some other node process? I tried adding the flag to the e2e test build scripts (#27675) but I'm still getting the same error.

Since you verified that the import is working correctly I think we can move forward with the current patch. Thanks for being on top of that.

Would be nice to figure this error out for the future though. I'll do some more digging.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is running under lavamoat and dynamic import is deliberately not supported - hence a transform changing all functions named import into __import__

We currently can't have dynamic import work inside compartments. It's not feasible to intercept it the way we'd need to. Since the bundler we use doesn't support it, the dynamic import would be called directly in the browser and "multiformats" is not a URL to a script file, so it would fail with a different error even if LavaMoat transforms weren't there to prevent it.
I recommend addressing this somehow in a minor refactor of the assets controller if it's intended for use in MetaMask.

When we switch to webpack with LavaMoat webpack plugin it's possible webpack will transform the dynamic import into its own syntax if configured for that, but that's the only hope for using dynamic require I see for now. Didn't check how that behaves yet. I can get back to you later.

Copy link
Contributor

@MajorLift MajorLift Oct 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@naugtur Thanks for the insight! I wasn't aware that Lavamoat did this. I'll have to look into what else it blocks.

Unfortunately this a language-level CJS/ESM interop issue that isn't specific to assets-controllers and multiformats -- it applies to any ESM-only module in our dependency tree.

Most of our modules are natively CJS. We use ESM syntax because we write in TypeScript, but we expose dual CJS/ESM builds and our manifests do not specify the "module": "type" property. Because of this, the only way for our modules to handle ESM imports in a CJS-compatible manner is with dynamic import syntax i.e. require doesn't work, and neither does static import syntax that transpiles down to require.

True CommonJS modules can require an ESM-transpiled-to-CJS module, since they’re both CommonJS at runtime. But in Node.js, require crashes if it resolves to an ES module. This means published libraries cannot migrate from transpiled modules to true ESM without breaking their CommonJS (true or transpiled) consumers:

// @Filename: node_modules/dependency/index.js
export function doSomething() { /* ... */ }
// @Filename: dependent.js
import { doSomething } from "dependency";
// ✅ Works if dependent and dependency are both transpiled
// ✅ Works if dependent and dependency are both true ESM
// ✅ Works if dependent is true ESM and dependency is transpiled
// 💥 Crashes if dependent is transpiled and dependency is true ESM

https://www.typescriptlang.org/docs/handbook/modules/appendices/esm-cjs-interop.html#cannot-require-a-true-es-module

This issue was previously masked by our usage of the outdated { module: "commonjs", moduleResolution: "node10" } tsconfig options. However, the core and snaps repos recently updated to "node16" for both options, which enforces sound module resolution restrictions and therefore prohibits ESM-only modules from being passed into require calls. This update is expected to propagate to all of our TypeScript repos.

In this specific case, we can use the patch as is because multiformats happens to work with require calls without breaking things, but this is a coincidence we can't rely on for all ESM packages in general.

To preserve the ban on dynamic import syntax I see three possibilities:

  1. Remove all ESM-only modules from all of our dependency trees, or replace them with CJS-compatible forks (we've done this before e.g. @metamask/superstruct).
  2. Convert all of our modules to "true ESM".
  3. Start using a bundler like Webpack in all of our repos to generate builds (assuming it can be set up to generate dual builds for dependencies in a way that would sidestep this issue).

All of these would be major, if not prohibitive, undertakings.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 and 2 are not options we're fond of.
With the exception of: until we have a lavamoat-node that supports ESM (we're working on it) we might sometimes have to eliminate esm-only packages from builds that run under lavamoat.

We should be able to switch to webpack in the foreseeable future. LavaMoat Webpack plugin is reaching 1.0 by the end of this year and we're wery close to getting a working MetaMask build out of it. 3rdparty audit is finishing too.

Meanwhile,
Joyee has made it possible to require(esm) in Node.js
https://nodejs.org/api/esm.html#interoperability-with-commonjs
https://joyeecheung.github.io/blog/2024/03/18/require-esm-in-node-js/

So we're looking for a solution to the typescript situation that we can live with for limited time.

Copy link
Contributor

@MajorLift MajorLift Oct 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed that 1, 2 aren't the most ideal options. ;)

I wasn't aware of --experimental-require-module, but it looks like a great stopgap. Fingers crossed that we don't run into an ESM package with top-level await.

Based on anecdotal experience from applying Node16 to core and snaps, our usage of CJS-incompatible packages is uncommon enough that we should be able to handle them on a case-by-case basis, at least for the time being.

However, the few exceptions can have an outsized impact. Migrating from superstruct to @metamask/superstruct ended up being a massive undertaking because it required us to update and release basically all transitive dependents. Removing the imports for such a widely used package will probably present difficulties as well. Hopefully we don't come across such a scenario again any time soon.

Anyway, it's very good to know that there are fundamental fixes on the way, and thank you for your work on that! Especially excited to potentially have lavamoat-node directly applied to our upstream libraries.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going back to the change itself:

The await on an empty promise before running synchronous require seems unnecessary. Does anything depend on this step being asynchronous? Doesn't seem so.

Suggested change
+ const { CID } = await Promise.resolve().then(() => _interopRequireWildcard(require("multiformats")));
+ const { CID } = _interopRequireWildcard(require("multiformats"));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in v37 this change was introduced:
BREAKING: getIpfsCIDv1AndPath, getFormattedIpfsUrl are now async functions (MetaMask/core#3645)

This patch update matches the generated build after the V37 update;

Copy link
Contributor

@MajorLift MajorLift Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The await is necessary in the CJS source code since we're forced to use a dynamic import. But in the build output that we're patching we definitely don't need to both then and await the synchronous _interopRequireWildcard call.

@naugtur's suggestion looks good to me, although I'd feel better with another manual check on whether CID is sourced at runtime.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @MajorLift and @naugtur 🙏 i have removed the empty promise; could you please approve again and we merge this 🙏

// We want to ensure that the CID is v1 (https://docs.ipfs.io/concepts/content-addressing/#identifier-formats)
// because most cid v0s appear to be incompatible with IPFS subdomains
return {
diff --git a/dist/token-prices-service/codefi-v2.mjs b/dist/token-prices-service/codefi-v2.mjs
index e7eaad2cfa8b233c4fd42a51f745233a1cc5c387..416dab35e83334f0cafe23c9bd34d0a0380145b2 100644
--- a/dist/token-prices-service/codefi-v2.mjs
+++ b/dist/token-prices-service/codefi-v2.mjs
@@ -12,8 +12,8 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
var _CodefiTokenPricesServiceV2_tokenPricePolicy;
import { handleFetch } from "@metamask/controller-utils";
import { hexToNumber } from "@metamask/utils";
-import $cockatiel from "cockatiel";
-const { circuitBreaker, ConsecutiveBreaker, ExponentialBackoff, handleAll, retry, wrap, CircuitState } = $cockatiel;
+
+import { circuitBreaker, ConsecutiveBreaker, ExponentialBackoff, handleAll, retry, wrap, CircuitState } from "cockatiel";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix makes sense, but I don't understand why we're getting a default import here in the first place.

@Mrtenz Is it possible that this is an artifact from ts-bridge processing mixed type vs. value imports in a single import statement?

This is the original code:

import {
  circuitBreaker,
  ConsecutiveBreaker,
  ExponentialBackoff,
  handleAll,
  type IPolicy,
  retry,
  wrap,
  CircuitState,
} from 'cockatiel';

https://github.com/MetaMask/core/blob/main/packages/assets-controllers/src/token-prices-service/codefi-v2.ts#L4-L13

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to type imports, those are supported by ts-bridge. I suspect this is caused by a difference in how Node.js and Webpack handle module detection... 😞

ts-bridge detects whether a package is CommonJS or ESM following Node.js' module resolution algorithm. If the package is detected as CommonJS, it checks what exports it has (using cjs-module-lexer, used by Node.js as well). If some CommonJS exports are not detected, the import is rewritten to a default import, as this is supposed to increase compatibility.

cockatiel has an ESM version, but it's only specified in the module field, which is not used by Node.js (but is used by Webpack). The CommonJS export seems to use a syntax that is not supported by cjs-module-lexer (though I need to verify this), so the exports are not detected.

There are several options here:

  1. We apply this patch.
    • We could do this as temporary solution to get this PR merged either way.
  2. We disable the module field in Webpack's module resolution.
    • This aligns it more with Node.js module resolution, but may result in a larger bundle if many dependencies use the module field, but not package.json exports.
  3. We submit a PR to cockatiel to use the exports field in package.json to allow Node.js to use the ESM version as well.
    • I will do this regardless, but I'm not sure how long it will take for this to be merged and released.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet another CJS/ESM interop scenario to keep an eye out for. :( Really appreciate the breakdown and your looking into this. I had a couple of questions:

If some CommonJS exports are not detected, the import is rewritten to a default import, as this is supposed to increase compatibility.

According to @sahar-fehri, this causes the following error:

I had this error when doing yarn build:storybook;

export 'default' (imported as '$cockatiel') was not found in 'cockatiel'

Is storybook an outlier here, or will we always see this error if there is no default export?

The CommonJS export seems to use a syntax that is not supported by cjs-module-lexer

Also, for this issue, is an upstream update pretty much the only possible fix?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you could say Webpack is the outlier because it looks at the module field. This is completely valid in Node.js for example:

import $cockatiel from 'cockatiel';
const { circuitBreaker } = $cockatiel;

console.log(circuitBreaker); // [Function: circuitBreaker]

Because Node.js loads the CommonJS version, but Webpack loads the ESM version.

Also, for this issue, is an upstream update pretty much the only possible fix?

I'm leaning towards configuring Webpack to stop using module for better Node.js compatibility. But for a proper fix where both are able to use ESM, without the need for a patch, it will need to be fixed upstream.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could apply this as patch temporarily until it's updated, rather than patching assets-controller:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really like the idea of patching closer to the root cause.

@sahar-fehri To clarify, we'd want to remove this section of the assets-controllers patch altogether (lines 22-36), and instead add a new patch file for cockatiel that contains the changes in the cockatiel PR #102 linked above.

The Webpack issue is really... not great. I also think configuring Webpack would be the preferable solution here. Fixing or patching every upstream package that triggers this issue doesn't seem advisable or feasible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you guys for looking into this 🙏 🙏
Just to clarify; so its okay to keep the patch for cockatiel and merge it just temporarily; until this PR is merged?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realised we need the assets-controller patch regardless, because it won't with the ESM version of cockatiel otherwise anyway. The cockatiel patch would need to be applied to the core repo, requiring a new release, etc.

So I think the easiest way forward for now is to keep this patch as it is, and hope that cockatiel gets updated quickly 😅.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a plan! Technically, anything downstream of assets-controllers would need to have this patch applied, but that's just our two clients so doesn't seem too terrible. In any case, it makes sense to avoid a controller release containing a patch. Hopefully the cockatiel maintainers will be responsive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using modules across ESM/CJS boundaries differs a lot across tools and environments too. Here's some examples: https://github.com/endojs/endo-e2e-tests/blob/main/matrix/table.md

/**
* The list of currencies that can be supplied as the `vsCurrency` parameter to
* the `/spot-prices` endpoint, in lowercase form.
12 changes: 2 additions & 10 deletions lavamoat/browserify/beta/policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -698,8 +698,8 @@
"@ethersproject/contracts": true,
"@ethersproject/providers": true,
"@metamask/abi-utils": true,
"@metamask/assets-controllers>@metamask/base-controller": true,
"@metamask/assets-controllers>@metamask/polling-controller": true,
"@metamask/base-controller": true,
"@metamask/contract-metadata": true,
"@metamask/controller-utils": true,
"@metamask/eth-query": true,
Expand All @@ -715,22 +715,14 @@
"uuid": true
}
},
"@metamask/assets-controllers>@metamask/base-controller": {
"globals": {
"setTimeout": true
},
"packages": {
"immer": true
}
},
"@metamask/assets-controllers>@metamask/polling-controller": {
"globals": {
"clearTimeout": true,
"console.error": true,
"setTimeout": true
},
"packages": {
"@metamask/assets-controllers>@metamask/base-controller": true,
"@metamask/base-controller": true,
"@metamask/snaps-utils>fast-json-stable-stringify": true,
"uuid": true
}
Expand Down
12 changes: 2 additions & 10 deletions lavamoat/browserify/flask/policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -698,8 +698,8 @@
"@ethersproject/contracts": true,
"@ethersproject/providers": true,
"@metamask/abi-utils": true,
"@metamask/assets-controllers>@metamask/base-controller": true,
"@metamask/assets-controllers>@metamask/polling-controller": true,
"@metamask/base-controller": true,
"@metamask/contract-metadata": true,
"@metamask/controller-utils": true,
"@metamask/eth-query": true,
Expand All @@ -715,22 +715,14 @@
"uuid": true
}
},
"@metamask/assets-controllers>@metamask/base-controller": {
"globals": {
"setTimeout": true
},
"packages": {
"immer": true
}
},
"@metamask/assets-controllers>@metamask/polling-controller": {
"globals": {
"clearTimeout": true,
"console.error": true,
"setTimeout": true
},
"packages": {
"@metamask/assets-controllers>@metamask/base-controller": true,
"@metamask/base-controller": true,
"@metamask/snaps-utils>fast-json-stable-stringify": true,
"uuid": true
}
Expand Down
12 changes: 2 additions & 10 deletions lavamoat/browserify/main/policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -698,8 +698,8 @@
"@ethersproject/contracts": true,
"@ethersproject/providers": true,
"@metamask/abi-utils": true,
"@metamask/assets-controllers>@metamask/base-controller": true,
"@metamask/assets-controllers>@metamask/polling-controller": true,
"@metamask/base-controller": true,
"@metamask/contract-metadata": true,
"@metamask/controller-utils": true,
"@metamask/eth-query": true,
Expand All @@ -715,22 +715,14 @@
"uuid": true
}
},
"@metamask/assets-controllers>@metamask/base-controller": {
"globals": {
"setTimeout": true
},
"packages": {
"immer": true
}
},
"@metamask/assets-controllers>@metamask/polling-controller": {
"globals": {
"clearTimeout": true,
"console.error": true,
"setTimeout": true
},
"packages": {
"@metamask/assets-controllers>@metamask/base-controller": true,
"@metamask/base-controller": true,
"@metamask/snaps-utils>fast-json-stable-stringify": true,
"uuid": true
}
Expand Down
12 changes: 2 additions & 10 deletions lavamoat/browserify/mmi/policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -790,8 +790,8 @@
"@ethersproject/contracts": true,
"@ethersproject/providers": true,
"@metamask/abi-utils": true,
"@metamask/assets-controllers>@metamask/base-controller": true,
"@metamask/assets-controllers>@metamask/polling-controller": true,
"@metamask/base-controller": true,
"@metamask/contract-metadata": true,
"@metamask/controller-utils": true,
"@metamask/eth-query": true,
Expand All @@ -807,22 +807,14 @@
"uuid": true
}
},
"@metamask/assets-controllers>@metamask/base-controller": {
"globals": {
"setTimeout": true
},
"packages": {
"immer": true
}
},
"@metamask/assets-controllers>@metamask/polling-controller": {
"globals": {
"clearTimeout": true,
"console.error": true,
"setTimeout": true
},
"packages": {
"@metamask/assets-controllers>@metamask/base-controller": true,
"@metamask/base-controller": true,
"@metamask/snaps-utils>fast-json-stable-stringify": true,
"uuid": true
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@
"@metamask/address-book-controller": "^6.0.0",
"@metamask/announcement-controller": "^7.0.0",
"@metamask/approval-controller": "^7.0.0",
"@metamask/assets-controllers": "^37.0.0",
"@metamask/assets-controllers": "patch:@metamask/assets-controllers@npm%3A38.2.0#~/.yarn/patches/@metamask-assets-controllers-npm-38.2.0-40af2afaa7.patch",
"@metamask/base-controller": "^7.0.0",
"@metamask/bitcoin-wallet-snap": "^0.6.0",
"@metamask/browser-passworder": "^4.3.0",
Expand Down
1 change: 1 addition & 0 deletions privacy-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"static.cx.metamask.io",
"swap.api.cx.metamask.io",
"test.metamask-phishing.io",
"thumb.canalplus.pro",
sahar-fehri marked this conversation as resolved.
Show resolved Hide resolved
"token.api.cx.metamask.io",
sahar-fehri marked this conversation as resolved.
Show resolved Hide resolved
"tokens.api.cx.metamask.io",
"tx-sentinel-ethereum-mainnet.api.cx.metamask.io",
Expand Down
88 changes: 63 additions & 25 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4861,22 +4861,22 @@ __metadata:
languageName: node
linkType: hard

"@metamask/assets-controllers@npm:^37.0.0":
version: 37.0.0
resolution: "@metamask/assets-controllers@npm:37.0.0"
"@metamask/assets-controllers@npm:38.2.0":
version: 38.2.0
resolution: "@metamask/assets-controllers@npm:38.2.0"
dependencies:
"@ethereumjs/util": "npm:^8.1.0"
"@ethersproject/address": "npm:^5.7.0"
"@ethersproject/bignumber": "npm:^5.7.0"
"@ethersproject/contracts": "npm:^5.7.0"
"@ethersproject/providers": "npm:^5.7.0"
"@metamask/abi-utils": "npm:^2.0.3"
"@metamask/base-controller": "npm:^6.0.2"
"@metamask/base-controller": "npm:^7.0.1"
"@metamask/contract-metadata": "npm:^2.4.0"
"@metamask/controller-utils": "npm:^11.0.2"
"@metamask/controller-utils": "npm:^11.3.0"
"@metamask/eth-query": "npm:^4.0.0"
"@metamask/metamask-eth-abis": "npm:^3.1.1"
"@metamask/polling-controller": "npm:^9.0.1"
"@metamask/polling-controller": "npm:^10.0.1"
"@metamask/rpc-errors": "npm:^6.3.1"
"@metamask/utils": "npm:^9.1.0"
"@types/bn.js": "npm:^5.1.5"
Expand All @@ -4893,9 +4893,47 @@ __metadata:
"@metamask/accounts-controller": ^18.0.0
"@metamask/approval-controller": ^7.0.0
"@metamask/keyring-controller": ^17.0.0
"@metamask/network-controller": ^20.0.0
"@metamask/network-controller": ^21.0.0
"@metamask/preferences-controller": ^13.0.0
checksum: 10/96ae724a002289e4df97bab568e0bba4d28ef18320298b12d828fc3b58c58ebc54b9f9d659c5e6402aad82088b699e52469d897dd4356e827e35b8f8cebb4483
languageName: node
linkType: hard

"@metamask/assets-controllers@patch:@metamask/assets-controllers@npm%3A38.2.0#~/.yarn/patches/@metamask-assets-controllers-npm-38.2.0-40af2afaa7.patch":
version: 38.2.0
resolution: "@metamask/assets-controllers@patch:@metamask/assets-controllers@npm%3A38.2.0#~/.yarn/patches/@metamask-assets-controllers-npm-38.2.0-40af2afaa7.patch::version=38.2.0&hash=e1c8b7"
dependencies:
"@ethereumjs/util": "npm:^8.1.0"
"@ethersproject/address": "npm:^5.7.0"
"@ethersproject/bignumber": "npm:^5.7.0"
"@ethersproject/contracts": "npm:^5.7.0"
"@ethersproject/providers": "npm:^5.7.0"
"@metamask/abi-utils": "npm:^2.0.3"
"@metamask/base-controller": "npm:^7.0.1"
"@metamask/contract-metadata": "npm:^2.4.0"
"@metamask/controller-utils": "npm:^11.3.0"
"@metamask/eth-query": "npm:^4.0.0"
"@metamask/metamask-eth-abis": "npm:^3.1.1"
"@metamask/polling-controller": "npm:^10.0.1"
"@metamask/rpc-errors": "npm:^6.3.1"
"@metamask/utils": "npm:^9.1.0"
"@types/bn.js": "npm:^5.1.5"
"@types/uuid": "npm:^8.3.0"
async-mutex: "npm:^0.5.0"
bn.js: "npm:^5.2.1"
cockatiel: "npm:^3.1.2"
immer: "npm:^9.0.6"
lodash: "npm:^4.17.21"
multiformats: "npm:^13.1.0"
single-call-balance-checker-abi: "npm:^1.0.0"
uuid: "npm:^8.3.2"
peerDependencies:
"@metamask/accounts-controller": ^18.0.0
"@metamask/approval-controller": ^7.0.0
"@metamask/keyring-controller": ^17.0.0
"@metamask/network-controller": ^21.0.0
"@metamask/preferences-controller": ^13.0.0
checksum: 10/89798930cb80a134263ce82db736feebd064fe6c999ddcf41ca86fad81cfadbb9e37d1919a6384aaf6d3aa0cb520684e7b8228da3b9bc1e70e7aea174a69c4ac
checksum: 10/c4f047cd41a2e8b2cc8e9fd6741724d0c220674e6d898a464ef71e31c9f42fb6355016b6d9fc14a85aba3e9ceecf6de6e14730a264b99b866e0f02286a09f0b3
languageName: node
linkType: hard

Expand Down Expand Up @@ -5983,6 +6021,22 @@ __metadata:
languageName: node
linkType: hard

"@metamask/polling-controller@npm:^10.0.1":
version: 10.0.1
resolution: "@metamask/polling-controller@npm:10.0.1"
dependencies:
"@metamask/base-controller": "npm:^7.0.1"
"@metamask/controller-utils": "npm:^11.3.0"
"@metamask/utils": "npm:^9.1.0"
"@types/uuid": "npm:^8.3.0"
fast-json-stable-stringify: "npm:^2.1.0"
uuid: "npm:^8.3.2"
peerDependencies:
"@metamask/network-controller": ^21.0.0
checksum: 10/25c11e65eeccb08a2b4b7dec21ccabb4b797907edb03a1534ebacb87d0754a3ade52aad061aad8b3ac23bfc39917c0d61b9734e32bc748c210b2997410ae45a9
languageName: node
linkType: hard

"@metamask/polling-controller@npm:^8.0.0":
version: 8.0.0
resolution: "@metamask/polling-controller@npm:8.0.0"
Expand All @@ -6000,22 +6054,6 @@ __metadata:
languageName: node
linkType: hard

"@metamask/polling-controller@npm:^9.0.1":
version: 9.0.1
resolution: "@metamask/polling-controller@npm:9.0.1"
dependencies:
"@metamask/base-controller": "npm:^6.0.2"
"@metamask/controller-utils": "npm:^11.0.2"
"@metamask/utils": "npm:^9.1.0"
"@types/uuid": "npm:^8.3.0"
fast-json-stable-stringify: "npm:^2.1.0"
uuid: "npm:^8.3.2"
peerDependencies:
"@metamask/network-controller": ^20.0.0
checksum: 10/e9e8c51013290a2e4b2817ba1e0915783474f6a55fe614e20acf92bf707e300bec1fa612c8019ae9afe9635d018fb5d5b106c8027446ba12767220db91cf1ee5
languageName: node
linkType: hard

"@metamask/post-message-stream@npm:^8.0.0, @metamask/post-message-stream@npm:^8.1.1":
version: 8.1.1
resolution: "@metamask/post-message-stream@npm:8.1.1"
Expand Down Expand Up @@ -26079,7 +26117,7 @@ __metadata:
"@metamask/announcement-controller": "npm:^7.0.0"
"@metamask/api-specs": "npm:^0.9.3"
"@metamask/approval-controller": "npm:^7.0.0"
"@metamask/assets-controllers": "npm:^37.0.0"
"@metamask/assets-controllers": "patch:@metamask/assets-controllers@npm%3A38.2.0#~/.yarn/patches/@metamask-assets-controllers-npm-38.2.0-40af2afaa7.patch"
"@metamask/auto-changelog": "npm:^2.1.0"
"@metamask/base-controller": "npm:^7.0.0"
"@metamask/bitcoin-wallet-snap": "npm:^0.6.0"
Expand Down