Skip to content

feat: add @metamask/foundryup package #5810

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

Open
wants to merge 45 commits into
base: main
Choose a base branch
from
Open

Conversation

davidmurdoch
Copy link

@davidmurdoch davidmurdoch commented May 14, 2025

Explanation

This PR introduces a JavaScript-based foundryup installer that simplifies the installation of Foundry toolchain binaries—Anvil, Cast, Forge, and Chisel. The installer is designed to be cross-platform and work across macOS, Linux, and Windows, supporting both ARM and AMD architectures.

It's been used in the MetaMask Extension for a few months now: MetaMask/metamask-extension#28393

References

Changelog

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed, highlighting breaking changes as necessary
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes

Copy link

socket-security bot commented May 14, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​types/​unzipper@​0.10.111001006878100
Addedunzipper@​0.12.310010010079100
Updatedyaml@​2.5.0 ⏵ 2.8.0100 +110010088100

View full report

@cortisiko
Copy link
Member

@metamaskbot publish-preview

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/accounts-controller": "29.0.0-preview-c1fef6e5",
  "@metamask-previews/address-book-controller": "6.0.3-preview-c1fef6e5",
  "@metamask-previews/announcement-controller": "7.0.3-preview-c1fef6e5",
  "@metamask-previews/app-metadata-controller": "1.0.0-preview-c1fef6e5",
  "@metamask-previews/approval-controller": "7.1.3-preview-c1fef6e5",
  "@metamask-previews/assets-controllers": "63.0.0-preview-c1fef6e5",
  "@metamask-previews/base-controller": "8.0.1-preview-c1fef6e5",
  "@metamask-previews/bridge-controller": "25.0.0-preview-c1fef6e5",
  "@metamask-previews/bridge-status-controller": "21.0.0-preview-c1fef6e5",
  "@metamask-previews/build-utils": "3.0.3-preview-c1fef6e5",
  "@metamask-previews/chain-agnostic-permission": "0.6.0-preview-c1fef6e5",
  "@metamask-previews/composable-controller": "11.0.0-preview-c1fef6e5",
  "@metamask-previews/controller-utils": "11.8.0-preview-c1fef6e5",
  "@metamask-previews/delegation-controller": "0.3.0-preview-c1fef6e5",
  "@metamask-previews/earn-controller": "0.14.0-preview-c1fef6e5",
  "@metamask-previews/eip1193-permission-middleware": "0.1.0-preview-c1fef6e5",
  "@metamask-previews/ens-controller": "16.0.0-preview-c1fef6e5",
  "@metamask-previews/eth-json-rpc-provider": "4.1.8-preview-c1fef6e5",
  "@metamask-previews/foundryup": "0.0.0-preview-c1fef6e5",
  "@metamask-previews/gas-fee-controller": "23.0.0-preview-c1fef6e5",
  "@metamask-previews/json-rpc-engine": "10.0.3-preview-c1fef6e5",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.7-preview-c1fef6e5",
  "@metamask-previews/keyring-controller": "22.0.0-preview-c1fef6e5",
  "@metamask-previews/logging-controller": "6.0.4-preview-c1fef6e5",
  "@metamask-previews/message-manager": "12.0.1-preview-c1fef6e5",
  "@metamask-previews/multichain": "4.0.0-preview-c1fef6e5",
  "@metamask-previews/multichain-api-middleware": "0.2.0-preview-c1fef6e5",
  "@metamask-previews/multichain-network-controller": "0.7.0-preview-c1fef6e5",
  "@metamask-previews/multichain-transactions-controller": "0.11.0-preview-c1fef6e5",
  "@metamask-previews/name-controller": "8.0.3-preview-c1fef6e5",
  "@metamask-previews/network-controller": "23.4.0-preview-c1fef6e5",
  "@metamask-previews/notification-services-controller": "8.0.0-preview-c1fef6e5",
  "@metamask-previews/permission-controller": "11.0.6-preview-c1fef6e5",
  "@metamask-previews/permission-log-controller": "3.0.3-preview-c1fef6e5",
  "@metamask-previews/phishing-controller": "12.5.0-preview-c1fef6e5",
  "@metamask-previews/polling-controller": "13.0.0-preview-c1fef6e5",
  "@metamask-previews/preferences-controller": "18.0.0-preview-c1fef6e5",
  "@metamask-previews/profile-sync-controller": "15.0.0-preview-c1fef6e5",
  "@metamask-previews/queued-request-controller": "10.0.0-preview-c1fef6e5",
  "@metamask-previews/rate-limit-controller": "6.0.3-preview-c1fef6e5",
  "@metamask-previews/remote-feature-flag-controller": "1.6.0-preview-c1fef6e5",
  "@metamask-previews/sample-controllers": "0.1.0-preview-c1fef6e5",
  "@metamask-previews/selected-network-controller": "22.0.0-preview-c1fef6e5",
  "@metamask-previews/signature-controller": "29.0.0-preview-c1fef6e5",
  "@metamask-previews/token-search-discovery-controller": "3.1.0-preview-c1fef6e5",
  "@metamask-previews/transaction-controller": "56.0.0-preview-c1fef6e5",
  "@metamask-previews/user-operation-controller": "35.0.0-preview-c1fef6e5"
}

