Skip to content

Conversation

@zerosnacks
Copy link
Member

@zerosnacks zerosnacks commented Oct 27, 2025

Motivation

Closes: #8693

Solution

Adds a browser wallet interface for Foundry.

Currently support transaction signing for:

  • cast send

And message signing and typed data (EIP712) signing for:

  • cast wallet sign

To test, build the branch:

To test Rabby / Metamask, load up the private key of Alice: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

$ anvil
$ cast send 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 --value 10 --rpc-url https://mainnet.base.org --chain-id 8453 --browser

To test Porto, load up a wallet with a balance on Base:

$ cast send 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 --value 10 --rpc-url https://mainnet.base.org --chain-id 8453 --browser

For development mode add the --browser-disable-open and --browser-development flags.

git clone https://github.com/foundry-rs/foundry-browser-wallet
pnpm install
pnpm dev

To test the sign typed data / message

$ anvil
$ cast wallet sign \
  --browser \
  --data \
  '{
    "domain": {
      "name": "Foundry",
      "version": "1",
      "chainId": 31337
    },
    "types": {
      "Mail": [
        { "name": "from", "type": "address" },
        { "name": "to", "type": "address" },
        { "name": "contents", "type": "string" }
      ]
    },
    "primaryType": "Mail",
    "message": {
      "from": "0x0000000000000000000000000000000000000001",
      "to": "0x0000000000000000000000000000000000000002",
      "contents": "Hello Foundry!"
    }
  }'

Security

It has number of security features:

  • A CORS layer enforcing that only the exact port on 127.0.0.1 can load up the page
  • A strict CSP (whilst permitting RPC communication)
  • A session token that gets injected into main.js and is required to be passed in the header and the CSP enforces no other page can load the index.html. This prevents random processes from interacting with the API (the session token is required for all endpoints).

Considering the server is short-lived I think this should limit the attack surface to a significant degree.

Updating the interface

You can create a release as follows

Screenshot from 2025-11-03 18-23-09

This yields a release

Screenshot from 2025-11-03 18-25-36

Then download and unzip the dist.tar.gz and update the build files & commit

This could also be automated in a sync workflow similar to how we update forge-std, I haven't gotten around to that just yet.

PR Checklist

  • Added Tests
  • Added Documentation
  • Breaking changes

@zerosnacks zerosnacks marked this pull request as ready for review October 31, 2025 15:18
@akshatmittal
Copy link
Contributor

Only took us 4 years to have an alternative to Truffle Dashboard! Very much looking forward to this!

Something to note (from someone who worked on this years ago): It is generally preferred to use the Browser RPC for all interactions, including onchain reads as well as receipts. Receipts is the obvious one since not all wallets give you the canonical receipt but some give you a namespaced hash (most common example is Safe Wallet). RPC interactions because some wallets apply additional state changes before execution, as well as ordered-transaction-priority.

(Also would be down to help with the interface if that's useful!)

@zerosnacks
Copy link
Member Author

Hi @akshatmittal, that's great to hear!

I've now put it up for an initial review for the core team, once it is merged we gladly accept external contributions to improve the interface and feature set.

Copy link
Contributor

@onbjerg onbjerg left a comment

Choose a reason for hiding this comment

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

how do we rebuild the frontend?

@zerosnacks
Copy link
Member Author

zerosnacks commented Nov 3, 2025

Updated the description

how do we rebuild the frontend?

You can create a release as follows:

Screenshot from 2025-11-03 18-23-09

This yields a release

Screenshot from 2025-11-03 18-25-36

You can then download and unzip the dist.tar.gz and update the build files & commit

This could also be automated in a sync workflow similar to how we update forge-std, I haven't gotten around to that just yet.

@zerosnacks zerosnacks requested a review from onbjerg November 3, 2025 19:29
return Err(BrowserWalletError::Timeout { operation: "Transaction" });
}

tokio::time::sleep(Duration::from_millis(100)).await;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: this works, but i believe u could listen to events by using tokio::sync::watch

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

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

feat(wallets): add passkey, browser extension wallets and WalletConnect support for signing operations

6 participants