@cortisiko
Copy link
Member

Update on the changes I made to this PR:

  • I successfully ran this package as an executable in the mobile repository. The e2e tests ran with Anvil and passed: https://app.bitrise.io/build/f2b009b6-5e12-407f-ac77-484240cb064e
  • The default unit test coverage is 100%. I added a few more tests, which put our coverage around 55%. We can continue to strive for 100% coverage. In the meantime, I adjusted the test coverage threshold to 50%.
  • I added jsdocs for the files that were missing them.

The challenge i am facing now is this linting error Do not import Node.js builtin module "node:process"

I am unsure on how to handle it. I will post a message in the wallet framework channel to get some guidance.

@cortisiko cortisiko marked this pull request as ready for review May 28, 2025 01:29
@cortisiko cortisiko requested a review from a team as a code owner May 28, 2025 01:52
@cortisiko
Copy link
Member

@metamaskbot publish-preview

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/accounts-controller": "29.0.0-preview-de21a3fe",
  "@metamask-previews/address-book-controller": "6.0.3-preview-de21a3fe",
  "@metamask-previews/announcement-controller": "7.0.3-preview-de21a3fe",
  "@metamask-previews/app-metadata-controller": "1.0.0-preview-de21a3fe",
  "@metamask-previews/approval-controller": "7.1.3-preview-de21a3fe",
  "@metamask-previews/assets-controllers": "65.0.0-preview-de21a3fe",
  "@metamask-previews/base-controller": "8.0.1-preview-de21a3fe",
  "@metamask-previews/bridge-controller": "28.0.0-preview-de21a3fe",
  "@metamask-previews/bridge-status-controller": "25.0.0-preview-de21a3fe",
  "@metamask-previews/build-utils": "3.0.3-preview-de21a3fe",
  "@metamask-previews/chain-agnostic-permission": "0.7.0-preview-de21a3fe",
  "@metamask-previews/composable-controller": "11.0.0-preview-de21a3fe",
  "@metamask-previews/controller-utils": "11.9.0-preview-de21a3fe",
  "@metamask-previews/delegation-controller": "0.3.0-preview-de21a3fe",
  "@metamask-previews/earn-controller": "0.14.0-preview-de21a3fe",
  "@metamask-previews/eip1193-permission-middleware": "0.1.0-preview-de21a3fe",
  "@metamask-previews/ens-controller": "16.0.0-preview-de21a3fe",
  "@metamask-previews/error-reporting-service": "0.0.0-preview-de21a3fe",
  "@metamask-previews/eth-json-rpc-provider": "4.1.8-preview-de21a3fe",
  "@metamask-previews/foundryup": "0.0.0-preview-de21a3fe",
  "@metamask-previews/gas-fee-controller": "23.0.0-preview-de21a3fe",
  "@metamask-previews/json-rpc-engine": "10.0.3-preview-de21a3fe",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.7-preview-de21a3fe",
  "@metamask-previews/keyring-controller": "22.0.0-preview-de21a3fe",
  "@metamask-previews/logging-controller": "6.0.4-preview-de21a3fe",
  "@metamask-previews/message-manager": "12.0.1-preview-de21a3fe",
  "@metamask-previews/multichain": "4.1.0-preview-de21a3fe",
  "@metamask-previews/multichain-api-middleware": "0.4.0-preview-de21a3fe",
  "@metamask-previews/multichain-network-controller": "0.7.0-preview-de21a3fe",
  "@metamask-previews/multichain-transactions-controller": "1.0.0-preview-de21a3fe",
  "@metamask-previews/name-controller": "8.0.3-preview-de21a3fe",
  "@metamask-previews/network-controller": "23.5.0-preview-de21a3fe",
  "@metamask-previews/notification-services-controller": "8.0.0-preview-de21a3fe",
  "@metamask-previews/permission-controller": "11.0.6-preview-de21a3fe",
  "@metamask-previews/permission-log-controller": "3.0.3-preview-de21a3fe",
  "@metamask-previews/phishing-controller": "12.5.0-preview-de21a3fe",
  "@metamask-previews/polling-controller": "13.0.0-preview-de21a3fe",
  "@metamask-previews/preferences-controller": "18.0.0-preview-de21a3fe",
  "@metamask-previews/profile-sync-controller": "15.0.0-preview-de21a3fe",
  "@metamask-previews/queued-request-controller": "10.0.0-preview-de21a3fe",
  "@metamask-previews/rate-limit-controller": "6.0.3-preview-de21a3fe",
  "@metamask-previews/remote-feature-flag-controller": "1.6.0-preview-de21a3fe",
  "@metamask-previews/sample-controllers": "0.1.0-preview-de21a3fe",
  "@metamask-previews/selected-network-controller": "22.1.0-preview-de21a3fe",
  "@metamask-previews/signature-controller": "29.0.0-preview-de21a3fe",
  "@metamask-previews/token-search-discovery-controller": "3.2.0-preview-de21a3fe",
  "@metamask-previews/transaction-controller": "56.2.0-preview-de21a3fe",
  "@metamask-previews/user-operation-controller": "35.0.0-preview-de21a3fe"
}

Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

Hey thanks for the PR, just had questions about some things. I realize that some of the comments I left may require some followup. I will do that soon but thought I'd jot down my thoughts in the meantime.

@@ -24,6 +24,11 @@ const config = createConfig([
// e.g. `txreceipt_status`, `signTypedData_v4`, `token_id`
camelcase: 'off',
'id-length': 'off',
'import-x/no-nodejs-modules': 'off',
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice if we didn't have to add these rules globally. It's one of our (soft) goals to simplify this file eventually.

Can you explain why these are needed? I can probably guess why, but just want to make sure.

Copy link
Member

Choose a reason for hiding this comment

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

ah so the rule is disabled because this is a Node.js package that needs to use Node.js built-in modules.

Copy link
Author

Choose a reason for hiding this comment

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

not sure why these needed to be added. cc @cortisiko ?

@@ -0,0 +1 @@
enableGlobalCache: false
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we adding this?

Copy link
Author

@davidmurdoch davidmurdoch May 28, 2025

Choose a reason for hiding this comment

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

This is the default yarn setting on Extension, so it best replicates how it is used in practice right now.

@@ -0,0 +1 @@
.metamask
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we adding this?

Copy link
Author

Choose a reason for hiding this comment

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

.metamask is the name of the root directory for the cache for the binaries we download

```

Kind of weird, but it seems to work okay. You can probably use `npx anvil` in place of `node_modules/.bin/anvil`, but
getting it to work in all scenarios (cross platform and in CI) wasn't straightforward. `yarn bin anvil` doesn't work
Copy link
Contributor

Choose a reason for hiding this comment

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

Does yarn dlx anvil work instead? That's the equivalent to npx in Yarn v2+.

Copy link
Author

Choose a reason for hiding this comment

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

IIRC, dlx isn't exactly equivalent. I think it was that npx executes anything in the .bin directory, dlx only executes executables declared by the package.jsons's bin. I can't check right now.

// An object that configures minimum threshold enforcement for coverage results
coverageThreshold: {
global: {
branches: 50,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a way we can start with 100% test coverage instead of 50%? If the threshold is below 100%, it ends up being extremely annoying in the future, as any new gaps in coverage that are introduced in the future are very difficult to find.

Copy link
Member

Choose a reason for hiding this comment

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

Hey @mcmire, the reason for adjusting the threshold is that we need a bit more flexibility to reach 100% coverage over time. For now, the team's goal was to hit at least 50%, and we're currently at around 55%, so we're above that baseline.

Since I have another PR that depends on this package, would you be open to us following up in a separate PR focused solely on bringing coverage to 100%?

Copy link
Author

Choose a reason for hiding this comment

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

I'd love to, and normally wouldn't put a PR with such low coverage. But I didn't want to keep blocking Mobile. I won't be able to do any more work for at least a month. Not sure if @cortisiko has the time to increase coverage.

@@ -0,0 +1,6 @@
declare module 'fs' {
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, I'd like to avoid ambient types if we can. I wonder if we're using an older version of @types/node?

Copy link
Author

Choose a reason for hiding this comment

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

I'd like to as well, but the correct types were missing :-)

@@ -0,0 +1,17 @@
import 'unzipper';
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there no @types/unzipper?

Copy link
Author

Choose a reason for hiding this comment

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

they are incomplete types.

@@ -63,7 +63,7 @@ main().catch((error) => {
* The entrypoint to this script.
*/
async function main() {
const { cache, fix, quiet } = parseCommandLineArguments();
const { cache, fix, quiet } = await parseCommandLineArguments();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why were these changes added?

Copy link
Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

oh good observation. I was going down a rabbit hole of addressing linting issue. This particular change was to address: 'TSError: ⨯ Unable to compile TypeScript: .

"extends": "../../tsconfig.packages.build.json",
"compilerOptions": {
"baseUrl": "./",
"lib": ["ES2021", "DOM"],
Copy link
Contributor

Choose a reason for hiding this comment

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

  • Why is DOM needed here if this script is intended to run on Node?
  • Why is ES2021 needed here? (I can probably guess why, but am curious)

Copy link
Author

Choose a reason for hiding this comment

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

I think ES2021 was the minimum version that worked with the existing version of this package that we are using in Metamask Extension. Not sure why DOM is added 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants