Created
March 4, 2026 21:38
-
-
Save johngrantuk/753ead94adf420400aa55afce4e03bee to your computer and use it in GitHub Desktop.
Example of JSON Export for Metamask
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "walletId": "metamask", | |
| "types": [ | |
| "SOFTWARE" | |
| ], | |
| "variants": [ | |
| "MOBILE", | |
| "BROWSER" | |
| ], | |
| "displayName": "MetaMask", | |
| "description": "MetaMask is a popular multichain wallet created by Consensys and that has been around for a long time. It is a jack-of-all-trades wallet that can be extended through MetaMask Snaps.", | |
| "lastUpdated": "2025-10-13", | |
| "stage": "Stage 0", | |
| "stageBreakdown": [ | |
| { | |
| "stageId": "stage:software-0", | |
| "label": "Stage 0", | |
| "passedCount": 1, | |
| "totalCount": 1, | |
| "status": "PASS", | |
| "criteriaGroups": [ | |
| { | |
| "description": "The wallet's source code can be reviewed by the public.", | |
| "criteria": [ | |
| { | |
| "criterionId": "source_available", | |
| "attributeId": "sourceVisibility", | |
| "attributeDisplayName": "Source visibility", | |
| "description": "The wallet's source code is publicly available.", | |
| "rating": "PASS" | |
| } | |
| ] | |
| } | |
| ] | |
| }, | |
| { | |
| "stageId": "stage:software-1", | |
| "label": "Stage 1", | |
| "passedCount": 6, | |
| "totalCount": 9, | |
| "status": "PARTIAL", | |
| "criteriaGroups": [ | |
| { | |
| "description": "The wallet provides a basic level of security.", | |
| "criteria": [ | |
| { | |
| "criterionId": "security_audit_1y", | |
| "attributeId": "securityAudits", | |
| "attributeDisplayName": "Security audits", | |
| "description": "The wallet has passed a security audit within the last year.", | |
| "rating": "PASS" | |
| }, | |
| { | |
| "criterionId": "hardware_wallet_subset", | |
| "attributeId": null, | |
| "attributeDisplayName": "Hardware Wallet Subset", | |
| "description": "The wallet supports hardware wallets from at least three manufacturers.", | |
| "rating": "PASS" | |
| }, | |
| { | |
| "criterionId": "chain_verification", | |
| "attributeId": "chainVerification", | |
| "attributeDisplayName": "Chain verification", | |
| "description": "The wallet verifies the integrity of the L1 chain.", | |
| "rating": "FAIL" | |
| } | |
| ] | |
| }, | |
| { | |
| "description": "The wallet offers a minimal level of privacy to its users.", | |
| "criteria": [ | |
| { | |
| "criterionId": "private_transfers", | |
| "attributeId": "privateTransfers", | |
| "attributeDisplayName": "Private token transfers", | |
| "description": "Token transfers and balances are private by default.", | |
| "rating": "FAIL" | |
| } | |
| ] | |
| }, | |
| { | |
| "description": "The wallet does not lock the user in and lets the user remain in full control of their account.", | |
| "criteria": [ | |
| { | |
| "criterionId": "account_portability", | |
| "attributeId": "accountPortability", | |
| "attributeDisplayName": "Account portability", | |
| "description": "The user can freely export their account to another wallet.", | |
| "rating": "PASS" | |
| }, | |
| { | |
| "criterionId": "support_own_node", | |
| "attributeId": null, | |
| "attributeDisplayName": "Support Own Node", | |
| "description": "The wallet allows the user to use their own node when interacting with the L1 chain.", | |
| "rating": "PASS" | |
| } | |
| ] | |
| }, | |
| { | |
| "description": "The wallet's development process and internal workings are transparent to the user.", | |
| "criteria": [ | |
| { | |
| "criterionId": "foss", | |
| "attributeId": "openSource", | |
| "attributeDisplayName": "Source code license", | |
| "description": "The wallet is licensed under a Free and Open Source Software (FOSS) license.", | |
| "rating": "FAIL" | |
| } | |
| ] | |
| }, | |
| { | |
| "description": "The wallet is aligned with basic Ethereum ecosystem best practices for usability.", | |
| "criteria": [ | |
| { | |
| "criterionId": "address_resolution", | |
| "attributeId": "addressResolution", | |
| "attributeDisplayName": "Address resolution", | |
| "description": "The wallet can send funds to human-readable Ethereum addresses (e.g. ENS).", | |
| "rating": "PASS" | |
| }, | |
| { | |
| "criterionId": "browser_integration", | |
| "attributeId": "browserIntegration", | |
| "attributeDisplayName": "Browser integration", | |
| "description": "The wallet complies with web browser integration standards.", | |
| "rating": "PASS" | |
| } | |
| ] | |
| } | |
| ] | |
| }, | |
| { | |
| "stageId": "stage:software-2", | |
| "label": "Stage 2", | |
| "passedCount": 5, | |
| "totalCount": 10, | |
| "status": "PARTIAL", | |
| "criteriaGroups": [ | |
| { | |
| "description": "The wallet provides a strong level of security.", | |
| "criteria": [ | |
| { | |
| "criterionId": "bug_bounty_program", | |
| "attributeId": null, | |
| "attributeDisplayName": "Bug Bounty Program", | |
| "description": "The wallet is part of a funded Bug Bounty program.", | |
| "rating": "UNRATED" | |
| } | |
| ] | |
| }, | |
| { | |
| "description": "The wallet collects no more information about its users by default than a web browser does.", | |
| "criteria": [ | |
| { | |
| "criterionId": "address_privacy", | |
| "attributeId": "addressCorrelation", | |
| "attributeDisplayName": "Wallet address privacy", | |
| "description": "Wallet addresses are not correlatable with other user information.", | |
| "rating": "UNRATED" | |
| }, | |
| { | |
| "criterionId": "multi_address_correlation", | |
| "attributeId": "multiAddressCorrelation", | |
| "attributeDisplayName": "Multi-address privacy", | |
| "description": "Multiple wallet addresses are not correlatable with one another.", | |
| "rating": "UNRATED" | |
| } | |
| ] | |
| }, | |
| { | |
| "description": "The wallet does not lock the user in and lets the user remain in full control of their account.", | |
| "criteria": [ | |
| { | |
| "criterionId": "transaction_inclusion", | |
| "attributeId": "transactionInclusion", | |
| "attributeDisplayName": "Transaction inclusion", | |
| "description": "The wallet can withdraw L2 funds to Ethereum L1 without relying on intermediaries.", | |
| "rating": "UNRATED" | |
| }, | |
| { | |
| "criterionId": "support_own_chains", | |
| "attributeId": null, | |
| "attributeDisplayName": "Support Own Chains", | |
| "description": "The wallet allows the user to use their own node when interacting with any chain.", | |
| "rating": "PASS" | |
| } | |
| ] | |
| }, | |
| { | |
| "description": "The wallet's development process and internal workings are transparent to the user.", | |
| "criteria": [ | |
| { | |
| "criterionId": "funding", | |
| "attributeId": "funding", | |
| "attributeDisplayName": "Funding", | |
| "description": "The wallet's funding sources and revenue model are public and transparent.", | |
| "rating": "PASS" | |
| }, | |
| { | |
| "criterionId": "fee_transparency", | |
| "attributeId": "feeTransparency", | |
| "attributeDisplayName": "Fee transparency", | |
| "description": "The fees charged by the wallet are made transparent to the user at all times.", | |
| "rating": "PASS" | |
| } | |
| ] | |
| }, | |
| { | |
| "description": "The wallet is aligned with advanced Ethereum ecosystem best practices for usability.", | |
| "criteria": [ | |
| { | |
| "criterionId": "chain_specific_address_resolution", | |
| "attributeId": "addressResolution", | |
| "attributeDisplayName": "Address resolution", | |
| "description": "The wallet supports chain-specific human-readable addresses (e.g. ERC-7828, ERC-7831).", | |
| "rating": "FAIL" | |
| }, | |
| { | |
| "criterionId": "account_abstraction", | |
| "attributeId": "accountAbstraction", | |
| "attributeDisplayName": "Account Abstraction", | |
| "description": "The wallet is Account Abstraction ready.", | |
| "rating": "PASS" | |
| }, | |
| { | |
| "criterionId": "transaction_batching", | |
| "attributeId": "transactionBatching", | |
| "attributeDisplayName": "Transaction batching", | |
| "description": "The wallet supports atomic batched transactions.", | |
| "rating": "PASS" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| ], | |
| "website": "https://metamask.io", | |
| "repository": "https://github.com/MetaMask/metamask-extension", | |
| "overall": { | |
| "security": { | |
| "securityAudits": { | |
| "attribute": { | |
| "attributeDisplayName": "Security audits", | |
| "attributeId": "securityAudits", | |
| "shortQuestion": "Has the wallet's source code been reviewed by security auditors?", | |
| "whyItMatters": "\nWallets are high-stakes pieces of software that deal with sensitive\nuser data and funds. To ensure that their code is secure, industry best\npractices involve regularly submitting the wallet's source code for audit\nby an independent security auditor. These companies specialize in\nreviewing source code with an eye for security vulnerabilities. They\nreport their findings to the wallet's development team for consideration,\npointing out both flaws and potential security improvements.\n\nThese security audits matter in order to ensure the wallet's source code\nis secure, and remains that way over time. Wallet development teams\ntypically publish such audits so that wallet users can feel safer knowing\nthat the wallet's source code was independently audited.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's security auditing track record evaluated?", | |
| "methodology": "\nWallets are evaluated by their track record of published security audits.\n\nWalletbeat examines the set of published security audits of the wallet.\nTo qualify, a security audit must be publicly available, and must be\nfrom a security auditor that has a traceable corporate entity distinct\nfrom the wallet's own development team.\n\nSecurity audits typically come with one or more security flaws found,\ncategorized by level of severity. Definitions of severity vary across\nauditors, but generally anything \"medium\" or above is worth paying\nattention to.\n\nA wallet gets a passing rating if it has been audited at least once\nwithin the last 365 days, and that all medium-or-higher severity flaws\nthat were found across *all* audits (including older ones) are addressed.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask has undergone a recent security audit with all faults addressed.", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "urls": [ | |
| { | |
| "label": "assets.ctfassets.net", | |
| "url": "https://assets.ctfassets.net/clixtyxoaeas/21m4LE3WLYbgWjc33aDcp2/8252073e115688b1dc1500a9c2d33fe4/metamask-delegator-framework-audit-2024-10.pdf" | |
| } | |
| ] | |
| }, | |
| { | |
| "urls": [ | |
| { | |
| "label": "assets.ctfassets.net", | |
| "url": "https://assets.ctfassets.net/clixtyxoaeas/4sNMB55kkGw6BtAiIn08mm/f1f4a78d3901dd03848d070e15a1ff12/pentest-report_metamask-signing-snap.pdf" | |
| } | |
| ] | |
| }, | |
| { | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/Cyfrin/cyfrin-audit-reports/blob/main/reports/2025-03-18-cyfrin-Metamask-DelegationFramework1-v2.0.pdf" | |
| } | |
| ] | |
| }, | |
| { | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/Cyfrin/cyfrin-audit-reports/blob/main/reports/2025-04-01-cyfrin-Metamask-DelegationFramework2-v2.0.pdf" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "scamPrevention": { | |
| "attribute": { | |
| "attributeDisplayName": "Scam prevention", | |
| "attributeId": "scamPrevention", | |
| "shortQuestion": "Does the wallet warn the user about potential scams?", | |
| "whyItMatters": "Transactions in Ethereum are very difficult to reverse, and there is no shortage of scams. Wallets have a role to play in helping users avoid known scams ahead of the user making the transaction.", | |
| "howIsEvaluated": { | |
| "heading": "How is scam prevention evaluated?", | |
| "methodology": "\nWallets are rated based on whether they alert the user about potential\nscams. This is measured along three scenarios:\n**Does the wallet *warn* the user when...**\n\n* Sending funds to an address the user has never previously sent or\n\treceived funds from before\n* Interacting with a contract that is known to be a scam\n* Interacting with a contract that the user has never previously\n\tinteracted with before\n* Interacting with a contract that has only recently been deployed\n\tonchain\n* Connecting to an app that is known to be a scam\n\nFor payments-focused wallets that do not support interacting with\narbitrary contracts or external applications, only the payment scenario\napplies.\n\nNote that wallets should only *warn* the user about such scenarios, not\noutright *prevent* the user from making such transactions, as preventing\nthem entirely would limit the user's ability to have real sovereignty\nover their own wallet.\n\nWallets are also rated based on whether these warnings are implemented\nin a privacy-preserving manner. Specifically:\n\n* When sending funds, does the lookup for past interactions with that\n\taddress unconditionally reveal the sender and recipient addresses to an\n\texternal provider other than the wallet's default RPC provider for this\n\tchain?\n\n\t* Wallets can implement this feature in a privacy-preserving manner by\n\t\tmaintaining a local set of known addresses.\n\n* When interacting with a contract, does the check whether that contract\n\tis known to be a scam reveal the user's IP address together with the\n\tcontract address about to be interacted with?\n\n\t* This is a privacy leak similar to that of leaking the user's\n\t\tbrowsing history, as contract addresses are usually closely tied to\n\t\tthe application being visited.\n\t* Wallets can implement this feature in a privacy-preserving manner by\n\t\tmaintaining a local, frequently-updated cache of known-scam contract\n\t\taddresses.\n\n* When connecting to an application, does the check whether that\n\tapplication reveal the domain name or URL of the application being used?\n\n\t* If leaking full URLs, this is a privacy leak similar to that of\n\t\tleaking the user's browsing history.\n\t* If leaking domain names only, they must not be linkable to the\n\t\tuser's IP address or Ethereum address.\n\t* Wallets can implement this feature in a privacy-preserving manner by\n\t\tmaintaining a local, frequently-updated cache of known-scam contract\n\t\tURLs, or by looking up such a list based on a domain hash prefix\n\t\tlike [Safe Browsing](https://security.googleblog.com/2022/08/how-hash-based-safe-browsing-works-in.html).\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask warns the user about outgoing transactions to unknown addresses, transactions with potential scam contracts and connections to potential scam applications in a privacy-invasive way.", | |
| "details": "See full details on the wallet page.", | |
| "howToImprove": "\nMetaMask should ensure all scam alerting features are implemented in a privacy-preserving manner.\n\n\n* Checking arbitrary transactions for potential scams should not allow an external service to link your browsing history with your IP or Ethereum address.\n\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask provides address labeling and warns about address poisoning attacks using local address book and transaction history. For enhanced security validation, MetaMask may use Consensys services which share recipient and user addresses along with IP addresses. Users can disable external services to prevent this data sharing.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/configure/privacy/how-to-adjust-metamask-privacy-settings/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "MetaMask uses Blockaid integration to provide privacy-preserving transaction simulation and malicious contract detection without sharing transaction details with parties other than Consensys.", | |
| "urls": [ | |
| { | |
| "label": "metamask.io", | |
| "url": "https://metamask.io/news/latest/metamask-security-alerts-by-blockaid-the-new-normal-for-a-safer-transaction/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "MetaMask maintains a local phishing database to detect malicious apps and websites without revealing browsing activity to external services.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/ms/privacy-and-security/how-to-turn-on-security-alerts/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "Privacy preserving registry of malicious URLs implemented through eth-phishing-detect.", | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/MetaMask/eth-phishing-detect" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "chainVerification": { | |
| "attribute": { | |
| "attributeDisplayName": "Chain verification", | |
| "attributeId": "chainVerification", | |
| "shortQuestion": "Does the wallet verify the integrity of the chain(s) it interacts with?", | |
| "whyItMatters": "\n\"Trust but verify\" is one of the foundational principles of blockchains.\nIt refers to the ability for participants to verify that the chain data\nis valid when they interact with it.\n\nWithout such verification, users rely on trusted external providers to tell\nthem what the state of the blockchain is, similar to the web2 trust model.\nThis allows such external providers to trick wallet users into signing\ntransactions that do not end up having the user's intended effect.\n\nTo avoid this, Ethereum was designed to be verifiable on commodity\nhardware. Using a\n[light client](https://ethereum.org/en/developers/docs/nodes-and-clients/light-clients/),\nthis verification is possible without having to download the entire\nblockchain.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is chain verification evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether or not they integrate a light\nclient for verification of Ethereum L1 state.\n\n*Note*: Walletbeat currently only considers L1 chain state verification\nfor this criterion, not L2s. This is because L2 state verification is\nstill in its infancy. As L2 technology matures, Walletbeat will also\nstart requiring wallets to verify L2 chain state.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask does not verify chain integrity of the Ethereum L1.", | |
| "details": "\nMetaMask does not verify the integrity of the Ethereum L1 blockchain when retrieving chain state or simulating transactions.\n\nUsers may work around this by setting a custom RPC endpoint for the L1 chain and running their own node or external light client.\n", | |
| "howToImprove": "MetaMask should integrate [light client functionality](https://ethereum.org/en/developers/docs/nodes-and-clients/light-clients/) to verify the integrity of Ethereum chain data." | |
| } | |
| }, | |
| "transactionLegibility": { | |
| "attribute": { | |
| "attributeDisplayName": "Transaction Legibility", | |
| "attributeId": "transactionLegibility", | |
| "shortQuestion": "When signing a transaction, does the wallet show transaction details clearly?", | |
| "whyItMatters": "\nTransaction legibility is a critical security feature for wallets that allows users to verify\ntransaction details directly on their wallet's screen/window before signing. This verification\nstep is crucial for preventing attacks where malicious software might attempt to trick users\ninto signing transactions with different parameters than what they intended.\n\nWithout this, users are at the mercy of the app they are interacting with sending them a bad transactions, either because they have a bug, were hacked, or are malicious. Without a signer being able to verify if their transaction is correct, user should not send such a transaction.\n\nFull transaction legibility implementations ensure that all relevant transaction details (recipient\naddress, amount, fees, etc.) are clearly displayed on the wallet screen, EIP-712 message hashes,\nand decoded calldata, allowing users to make informed decisions before authorizing transactions.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet evaluated for clearly showing what users are signing?", | |
| "methodology": "\nWallets are evaluated based on key aspects of transaction legibility, with different criteria for software and hardware wallets:\n\n**Calldata Decoding/Display:**\nThe wallet's ability to decode and display calldata for various transaction types, including:\n- Simple transfers (ETH transfers, ERC-20 transfers, ERC-1155, and ERC-721 transfers)\n- Token approvals\n- DeFi interactions\n- Complex nested transactions\n\nFor software wallets, transaction details are evaluated according to the set of information they display:\n- For transfers (ETH transfers, ERC-20 transfers, ERC-721 transfers, ERC-1155 transfers): gas, nonce, sender, recipient, chain, amount. Some details may be collapsed by default (e.g. 'nonce'), but all of them must be accessible through the UI.\n- Non-transfer transactions (approvals, DeFi contract interactions, Safe multisig nested transactions): gas, nonce, from, chain. In addition, the wallet must explain the transaction outcome visually or in plain language; for example, for ERC-20 approvals, it should explain what token is being approved, for which contract, and for how many tokens.\n- If presented with a transaction that will revert if included onchain, the wallet must detect that the transaction would fail and warn the user beforehand.\n- If presented with a transaction for which the behavior would be nondeterministic based on predictably-changing parameters (e.g. block number), the wallet must detect that the transaction has a nondeterministic outcome and warn the user beforehand.\n\n**Software Wallet Specific Requirements:**\nFor software wallets, calldata must be displayed in multiple formats:\n- Raw hex format: Users can view the raw hexadecimal calldata\n- Formatted output: Users can view decoded, human-readable calldata\n- Copy to clipboard: Users can copy the calldata directly for verification\n\nSoftware wallets must also support calldata decoding for various transaction types, from basic token transfers to complex nested transactions.\n\n**Hardware Wallet Specific Requirements:**\nFor hardware wallets, the signature/transaction information *must* be visible on the hardware wallet device itself. Any data shown on a software wallet component is ignored for hardware wallet ratings.\n\nHardware wallets must also provide data extraction methods to allow users to independently verify transaction data:\n- Visual display: Users can view the data on the hardware wallet screen\n- QR code: Users can scan a QR code displayed on the device to extract data\n- Hashes: Users can compare hashes displayed on the device to verify data\n\n**Rating Criteria:**\n\nFor software wallets:\n- A wallet receives a passing rating if it displays calldata in all three formats (raw hex, formatted, copyable), displays all essential transaction details, and supports complex calldata decoding (including nested transactions).\n- A wallet receives a partial rating if it has some combination of these features but not all, or if calldata decoding data has not been provided.\n- A wallet receives a failing rating if it lacks calldata display capabilities or does not display essential transaction details.\n\nFor hardware wallets:\n- A wallet receives a passing rating if it supports decoding of complex nested transactions, displays all essential transaction details on the device, and provides comprehensive data extraction methods (QR codes and hashes, in addition to visual display).\n- A wallet receives a partial rating if it has some combination of these features (decoding support, transaction details display, or data extraction methods), but not all at the full level.\n- A wallet receives a failing rating if it lacks calldata decoding support, does not display essential transaction details on the device, and provides no effective data extraction methods.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask supports partial transaction legibility.", | |
| "details": "MetaMask supports some transaction legibility features, but not all. The wallet displays basic transaction details but may be missing calldata display formats, clear transaction outcome explanations for complex interactions, or simulation capabilities. Showing full transaction details is crucial for security.\n\n**Calldata Display**\n\n✓ Supported: Raw hex display, Formatted output and Copy to clipboard\n\n\n**Transaction Benchmarks**\n\n✓ Passing: ETH transfer, ERC-20 token transfer, ERC-721 NFT transfer, ERC-1155 token transfer, ZKSync USDC transfer, USDC approval, Aave supply and Failed transaction simulation\n\n⚠ Partial: Safe nested Aave supply (calldata not decoded), Safe nested multisend (calldata not decoded) and Nondeterministic transaction simulation (detected but no warning shown)\n\n\n**Message Signing**\n\n✓ Supported: EIP-712 structured data\n\n✗ Missing: Domain hash, Message hash and Safe hash\n", | |
| "howToImprove": "MetaMask should implement the following improvements:\n\n**Transaction Clarity:** Safe nested Aave supply (calldata not decoded), Safe nested multisend (calldata not decoded) and Nondeterministic transaction simulation (detected but no warning shown)\n\n**Message Signing:** Add support for displaying Domain hash, Message hash and Safe hash" | |
| } | |
| }, | |
| "hardwareWalletSupport": { | |
| "attribute": { | |
| "attributeDisplayName": "Hardware wallet support", | |
| "attributeId": "hardwareWalletSupport", | |
| "shortQuestion": "Does the wallet support connecting to hardware wallets?", | |
| "whyItMatters": "\nHardware wallets are physical devices that store a user's private keys offline,\nproviding an additional layer of security against online threats. By keeping\nprivate keys isolated from internet-connected devices, hardware wallets protect\nusers from malware, phishing attacks, and other security vulnerabilities that\ncould compromise their funds.\n\nWhen a software wallet supports hardware wallets, users can enjoy the\nconvenience and features of the software wallet while maintaining the\nsecurity benefits of keeping their private keys offline. This combination\noffers the best of both worlds: a user-friendly interface with enhanced security.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's hardware wallet support evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether it is possible to use them in\nconjunction with any physically-separate hardware wallet.\nThis means the software wallet must provide the same level of\nfunctionality as when not using a hardware wallet, and the private key\nmust never leave the hardware wallet.\n\nWallets that require the use of a separate software component (e.g.\nWalletConnect to an external desktop application that does the actual\ninterfacing with the hardware device) in order to use the hardware wallet\nget a partial rating. The need for this additional software component\nmeans the user has to do more work to get the hardware wallet working,\nwhich decreases the likelihood that users will actually do so in practice.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports hardware wallets.", | |
| "details": "MetaMask supports the following hardware wallets:\n\n* Ledger (directly via WebUSB)\n* Trezor (directly via WebUSB)\n* GridPlus (directly via WebUSB)\n* Keystone (directly via QR code)\n\t", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask supports Ledger, Trezor, Lattice (GridPlus), Keystone, OneKey, and KeepKey via its Hardware Wallet Hub.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/wallets/hardware-wallet-hub/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "passkeyImplementation": { | |
| "attribute": { | |
| "attributeDisplayName": "Passkey implementation", | |
| "attributeId": "passkeyImplementation", | |
| "shortQuestion": "Does MetaMask use a secure and efficient passkey verification library?", | |
| "whyItMatters": "\nPasskeys provide a secure and phishing-resistant way to authenticate users without relying on seed phrases. \nUsing gas-efficient and well-audited libraries for verification is crucial both for security and cost-effectiveness.\n\nP256 signature verification is computationally expensive on-chain, so using optimized libraries reduces transaction costs.\n\nSome verification libraries have undergone multiple security audits while others may have fewer or no publicly available audits.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's passkey implementation evaluated?", | |
| "methodology": "\nWallets are assessed based on the passkey verification library they use:\n\n1. **Pass (Best)**: Using the most gas-efficient and well-audited library like:\n\t- [Smooth Crypto Lib](https://github.com/get-smooth/crypto-lib)\n\t- [Daimo P256 verifier](https://github.com/daimo-eth/p256-verifier)\n\t- [OpenZeppelin P256 verifier](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/P256.sol)\n\t- [WebAuthn.sol](https://github.com/base/webauthn-sol) which falls back to Fresh Crypto Lib\n\n2. **Partial**: Using libraries that work but are less optimal:\n\t- [Fresh Crypto Lib](https://github.com/rdubois-crypto/FreshCryptoLib)\n\t- Other less common verification libraries\n\n3. **Fail**: Not implementing passkeys or using a non-recognized library.\n\nWallets that don't support smart contract accounts or are hardware wallets are exempt from this rating.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask does not implement passkeys or does not use a recognized verification library.", | |
| "details": "MetaMask either does not implement passkeys or does not use a recognized verification library for P256/R1 curve operations. Passkeys provide a more secure authentication method than traditional passwords, but proper implementation is crucial for security.", | |
| "howToImprove": "MetaMask should implement passkeys using a well-audited verification library such as [Smooth Crypto Lib](https://github.com/get-smooth/crypto-lib) 159K gas." | |
| } | |
| }, | |
| "accountRecovery": { | |
| "attribute": { | |
| "attributeDisplayName": "Account recovery", | |
| "attributeId": "accountRecovery", | |
| "shortQuestion": "How easy does the wallet make it to recover your account?", | |
| "whyItMatters": "\nWhat if you forget your seed phrase?\n\nSelf-custody is difficult and complicated for most normal users, relative\nto typical web2 accounts which often feature easy account recovery\nfeatures. Moreover, losing one's seed phrase can be a devastating\nand irrecoverable financial loss. Some users avoid self-custody due to\nthis concern.\n\n[Guardian-based recovery](https://vitalik.eth.limo/general/2021/01/11/recovery.html)\n(also known as \"Social recovery\") helps make self-custody safe and practical\nfor everyday users. Properly implemented, this keeps users safer while still\nproviding the self-sovereignty benefits of self-custody in the day-to-day.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account recovery evaluated?", | |
| "methodology": "\nWallets are evaluated based on their implementation of\n[guardian-based recovery](https://vitalik.eth.limo/general/2021/01/11/recovery.html).\n\nTo qualify, wallets must implement at least one form of guardian-based\nrecovery. They must also ensure that whatever option the user picks (as allowed by the\nwallet's onboarding flow), all the following prongs are satisfied:\n\n- If the user loses access to their device (which can include\n both their wallet's software and their passkeys), can they still recover their\n\taccount on a separate device?\n- If any single external provider goes out of business, can the user still\n recover their account?\n- If any single external provider is compromised or turns evil, can the\n user's account be taken over by that provider?\n\nThis attribute explicitly does **not** consider the scenario of the user's\nown self-custody key being compromised, as defenses against such scenarios\nare covered by a separate attribute in the Self-Sovereignty category.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "\nMetaMask's account recovery feature cannot be\nrelied upon in multiple scenarios.\n", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "urls": [ | |
| { | |
| "label": "MetaMask account recovery documentation", | |
| "url": "https://support.metamask.io/configure/wallet/social-login" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| "privacy": { | |
| "addressCorrelation": { | |
| "attribute": { | |
| "attributeDisplayName": "Wallet address privacy", | |
| "attributeId": "addressCorrelation", | |
| "shortQuestion": "Is your wallet address linkable to other information about yourself?", | |
| "whyItMatters": "\nYour wallet address is unique and permanent, which makes it easy for applications and companies\nlike Chainalysis to track your activity. In web-privacy terms, it is worse than cookies:\nwallet addresses are permanent, publicly visible, and can even be tracked across multiple\ndevices and websites.\nThe more personal information is linkable to your wallet address, the more effective such\ntracking can be. It is therefore important to use a wallet that protects your information\nfrom being linked to your wallet address.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is wallet address privacy evaluated?", | |
| "methodology": "\nIn order to qualify for a perfect rating on wallet address privacy, a\nwallet must not, *by default*, allow any external entity to link your\nwallet address to any personal information.\n\nAs Walletbeat only considers the wallet's *default* behavior, wallets may\nstill choose to offer features that allow external providers to link wallet\naddresses with personal information, so long as this is done with explicit\nuser opt-in.\n\nTo determine this, Walletbeat looks at the network requests made by\nwallets in their default configuration, and the contents of such requests.\nIf a request contains the user's wallet address, we look at whether it\nalso contains any other personal information, such as the user's name,\npseudonym, email address, phone number, CEX account information, etc.\n\nAdditionally, if such a request is not proxied, then it inherently reveals\nthe user's IP address and ties it with the user's wallet address, which is\nalso personal information.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "UNRATED", | |
| "shortExplanation": "Walletbeat lacks the information needed to determine this.", | |
| "details": "See full details on the wallet page." | |
| } | |
| }, | |
| "multiAddressCorrelation": { | |
| "attribute": { | |
| "attributeDisplayName": "Multi-address privacy", | |
| "attributeId": "multiAddressCorrelation", | |
| "shortQuestion": "Can your multiple wallet addresses be correlated with one another?", | |
| "whyItMatters": "\nYou probably have more than one wallet address configured in your wallet,\nwhich you use for different purposes and perhaps as different identities.\nThese wallet addresses all belong to you, but you would rather keep that\nfact private. It is therefore important to use a wallet that does not reveal that fact.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is multi-address privacy evaluated?", | |
| "methodology": "\nWallets are assessed based on whether an external provider can learn that\ntwo or more of the user's wallet addresses belong to the same user.\n\nAn external provider may learn of this correlation either through:\n\n- The wallet software explicitly sending this data (e.g. through\n analytics)\n- Requesting data about multiple wallet addresses in bulk, allowing\n the receiving endpoint to learn that all of these addresses belong to\n the same user. Similar correlations are also possible by IP and/or\n\ttime-based correlation of requests that each contain one wallet address.\n\nIn order to prevent this information from being revealed, wallets can\nuse a variety of strategies:\n\n* Wallets may offer the user to only have one active wallet address at\n\ta time, and only ever makes requests about the active wallet address.\n\tThe user is expected to not change their active address often.\n\tThe wallet should also ensure that any account-switching widget does\n\tnot cause bulk/simultaneous requests about multiple addresses to the\n\tsame endpoint, such as for refreshing balances.\n\tNote that this scheme, while simple to implement, is incompatible with\n\tstealth addresses. This is because stealth addresses inherently require\n\tthe user to simultaneously manage a range of addresses.\n* Wallets may look up information about multiple addresses by splitting\n\tup the requests such that each request only contains one address, then\n\tsending these requests over different proxy circuits in a manner that\n\tstaggers the requests over time. This ensures that the receiving\n\tendpoint cannot correlate addressed based on timing or IP address.\n* Wallets may distribute requests across multiple RPC endpoints owned by\n\tseparate entities for each wallet address, preventing each entity from\n\tlearning more than one wallet address.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "UNRATED", | |
| "shortExplanation": "Walletbeat lacks the information needed to determine this.", | |
| "details": "See full details on the wallet page." | |
| } | |
| }, | |
| "privateTransfers": { | |
| "attribute": { | |
| "attributeDisplayName": "Private token transfers", | |
| "attributeId": "privateTransfers", | |
| "shortQuestion": "Can you send and receive tokens without revealing your transaction history to others?", | |
| "whyItMatters": "\nData posted on public blockchains like Ethereum is publicly available to\neveryone. This means that anyone can see your transaction history.\nYou would not voluntarily post your bank statements or private purchase\nhistory online, yet this is what happens by default when transacting\non public blockchains.\n\nMany privacy solutions have emerged to solve this problem. However, to\nbe actually usable by users, **these solutions must be tightly integrated\nin wallets** and easy to use. Walletbeat looks at whether wallets\nlet users send, receive, and spend tokens privately by default.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is token transfer privacy evaluated?", | |
| "methodology": "\nIn order to get a passing rating, wallets must ensure that sending Ether\nor ERC-20 tokens to other addresses comes with privacy guarantees\n**by default**. In addition, they must ensure that users can receive and\nspend such tokens privately.\n\n\"Privately\" here means that other than the wallet user, no single entity\n(including any external provider) can infer or reconstruct the user's\ntransaction history.\n\nWalletbeat currently recognizes the following privacy-preserving token\ntransfer solutions:\n\n- [ERC-5564 Stealth Addresses](https://eips.ethereum.org/EIPS/eip-5564#wb-format=long)\n- [Tornado Cash Nova](https://nova.tornadocash.eth.limo/)\n- [Privacy Pools](https://privacypools.com/)\n- [Railgun](https://www.railgun.org/)\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask does not support private token transfers.", | |
| "details": "\nMetaMask does not support any type of private token transfers.\n\nThis means all token transfers made using MetaMask are public\ninformation and are recorded forever. Users should only make token\ntransfers if they would be comfortable publishing their bank statement\nor payment history online—their privacy level would be similar.\n", | |
| "impact": "\nAs all token transfers will be recorded publicly onchain forever,\nMetaMask should only be used for transactions where privacy is not\nand will never be needed, such as public DAO treasury operations.\n\nMetaMask **should not be used for peer-to-peer transfers**, and\nusers should keep their addresses to themselves to avoid creating\npermanent associations between their public transactions and their\npersonal identity.\n\nUsing MetaMask for real-world payments is especially **not advisable**.\nMerchants could look up a customer's balance and initiate a\n[**wrench attack**](https://github.com/jlopp/physical-bitcoin-attacks/blob/master/README.md).\nThis puts users at risk of physical and financial harm.\n", | |
| "howToImprove": "\nMetaMask should support some form of private token transfers,\nsuch as [ERC-5564: Stealth Addresses](https://eips.ethereum.org/EIPS/eip-5564#wb-format=short), and should make this the primary\nway to perform token transfers. Public token transfers should either be\nhidden under a power-user-only menu, come with important user safety\nwarnings, or deleted from the wallet's feature set.\n" | |
| } | |
| }, | |
| "appIsolation": { | |
| "attribute": { | |
| "attributeDisplayName": "App isolation", | |
| "attributeId": "appIsolation", | |
| "shortQuestion": "\nIf you connect to an app, will it be able to learn your past activity\nfrom other apps by default?\n", | |
| "whyItMatters": "\nOn the web, website `A` is not allowed to query your browsing history from\nwebsite `B` by default. This ensures your browsing activity remains private\nacross websites. This principle is enshrined in the HTTP protocol as the\n[**Same-Origin Policy**](hhttps://en.wikipedia.org/wiki/Same-origin_policy):\nby default, each website has its own isolated data about a user,\nand may not obtain any other information without explicit consent.\n\nIn web3, address reuse allows app to correlate your usage and browsing\nhistory across other apps. While this can be a useful feature that\nenables easy composability, it is also an irreversible privacy problem\nand a regression from web2-level privacy.\n\nFor web3 to avoid perpetuating this privacy problem, users need to be\nable to control the amount of information each new app may learn about\ntheir past onchain history.\n\nMaintaining per-app accounts creates complex fragmentation and UX issues\nwhich are difficult to abstract away from users. Nonetheless, address\nreuse creates an indelible data trail for users.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is app isolation evaluated?", | |
| "methodology": "\nWallets are assessed based on whether they make it easy for the user to\ncreate a distinct account for each new app they use, and whether this is\nthe default choice.\n\nWhen connecting to apps that the user previously connected to, the\nwallet must use the address(es) that were last used for this specific\napp.\n\nWallets that do not support connecting to apps are exempt from this\nattribute.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "\nMetaMask does not remember which set of addresses you last\nused when connecting to an app.\n", | |
| "details": "\nWhen connecting to an app you have connected to before,\nMetaMask does not default to the same set of addresses as you\nhad last selected.\n", | |
| "impact": "\nMetaMask makes it likely for the user to accidentally expose\nother addresses beyond the one they had initially intended for\nthe app to be able to access. Once connected, this allows the app to\ncorrelate more of the user's activity than the user had initially\nintended.\n", | |
| "howToImprove": "\nMetaMask should locally store the set of addresses that the\nuser selected when connecting to apps, and use this set of addresses\nby default when reconnecting to them.\n" | |
| } | |
| } | |
| }, | |
| "selfSovereignty": { | |
| "l1ProviderIndependence": { | |
| "attribute": { | |
| "attributeDisplayName": "L1 provider independence", | |
| "attributeId": "l1ProviderIndependence", | |
| "shortQuestion": "\nCan you use the wallet without relying on its default provider for\ninteracting with the L1 chain?\n", | |
| "whyItMatters": "\nEthereum's design goes to painstaking lengths to ensure that users can\nrun an Ethereum L1 node on commodity consumer-grade hardware and\nresidential Internet connections, and use it for interacting with L1.\n\nRunning your own node gives you several important benefits:\n\n* **Privacy**: Because the wallet can work directly on your own hardware\n\twith no outside dependencies, the wallet can query chain data without\n\trevealing private details (wallet address, IP address, etc.) to an\n\texternal RPC provider.\n* **Integrity**: Relying on an external RPC provider means that this\n\tprovider may return incorrect data about the state of the chain,\n\ttricking you into signing a transaction that ends up having a different\n\teffect than intended. Your own L1 node will verify the integrity of the\n\tchain, so such attacks cannot occur when using a self-hosted node.\n* **Censorship resistance**: Because an L1 node may broadcast transactions\n\tinto a shared mempool directly to other nodes in the network, your\n\ttransactions are not censorable by an external RPC provider that would\n\totherwise act as an intermediary.\n* **No downtime**: Because the L1 node is running on your own hardware,\n\tyou are not at risk of losing funds or opportunities due to downtime\n\tfrom an external RPC provider.\n\nHowever, **these advantages only matter if wallet users can actually take\nadvantage of them**. Thus, wallets must allow users to use a self-hosted\nnode for these benefits to be realized in practice, and must not\ncritically depend on external services to perform basic L1 interactions\nsuch as balance lookups and sending tokens.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is L1 provider independence evaluated?", | |
| "methodology": "\nIn order to qualify for this attribute, wallets must:\n\n- Allow the user to configure the L1 RPC endpoint to a self-hosted node\n before any request is made to that endpoint.\n- Support basic functions (account creation/import, balance lookups,\n token transfers) using nothing but the self-hosted node\n\t(no external services, no non-Ethereum-API calls), and whether\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "\nEven with your self-hosted node, MetaMask depends on external\nservices to perform basic tasks on Ethereum mainnet.\n", | |
| "details": "\nWhile MetaMask lets you use a self-hosted Ethereum node to\ninteract with mainnet, it still critically depends on external\nservices to perform the following basic operations:\n\n\n\n\n* Looking up your balance for an ERC-20 contract address\n* Sending ERC-20 tokens\n", | |
| "howToImprove": "\nMetaMask should ensure that basic operations work with no\nother dependency than the user-configured L1 RPC endpoint.\n", | |
| "references": [ | |
| { | |
| "explanation": "\n\t\t\t\t\t\tMetaMask lets users set custom RPC endpoints for any network,\n\t\t\t\t\t\tincluding mainnet. Before that, it contacts default endpoints\n\t\t\t\t\t\t(mainnet.infura.io and some L2s) for non-sensitive RPCs\n\t\t\t\t\t\t(`eth_blockNumber`, `net_version`).\n\t\t\t\t\t", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/configure/networks/how-to-add-a-custom-network-rpc/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "accountPortability": { | |
| "attribute": { | |
| "attributeDisplayName": "Account portability", | |
| "attributeId": "accountPortability", | |
| "shortQuestion": "\nAre you locked into this wallet?\nOr can you permissionlessly import your Ethereum account into another wallet?\n", | |
| "whyItMatters": "\nQuestion:\n**What if a wallet's dev team walked away or turned evil one day?**\n\nOne of Ethereum's core promises as an Internet upgrade is to avoid the\npossibility for user lock-in of web2. This is achieved by ensuring\naccounts are permissionlessly portable across wallets.\n\nEnsuring that accounts remain portable avoids wallets becoming lock-in\nvectors in web3. Permissionless account portability also keeps the wallet\necosystem healthy through open competition.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account portability evaluated?", | |
| "methodology": "\nWallets are rated based on whether accounts created within can be\nexported out of the wallet and imported into another, without requiring\npermission from the exporter wallet provider.\n\nFor EOA wallets based on private keys, this is relatively straightforward\nto determine. However, for more complex situations such as multisig\nwallets, Walletbeat considers whether such wallets can be made fully\nself-custodial, and whether assets and tokens can be permissionlessly\ntransferred out of the wallet.\n\nSpecifically:\n\n* **EOA wallets** are rated based on the exportability of their private\n\tkey material, and on whether such private key material is derived using\n\tthe following standards:\n\n\t* [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)\n\t\tfor deriving a binary seed from a seed phrase.\n\t* [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)\n\t\tfor deterministic hierarchical key derivation from the binary seed.\n\t* [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)\n\t\tas a standard when deriving hierarchical private keys.\n\n* **MPC wallets** are rated based on whether the user has a sufficient\n\tshares of the underlying key to have full control over the wallet in\n\ta self-custodial manner. Additionally, there must be a way for the user\n\tto generate a transaction (Walletbeat uses a token transfer out of the\n\twallet as the litmus transaction for this) without reliance on an\n\texternal API or proprietary application. The combination of these\n\tfactors ensures that the wallet remains self-custodial and that the\n\taccount cannot be frozen in-place due to an uncooperative external\n\tprovider.\n* [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short) (smart contract wallets) are rated based on\n\tthe level of control the user has over their account according to the\n\tsmart contract's control logic that the wallet uses. The user must be\n\t*in control of who controls their account* by default, and be able to\n\tpermissionlessly create asset transfer transactions. \n\tSpecifically, the rating considers:\n\n\t* Whether the user has the ability to change the cryptographic keys\n\t\tused to control the account in general, in a manner that does not\n\t\tinvolve relying on an external provider or proprietary software.\n\t* Whether the smart contract wallet's default configuration starts\n\t\tout with the user having self-custody of their account, for example\n\t\tby having a majority of the key shares in self-custody in a multisig\n\t\twallet.\n\t* Whether the generation of a token transfer transaction requires\n\t\trelying on an external provider or proprietary software, even if the\n\t\tuser has self-custody of all requisite cryptographic keys to sign\n\t\tsuch a transaction.\n\n* [EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) are not yet rated on account portability and\n\twill show up as \"Unrated\".\n\nIf a wallet supports multiple types of accounts, the rating for the account\ntype it supports that is *least* portable takes precedence. This makes the\nfinal rating act as an effective \"floor\" across the account types the\nwallet supports.\n\nIf a wallet supports multiple types of accounts and all of them have the\nsame level of portability, the account type that takes precedence is the\none that the wallet offers the user to create by default.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask follows EOA key derivation standards.", | |
| "details": "\nMetaMask generates EOA keys in a\nstandards-compliant way:\n\n* [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)\n\tfor deriving a binary seed from a seed phrase.\n* [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)\n\tfor deterministic hierarchical key derivation from the binary seed.\n* [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)\n\tas a standard when deriving hierarchical private keys.\n\nIn addition, seed phrases are exportable so that they can be\nimported into other wallets. This ensures your account is portable\nand avoids lock-in.\n\n" | |
| } | |
| }, | |
| "transactionInclusion": { | |
| "attribute": { | |
| "attributeDisplayName": "Transaction inclusion", | |
| "attributeId": "transactionInclusion", | |
| "shortQuestion": "Can the wallet withdraw L2 funds to Ethereum L1 without relying on intermediaries?", | |
| "whyItMatters": "\nOne of the core tenets of Ethereum is **censorship resistance**.\nThis means that users must be able to reliably get transactions\nincluded onchain, without the ability for intermediaries to prevent\nthis from happening.\n\nThis property is critical to ensure that all Ethereum participants are\nprovided equal-opportunity, unfettered access to Ethereum, and to ensure\nthat Ethereum is resilient to attackers that would want to prevent others\nfrom using Ethereum on such footing.\n\nIn order to uphold this property on Ethereum L2s, users must be able to\nforce transactions to be included on L2 chains as well. Most L2s\nimplement such functionality by allowing L2 transactions to be\nsubmitted on the L1, and enforcing that their sequencing logic must\nrespect such L1 force-inclusion requests by including them on the L2\nchain, typically within some fixed duration.\n\nBy verifying that the wallet supports L2 force-withdrawal transactions,\nthis attribute verifies censorship resistance at both levels: L1 and L2.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is transaction inclusion evaluated?", | |
| "methodology": "\nWallets are rated based on whether users need to trust any intermediary\nin order to withdraw their funds from L2s.\n\nThis fundamentally requires two major features:\n\n* A wallet must support the creation of an L1 transaction which forces the\n\tL2 to withdraw user funds back to the L1. This message is typically\n\tposted as an L1 transaction which forces the L2 sequencing process to\n\ttake it into account.\n* Since L2 force-withdrawal transactions require an L1 transaction, the\n\twallet must also be able to get this transaction included without\n\trelying on an external service to broadcast this transaction for block\n\tinclusion. Therefore, the wallet must also support either participating\n\tin Ethereum's L1 gossip network, or (for environments that do not\n\tsupport this such as browser extension wallets) support broadcasting\n\tL1 transactions through a user's self-hosted Ethereum node.\n\nWith these two features in place, users can withdraw their L2 funds\nwithout trusting intermediaries.\n\nWalletbeat currently only considers OP Stack chains and Arbitrum One for\nthis evaluation, but more L2 chains may be added as support for\nforce-withdrawal transaction becomes feasible for them.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "UNRATED", | |
| "shortExplanation": "Walletbeat lacks the information needed to determine this.", | |
| "details": "See full details on the wallet page." | |
| } | |
| }, | |
| "accountUnruggability": { | |
| "attribute": { | |
| "attributeDisplayName": "Account unruggability", | |
| "attributeId": "accountUnruggability", | |
| "shortQuestion": "Can the wallet developer take over your account without your consent?", | |
| "whyItMatters": "\nThe promise of crypto is to make your accounts and your funds truly yours.\nThis is what is most commonly referred to when discussing\n\"self-sovereignty\".\n\nThe underlying property that makes an account truly yours is the inability\nfor anyone other than yourself to act on your behalf or to take over your\naccount without prior consent.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account unruggability evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether there is any mechanism by which\nany entity other than the user may sign or approve transactions on behalf\nof the user's account, or can transfer ownership of the account away from\nthe user. This includes features like seed phrase backups where the wallet\ndeveloper gets to learn the user's seed phrase, or other account recovery\nfeatures that let the wallet developer unilaterally recover the user's\naccount.\n\nFully-custodial wallets (i.e. wallets where the signing key material\nresides entirely on external services) are also not self-sovereign\n(aka ruggable) by definition.\n\nFeatures that allow the user to pre-approve certain types of transactions\nahead of time are treated as maintaining self-sovereignty, so long as\nthe user controls their limits explicitly:\ntime-bound, amount-bound, destination/purpose-bound, etc.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "\nMetaMask does not allow any external service to take over\nyour account.\n", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "urls": [ | |
| { | |
| "label": "MetaMask account recovery documentation", | |
| "url": "https://support.metamask.io/configure/wallet/social-login" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| "transparency": { | |
| "openSource": { | |
| "attribute": { | |
| "attributeDisplayName": "Source code license", | |
| "attributeId": "openSource", | |
| "shortQuestion": "\nDoes the user have the ability to avoid lock-in and freely audit,\nmodify, and redistribute the wallet's source code?\n", | |
| "whyItMatters": "\n[Free & Open Source Software (FOSS) licensing](https://en.wikipedia.org/wiki/Open-source_license)\nallows a software project's source code to be freely used, modified and distributed.\nThis allows better collaboration, more transparency into the software development practices\nthat go into the project, and allows security researchers to more easily identify and report\nsecurity vulnerabilities. In short, it turns software projects into public goods.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is source code license evaluated?", | |
| "methodology": "\nWallets are assessed based whether the license of their source code meets\nthe [Open Source Initiative's definition of open source](https://en.wikipedia.org/wiki/The_Open_Source_Definition).\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask uses a proprietary license for some of its code.", | |
| "details": "\nWhile part of **MetaMask** is licensed under the\n[**MIT** license](https://spdx.org/licenses/MIT.html)\n(a Free & Open-Source (FOSS) license), others are not.\n", | |
| "howToImprove": "MetaMask should consider licensing all of its code under a Free & Open Source Software license." | |
| } | |
| }, | |
| "sourceVisibility": { | |
| "attribute": { | |
| "attributeDisplayName": "Source visibility", | |
| "attributeId": "sourceVisibility", | |
| "shortQuestion": "Is the source code for the wallet visible to the public?", | |
| "whyItMatters": "\nWhen using a wallet, users are entrusting it to preserve their funds\nsafely. This requires a high level of trust in the wallet's source code\nand in the wallet's development team. By making the wallet's source code\nvisible to the public, its source code can be more easily inspected for\nsecurity vulnerabilities and for potential malicious code.\nThis improves the wallet's security and trustworthiness.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is source visibility evaluated?", | |
| "methodology": "\nWallets are assessed based on whether or not their source code is\npublicly visible, irrespective of the license of the source code.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "\nThe source code for MetaMask is public.\n", | |
| "details": "\nThe source code for **MetaMask** is publicly viewable.\n", | |
| "impact": "\nThis allows its source code to be examined for security flaws and\nfor Walletbeat to review how the wallet works.\n", | |
| "references": [ | |
| { | |
| "explanation": "The MetaMask core repository contains various packages reused across all MetaMask versions, licensed under MIT.", | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/MetaMask/core/tree/main/packages" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "The MetaMask browser extension uses a proprietary source-available license.", | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/MetaMask/metamask-extension/blob/main/LICENSE" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "funding": { | |
| "attribute": { | |
| "attributeDisplayName": "Funding", | |
| "attributeId": "funding", | |
| "shortQuestion": "How is the wallet's development team funded?", | |
| "whyItMatters": "\nWallets are complex, high-stakes pieces of software.\nThey must be maintained, regularly audited, and follow the continuous\nimprovements in the ecosystem.\nThis requires a reliable, transparent source of funding.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is funding evaluated?", | |
| "methodology": "\nWallets are assessed based on how sustainable, transparent, and\nuser-aligned their funding mechanisms are.\n\nWallets are typically funded by one or more of the following methods:\n\n* Self-funding from developers\n* Seeking donations from users\n* Seeking grants from foundations\n* Venture capital funding\n* Charging fees on convenience functions (e.g. swapping and bridging\n\ttokens)\n* Governance tokens\n* Commemorative NFT sales\n\nWalletbeat looks at each funding source of funding and verifies whether\nit is done transparently and in a user-aligned manner. In this context,\n\"user alignment\" refers to whether a source of funding grows as a\nfunction of the user's own goals, rather than being uncorrelated or\nanti-correlated. For example, funding acquired through hidden swap fees\nor governance token sales with undisclosed insider token allocations are\nnot user-aligned. Funding acquired through transparent swap fees, user\ndonations, or ecosystem grants are user-aligned.\n\nIn order to pass this criterion, wallets must have at least one source of\nfunding, and all of their sources of funding must be transparent to users.\nAdditionally, if the wallet is funded from multiple sources and some of\nthese sources are not user-aligned, the public must be able to determine\nthe proportion of each such funding source to the wallet's overall\nrevenue. Depending on the funding mechanism, this can be done through\npublication of a revenue breakdown page, public regulatory filings,\nor token allocation and vesting disclosures.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask is transparently funded.", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask is funded through transparent swap fees and venture capital with publicly disclosed funding rounds.", | |
| "urls": [ | |
| { | |
| "label": "consensys.io", | |
| "url": "https://consensys.io/blog/consensys-raises-450m-series-d-funding" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "feeTransparency": { | |
| "attribute": { | |
| "attributeDisplayName": "Fee transparency", | |
| "attributeId": "feeTransparency", | |
| "shortQuestion": "Does the wallet clearly display all transaction fees and their purpose?", | |
| "whyItMatters": "\nFee transparency is crucial for users to understand the full cost of their transactions.\nWithout clear fee information, users may be surprised by high transaction costs or\nhidden fees charged by the wallet.\n\nTransparent fee disclosure helps users make informed decisions about when to transact\nand which wallet to use. It also builds trust between users and wallet providers by\nensuring that all costs are clearly communicated upfront.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's fee transparency evaluated?", | |
| "methodology": "\nWallets are evaluated based on how transparently they display transaction fees and\ntransaction purposes to users.\n\nA wallet receives a passing rating if it provides comprehensive fee information,\nincluding detailed breakdowns of network fees, clear disclosure of any additional\nwallet fees. Fees may be aggregated down to one number, but a breakdown must be\navailable to the user within a single click.\n\nA wallet receives a partial rating if it provides an aggregate fee but does not\nlet the user get a detailed breakdown.\n\nA wallet fails this attribute if it provides minimal or no fee information before\ntransaction confirmation.\n\nVarious transaction types are tested: Ether and ERC-20 transfers on L1, built-in\nswaps or bridging transactions, DeFi transactions, private transactions if\nsupported. If a wallet displays fees differently depending on the type of\ntransaction, the transaction type with the **least clear** display level is\ntaken into consideration for the purpose of this attribute.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "\nMetaMask breaks down all transaction fees.\n", | |
| "details": "\nMetaMask shows a complete breakdown of all transaction\nfees by default.\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask has a built-in bridge feature that allows users to bridge assets between chains.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/learn/field-guide-to-bridges/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| "ecosystem": { | |
| "accountAbstraction": { | |
| "attribute": { | |
| "attributeDisplayName": "Account Abstraction", | |
| "attributeId": "accountAbstraction", | |
| "shortQuestion": "Is the wallet Account Abstraction ready?", | |
| "whyItMatters": "\nUser experience on Ethereum has historically suffered from the limitations of Externally-Owned Accounts (EOAs), which is the type of account most Ethereum users use today. By contrast, smart wallet accounts offer many UX and security improvements, such as the ability to:\n\n* Batch multiple transactions, removing the need for separate \"token approval\" transactions before every other token operation.\n* Pay gas fees in other tokens than Ether, or support sponsored transaction fees (with [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short))\n* Delegate some operation to trusted provider, such as allowing onchain games to withdraw small amounts of tokens without signing pop-ups for each and every transaction.\n* Change transaction authorization logic, enabling the use of Passkeys (and cellphone authentication methods) for signing transactions.\n* Update the set of keys used to control the wallet, enabling the switch to quantum-resistant encryption algorithms in the future.\n* Define account recovery rules, reducing the risk of losing access to your account when losing a private key or a device.\n\nHowever, smart wallet accounts have historically been an all-or-nothing, wallet-specific proposition for users. There was no transition path to such wallets.\n\nAs part of the [Pectra upgrade](https://eips.ethereum.org/EIPS/eip-7600),\n[EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) fixes this problem. It create a clean path for\nexisting EOAs to obtain all the UX benefits of smart wallet accounts\nand account abstraction, without the need for users to switch to a\ndifferent account address.\nThis represents a large User Experience upgrade for all Ethereum EOA users.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account abstraction support evaluated?", | |
| "methodology": "\nWallets are rated based on whether they make use of\n[EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) transactions (for EOA or MPC wallets),\nor if they support [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short) transactions\n(for smart contract wallets).\n\nThe user experience benefits of these enhancements are still in-flight\nand are expected to develop as these standards mature and are built on\ntop of. As such, Walletbeat does not currently consider *which*\nimprovements wallets provide for their users as a result of these new\ncapabilities. However, it is expected that a future version of this\nattribute would look at such improvements. For example: to verify\nthat users are able to update the signing authority of their wallets\nto a quantum-safe signature scheme.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports Account Abstraction via EIP-7702.", | |
| "details": "MetaMask supports Account Abstraction via [EIP-7702 Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=long)." | |
| } | |
| }, | |
| "addressResolution": { | |
| "attribute": { | |
| "attributeDisplayName": "Address resolution", | |
| "attributeId": "addressResolution", | |
| "shortQuestion": "Can you send funds to human-readable Ethereum addresses?", | |
| "whyItMatters": "\nEthereum addresses are hexadecimal strings (`0x...`) which are\nunreadable to humans. Phishing scams and exploits have used this to\ntrick users into sending funds to invalid addresses, for example by\ngenerating lookalike-addresses and tricking users into copy/pasting\nthem without noticing the difference.\n\nAdditionally, Ethereum's transition to layer 2 chains has changed user\nneeds when sending funds. The hexadecimal address isn't sufficient\nanymore; the user needs to ensure that they are sending funds to the\ncorrect hexadecimal address *on the correct chain*, increasing the\npotential for mistakenly sending funds to the wrong place or the wrong\nchain.\n\nAddress naming registries like ENS partially solve this problem by\nallowing more human-readable names like `username.eth` to be\nautomatically turned into the hexadecimal address. This is easier to\nshare and to accurately transfer by humans. Additionally, some address\nformat standards improve upon this further by including the destination\nchain information as part of the address itself. Such standards include:\n\n* [ERC-7828 Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=long): `user@l2chain.eth`\n* [ERC-7831 Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=long): `user.eth:l2chain`\n\nWallets that support either of these standards are able to automatically\ndetermine the destination address and chain from a human-readable string,\nand can bridge funds across chains as appropriate. This improves the user\nexperience of Ethereum and its layer 2 ecosystem while reducing the\npotential for mistakes when sending funds.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is address resolution evaluated?", | |
| "methodology": "\nWallets are rated based on the types of addresses they support sending\nfunds to.\n\nWalletbeat recognizes the following destination address formats:\n\n* Plain ENS addresses (`username.eth`) without destination chain information\n* [ERC-7828 Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=long): `user@l2chain.eth`\n* [ERC-7831 Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=long): `user.eth:l2chain`\n\nWallets receive a **pass** only if they support [ERC-7828: Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=short) or\n[ERC-7831: Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=short) (chain-specific human-readable addresses).\nWallets that support only plain ENS, with or without onchain resolution,\nreceive a **partial** rating.\n\nFor a pass, the mechanism used to perform the resolution must either:\n\n* Be done using onchain data and reusing the wallet's common chain\n interaction client, inheriting its verifiability (e.g. via light\n client) and privacy properties.\n* **OR** be done using an offchain external provider in such a way that\n the address returned by the external provider is verifiable, and\n without revealing the user's IP address to the provider.\n This ensures that:\n - The wallet cannot be tricked into sending funds to an attacker\n compromising the offchain provider's responses\n - The provider may not progressively learn the user's contacts list by\n associating its successive resolution queries by IP over time.\n\nFor addresses that **require** an offchain lookup (e.g. ENS names\nusing [offchain resolvers with CCIP-Read](https://docs.ens.domains/resolvers/ccip-read)),\nonly the portion of the work necessary to _arrive at the conclusion_\nthat an offchain lookup is necessary is considered.\nIn other words, wallets must verify that the CCIP-Read\n`OffchainLookup` details are as claimed and then perform the CCIP-Read\nthemselves, rather than trust an offchain provider to do so on their\nbehalf.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask supports sending to plain ENS addresses but not chain-specific human-readable addresses.", | |
| "details": "\nMetaMask supports sending funds to human-readable ENS addresses such as `username.eth`, but does not support chain-specific address formats that specify the destination chain.\n\nIt does so using onchain data sources using the same code as when interacting with the chain in general, inheriting its privacy and verifiability properties.\n", | |
| "howToImprove": "\nMetaMask may want to add support for sending funds to chain-specific human-readable addresses, as specified by either:\n\n* [ERC-7828 Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=long): `user@l2chain.eth`\n* [ERC-7831 Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=long): `user.eth:l2chain`\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask supports ENS domain resolution.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/learn/sending-or-receiving-a-transaction-with-ens/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "browserIntegration": { | |
| "attribute": { | |
| "attributeDisplayName": "Browser integration", | |
| "attributeId": "browserIntegration", | |
| "shortQuestion": "Does the wallet comply with web browser integration standards?", | |
| "whyItMatters": "\nWeb applications that want to integrate with Ethereum should not have to\nwrite code specific to the wallet that the user has installed. For this\nreason, the Ethereum community has defined web browser integration\nstandards, which dictate how wallets and web pages can interact with each\nother.\n\nBy ensuring that wallets implement this standard interface, applications\nautomatically support all wallets that implement the interface. This\nensures compatibility across wallets, and ensures that the Ethereum wallet\necosystem remains competitive thanks to wallet interoperability.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is browser integration evaluated?", | |
| "methodology": "\nWallets are rated based on whether they implement the following Ethereum\nstandards for web browser integration:\n\n* [EIP-1193 JavaScript Provider API](https://eips.ethereum.org/EIPS/eip-1193#wb-format=long)\n* [EIP-2700 JavaScript Provider Events](https://eips.ethereum.org/EIPS/eip-2700#wb-format=long)\n* [EIP-6963 Multiple JavaScript Providers](https://eips.ethereum.org/EIPS/eip-6963#wb-format=long)\n\nFor multi-platform wallets, only the web browser version is assessed.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports all the prominent standards for web browser integration.", | |
| "details": "\nMetaMask supports all the prominent standards for web browser integration:\n\n* [EIP-1193 JavaScript Provider API](https://eips.ethereum.org/EIPS/eip-1193#wb-format=long)\n* [EIP-2700 JavaScript Provider Events](https://eips.ethereum.org/EIPS/eip-2700#wb-format=long)\n* [EIP-6963 Multiple JavaScript Providers](https://eips.ethereum.org/EIPS/eip-6963#wb-format=long)\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask browser extension supports standard Ethereum Provider APIs. Mobile app does not inject into web pages.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/hc/en-us/articles/360015489471" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "chainAbstraction": { | |
| "attribute": { | |
| "attributeDisplayName": "Chain abstraction", | |
| "attributeId": "chainAbstraction", | |
| "shortQuestion": "Does the wallet smooth out the complexities of dealing with multiple chains?", | |
| "whyItMatters": "\nEthereum activity is not limited to the main L1 chain; a lot of activity\nhas moved onto rollups and Layer 2 chains. This has allowed Ethereum to\nscale beyond what its L1 chain can handle, but has also introduced\ncomplexity and fragmentation for users and wallets to deal with.\nThey must now deal with token balances fragmented across multiple chains.\n\nTo address the UX impact of this complexity, wallets should provide\nfeatures to abstract away these issues, while remaining transparent to\nthe user when cross-chain bridging risks or fees are involved.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is chain abstraction evaluated?", | |
| "methodology": "\nWallets are rated based on how much of the complexity involved in dealing\nwith multiple chains is abstracted away from users, while keeping risks\nand fees transparent.\n\nTo get a passing rating, wallets must be cross-chain aware in how they\ndisplay account value and individual token balances:\n\n- When displaying the user account's total value, this value should sum\n\tup the user's valuations across all chains the wallet supports by\n\tdefault.\n- When displaying a specific token's balance, the balance should reflect\n\tthe user's total balance for this token across all wallet-supported\n\tchains (and on which the token exists). For rating purposes,\n\tWalletbeat looks specifically at Ether and USDT balances.\n\nIn addition, wallets must make it easy for users to move their assets\nacross chains when needed. To get a passing rating, wallets must provide\na built-in bridging feature.\n\n- This bridging feature must explain the risks involved in bridging assets\n\tacross chains. Our friends at [L2BEAT](https://l2beat.com/) do a\n\tfantastic job documenting this, but wallet developers also have a duty\n\tto explain these risks to their users.\n- For bridge operations where the net fee is larger than 1bps, the wallet\n\tmust display the fee breakdown by default.\n- When the user attempts to send tokens to an address on a chain where the\n\tuser's balance is insufficient, but for which they have sufficient tokens\n\ton another chain, the wallet should automatically propose to bridge them.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask does not add up token balances across chains.", | |
| "details": "\nMetaMask can display your account's total value across\nchains and per-chain token balances. It does not, however, show\nyour total balance for a given token (e.g. Ether or USDC) summed\nup across multiple chains. That makes it hard to see how much\nUSDC you have.\n\nCross-chain token balance awareness is one of many features that\nwallets need to be multi-chain-aware. This matters for the Ethereum\nL2 roadmap, which aims to make L2s seamless for users.\n", | |
| "howToImprove": "\nMetaMask should have a way to see token balances summed up\nacross chains.\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask displays tokens across multiple networks in a single aggregated view with estimated portfolio value", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/manage-crypto/tokens/how-to-view-your-token-balance-across-multiple-networks/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "MetaMask has a built-in bridge feature that allows users to bridge assets between chains.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/learn/field-guide-to-bridges/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "transactionBatching": { | |
| "attribute": { | |
| "attributeDisplayName": "Transaction batching", | |
| "attributeId": "transactionBatching", | |
| "shortQuestion": "Does the wallet support bundling multiple operations as a single transaction?", | |
| "whyItMatters": "\nTransaction batching is one of the longstanding features without which\nEthereum user experience (UX) has suffered. One of the most common pain\npoints for DeFi, for example, has been the need to perform separate\n\"token approval\" transactions, followed by a separate transaction to\nactually execute the user's original intent.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is transaction batching evaluated?", | |
| "methodology": "\nSmart account types such as [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short) and\n[EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) unlock the ability to perform multiple\noperations as a single transaction. This is exposed to applications\nthrough [EIP-5792 Wallet Call API](https://eips.ethereum.org/EIPS/eip-5792#wb-format=long).\n\nTo qualify for a passing rating, the wallet must:\n\n- Support at least one type of smart account.\n- Implement [EIP-5792 Wallet Call API](https://eips.ethereum.org/EIPS/eip-5792#wb-format=long).\n- Support atomic transaction bundles, as per the `atomic` capability\n declared in `wallet_getCapabilities`.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports transaction batching and atomic transaction bundles.", | |
| "details": "\nMetaMask implements [EIP-5792 Wallet Call API](https://eips.ethereum.org/EIPS/eip-5792#wb-format=long).\nThis means applications can request the wallet to bundle multiple\ntransactions into a single operation.\nFor example, this means token approval transactions need to be\nsubmitted separately from the transactions that spend these tokens.\n\nIn addition, MetaMask supports **atomic** transaction bundles.\nThis means that the wallet guarantees that a transaction bundle is\neither **all executed** or **all non-executed**. This enables some\nadvanced DeFi use-cases.\n" | |
| } | |
| }, | |
| "hardwareWalletInteroperability": { | |
| "attribute": { | |
| "attributeDisplayName": "Hardware wallet interoperability", | |
| "attributeId": "hardwareWalletInteroperability", | |
| "shortQuestion": "\nDoes the wallet support directly connecting to hardware wallets from a plurality of manufacturers?\n", | |
| "whyItMatters": "\nHardware wallets are physical devices that store a user's private keys offline,\nproviding an additional layer of security against online threats. By keeping\nprivate keys isolated from internet-connected devices, hardware wallets protect\nusers from malware, phishing attacks, and other security vulnerabilities that\ncould compromise their funds.\n\nSupporting multiple hardware wallet manufacturers preserves a healthy,\nopen, competitive, interoperable market for hardware wallets. It also\nincreases the total addressable market of users for the software wallet,\nas users that already own a specific hardware wallets will want to use a\nsoftware wallet that supports it.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's hardware wallet support evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether they directly integrate with\nhardware wallets from a plurality of major hardware wallet manufacturers.\n\nA wallet receives a passing rating if it supports hardware wallets from\nat least 3 major hardware wallet\nmanufacturers:\n\n\n* Ledger\n* Trezor\n* Keystone\n* GridPlus\n* imKey\n\nHardware wallets accessible only through WalletConnect are not counted,\nas they require relying on WalletConnect and external software beyond the\nwallet itself in order to function.\n\nA wallet receives a partial rating if it supports only two such\nhardware wallets manufacturers (without relying on WalletConnect or\nexternal software).\n\nA wallet fails this attribute if it only directly supports hardware wallets\nfrom a single manufacturer.\n\nWallets that do not directly support hardware wallets at all are exempt,\nas this check is only about hardware wallet *interoperability*.\nGeneral direct hardware wallet support is also part of Walletbeat's\nsecurity criteria as a separate attribute.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports a wide range of hardware wallets.", | |
| "details": "MetaMask supports the following hardware wallets:\n\n* Ledger (directly via WebUSB)\n* Trezor (directly via WebUSB)\n* GridPlus (directly via WebUSB)\n* Keystone (directly via QR code)\n\t", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask supports Ledger, Trezor, Lattice (GridPlus), Keystone, OneKey, and KeepKey via its Hardware Wallet Hub.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/wallets/hardware-wallet-hub/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| } | |
| }, | |
| "MOBILE": { | |
| "security": { | |
| "securityAudits": { | |
| "attribute": { | |
| "attributeDisplayName": "Security audits", | |
| "attributeId": "securityAudits", | |
| "shortQuestion": "Has the wallet's source code been reviewed by security auditors?", | |
| "whyItMatters": "\nWallets are high-stakes pieces of software that deal with sensitive\nuser data and funds. To ensure that their code is secure, industry best\npractices involve regularly submitting the wallet's source code for audit\nby an independent security auditor. These companies specialize in\nreviewing source code with an eye for security vulnerabilities. They\nreport their findings to the wallet's development team for consideration,\npointing out both flaws and potential security improvements.\n\nThese security audits matter in order to ensure the wallet's source code\nis secure, and remains that way over time. Wallet development teams\ntypically publish such audits so that wallet users can feel safer knowing\nthat the wallet's source code was independently audited.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's security auditing track record evaluated?", | |
| "methodology": "\nWallets are evaluated by their track record of published security audits.\n\nWalletbeat examines the set of published security audits of the wallet.\nTo qualify, a security audit must be publicly available, and must be\nfrom a security auditor that has a traceable corporate entity distinct\nfrom the wallet's own development team.\n\nSecurity audits typically come with one or more security flaws found,\ncategorized by level of severity. Definitions of severity vary across\nauditors, but generally anything \"medium\" or above is worth paying\nattention to.\n\nA wallet gets a passing rating if it has been audited at least once\nwithin the last 365 days, and that all medium-or-higher severity flaws\nthat were found across *all* audits (including older ones) are addressed.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask has undergone a recent security audit with all faults addressed.", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "urls": [ | |
| { | |
| "label": "assets.ctfassets.net", | |
| "url": "https://assets.ctfassets.net/clixtyxoaeas/21m4LE3WLYbgWjc33aDcp2/8252073e115688b1dc1500a9c2d33fe4/metamask-delegator-framework-audit-2024-10.pdf" | |
| } | |
| ] | |
| }, | |
| { | |
| "urls": [ | |
| { | |
| "label": "assets.ctfassets.net", | |
| "url": "https://assets.ctfassets.net/clixtyxoaeas/4sNMB55kkGw6BtAiIn08mm/f1f4a78d3901dd03848d070e15a1ff12/pentest-report_metamask-signing-snap.pdf" | |
| } | |
| ] | |
| }, | |
| { | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/Cyfrin/cyfrin-audit-reports/blob/main/reports/2025-03-18-cyfrin-Metamask-DelegationFramework1-v2.0.pdf" | |
| } | |
| ] | |
| }, | |
| { | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/Cyfrin/cyfrin-audit-reports/blob/main/reports/2025-04-01-cyfrin-Metamask-DelegationFramework2-v2.0.pdf" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "scamPrevention": { | |
| "attribute": { | |
| "attributeDisplayName": "Scam prevention", | |
| "attributeId": "scamPrevention", | |
| "shortQuestion": "Does the wallet warn the user about potential scams?", | |
| "whyItMatters": "Transactions in Ethereum are very difficult to reverse, and there is no shortage of scams. Wallets have a role to play in helping users avoid known scams ahead of the user making the transaction.", | |
| "howIsEvaluated": { | |
| "heading": "How is scam prevention evaluated?", | |
| "methodology": "\nWallets are rated based on whether they alert the user about potential\nscams. This is measured along three scenarios:\n**Does the wallet *warn* the user when...**\n\n* Sending funds to an address the user has never previously sent or\n\treceived funds from before\n* Interacting with a contract that is known to be a scam\n* Interacting with a contract that the user has never previously\n\tinteracted with before\n* Interacting with a contract that has only recently been deployed\n\tonchain\n* Connecting to an app that is known to be a scam\n\nFor payments-focused wallets that do not support interacting with\narbitrary contracts or external applications, only the payment scenario\napplies.\n\nNote that wallets should only *warn* the user about such scenarios, not\noutright *prevent* the user from making such transactions, as preventing\nthem entirely would limit the user's ability to have real sovereignty\nover their own wallet.\n\nWallets are also rated based on whether these warnings are implemented\nin a privacy-preserving manner. Specifically:\n\n* When sending funds, does the lookup for past interactions with that\n\taddress unconditionally reveal the sender and recipient addresses to an\n\texternal provider other than the wallet's default RPC provider for this\n\tchain?\n\n\t* Wallets can implement this feature in a privacy-preserving manner by\n\t\tmaintaining a local set of known addresses.\n\n* When interacting with a contract, does the check whether that contract\n\tis known to be a scam reveal the user's IP address together with the\n\tcontract address about to be interacted with?\n\n\t* This is a privacy leak similar to that of leaking the user's\n\t\tbrowsing history, as contract addresses are usually closely tied to\n\t\tthe application being visited.\n\t* Wallets can implement this feature in a privacy-preserving manner by\n\t\tmaintaining a local, frequently-updated cache of known-scam contract\n\t\taddresses.\n\n* When connecting to an application, does the check whether that\n\tapplication reveal the domain name or URL of the application being used?\n\n\t* If leaking full URLs, this is a privacy leak similar to that of\n\t\tleaking the user's browsing history.\n\t* If leaking domain names only, they must not be linkable to the\n\t\tuser's IP address or Ethereum address.\n\t* Wallets can implement this feature in a privacy-preserving manner by\n\t\tmaintaining a local, frequently-updated cache of known-scam contract\n\t\tURLs, or by looking up such a list based on a domain hash prefix\n\t\tlike [Safe Browsing](https://security.googleblog.com/2022/08/how-hash-based-safe-browsing-works-in.html).\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask warns the user about outgoing transactions to unknown addresses, transactions with potential scam contracts and connections to potential scam applications in a privacy-invasive way.", | |
| "details": "See full details on the wallet page.", | |
| "howToImprove": "\nMetaMask should ensure all scam alerting features are implemented in a privacy-preserving manner.\n\n\n* Checking arbitrary transactions for potential scams should not allow an external service to link your browsing history with your IP or Ethereum address.\n\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask provides address labeling and warns about address poisoning attacks using local address book and transaction history. For enhanced security validation, MetaMask may use Consensys services which share recipient and user addresses along with IP addresses. Users can disable external services to prevent this data sharing.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/configure/privacy/how-to-adjust-metamask-privacy-settings/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "MetaMask uses Blockaid integration to provide privacy-preserving transaction simulation and malicious contract detection without sharing transaction details with parties other than Consensys.", | |
| "urls": [ | |
| { | |
| "label": "metamask.io", | |
| "url": "https://metamask.io/news/latest/metamask-security-alerts-by-blockaid-the-new-normal-for-a-safer-transaction/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "MetaMask maintains a local phishing database to detect malicious apps and websites without revealing browsing activity to external services.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/ms/privacy-and-security/how-to-turn-on-security-alerts/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "Privacy preserving registry of malicious URLs implemented through eth-phishing-detect.", | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/MetaMask/eth-phishing-detect" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "chainVerification": { | |
| "attribute": { | |
| "attributeDisplayName": "Chain verification", | |
| "attributeId": "chainVerification", | |
| "shortQuestion": "Does the wallet verify the integrity of the chain(s) it interacts with?", | |
| "whyItMatters": "\n\"Trust but verify\" is one of the foundational principles of blockchains.\nIt refers to the ability for participants to verify that the chain data\nis valid when they interact with it.\n\nWithout such verification, users rely on trusted external providers to tell\nthem what the state of the blockchain is, similar to the web2 trust model.\nThis allows such external providers to trick wallet users into signing\ntransactions that do not end up having the user's intended effect.\n\nTo avoid this, Ethereum was designed to be verifiable on commodity\nhardware. Using a\n[light client](https://ethereum.org/en/developers/docs/nodes-and-clients/light-clients/),\nthis verification is possible without having to download the entire\nblockchain.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is chain verification evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether or not they integrate a light\nclient for verification of Ethereum L1 state.\n\n*Note*: Walletbeat currently only considers L1 chain state verification\nfor this criterion, not L2s. This is because L2 state verification is\nstill in its infancy. As L2 technology matures, Walletbeat will also\nstart requiring wallets to verify L2 chain state.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask does not verify chain integrity of the Ethereum L1.", | |
| "details": "\nMetaMask does not verify the integrity of the Ethereum L1 blockchain when retrieving chain state or simulating transactions.\n\nUsers may work around this by setting a custom RPC endpoint for the L1 chain and running their own node or external light client.\n", | |
| "howToImprove": "MetaMask should integrate [light client functionality](https://ethereum.org/en/developers/docs/nodes-and-clients/light-clients/) to verify the integrity of Ethereum chain data." | |
| } | |
| }, | |
| "transactionLegibility": { | |
| "attribute": { | |
| "attributeDisplayName": "Transaction Legibility", | |
| "attributeId": "transactionLegibility", | |
| "shortQuestion": "When signing a transaction, does the wallet show transaction details clearly?", | |
| "whyItMatters": "\nTransaction legibility is a critical security feature for wallets that allows users to verify\ntransaction details directly on their wallet's screen/window before signing. This verification\nstep is crucial for preventing attacks where malicious software might attempt to trick users\ninto signing transactions with different parameters than what they intended.\n\nWithout this, users are at the mercy of the app they are interacting with sending them a bad transactions, either because they have a bug, were hacked, or are malicious. Without a signer being able to verify if their transaction is correct, user should not send such a transaction.\n\nFull transaction legibility implementations ensure that all relevant transaction details (recipient\naddress, amount, fees, etc.) are clearly displayed on the wallet screen, EIP-712 message hashes,\nand decoded calldata, allowing users to make informed decisions before authorizing transactions.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet evaluated for clearly showing what users are signing?", | |
| "methodology": "\nWallets are evaluated based on key aspects of transaction legibility, with different criteria for software and hardware wallets:\n\n**Calldata Decoding/Display:**\nThe wallet's ability to decode and display calldata for various transaction types, including:\n- Simple transfers (ETH transfers, ERC-20 transfers, ERC-1155, and ERC-721 transfers)\n- Token approvals\n- DeFi interactions\n- Complex nested transactions\n\nFor software wallets, transaction details are evaluated according to the set of information they display:\n- For transfers (ETH transfers, ERC-20 transfers, ERC-721 transfers, ERC-1155 transfers): gas, nonce, sender, recipient, chain, amount. Some details may be collapsed by default (e.g. 'nonce'), but all of them must be accessible through the UI.\n- Non-transfer transactions (approvals, DeFi contract interactions, Safe multisig nested transactions): gas, nonce, from, chain. In addition, the wallet must explain the transaction outcome visually or in plain language; for example, for ERC-20 approvals, it should explain what token is being approved, for which contract, and for how many tokens.\n- If presented with a transaction that will revert if included onchain, the wallet must detect that the transaction would fail and warn the user beforehand.\n- If presented with a transaction for which the behavior would be nondeterministic based on predictably-changing parameters (e.g. block number), the wallet must detect that the transaction has a nondeterministic outcome and warn the user beforehand.\n\n**Software Wallet Specific Requirements:**\nFor software wallets, calldata must be displayed in multiple formats:\n- Raw hex format: Users can view the raw hexadecimal calldata\n- Formatted output: Users can view decoded, human-readable calldata\n- Copy to clipboard: Users can copy the calldata directly for verification\n\nSoftware wallets must also support calldata decoding for various transaction types, from basic token transfers to complex nested transactions.\n\n**Hardware Wallet Specific Requirements:**\nFor hardware wallets, the signature/transaction information *must* be visible on the hardware wallet device itself. Any data shown on a software wallet component is ignored for hardware wallet ratings.\n\nHardware wallets must also provide data extraction methods to allow users to independently verify transaction data:\n- Visual display: Users can view the data on the hardware wallet screen\n- QR code: Users can scan a QR code displayed on the device to extract data\n- Hashes: Users can compare hashes displayed on the device to verify data\n\n**Rating Criteria:**\n\nFor software wallets:\n- A wallet receives a passing rating if it displays calldata in all three formats (raw hex, formatted, copyable), displays all essential transaction details, and supports complex calldata decoding (including nested transactions).\n- A wallet receives a partial rating if it has some combination of these features but not all, or if calldata decoding data has not been provided.\n- A wallet receives a failing rating if it lacks calldata display capabilities or does not display essential transaction details.\n\nFor hardware wallets:\n- A wallet receives a passing rating if it supports decoding of complex nested transactions, displays all essential transaction details on the device, and provides comprehensive data extraction methods (QR codes and hashes, in addition to visual display).\n- A wallet receives a partial rating if it has some combination of these features (decoding support, transaction details display, or data extraction methods), but not all at the full level.\n- A wallet receives a failing rating if it lacks calldata decoding support, does not display essential transaction details on the device, and provides no effective data extraction methods.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask supports partial transaction legibility.", | |
| "details": "MetaMask supports some transaction legibility features, but not all. The wallet displays basic transaction details but may be missing calldata display formats, clear transaction outcome explanations for complex interactions, or simulation capabilities. Showing full transaction details is crucial for security.\n\n**Calldata Display**\n\n✓ Supported: Raw hex display, Formatted output and Copy to clipboard\n\n\n**Transaction Benchmarks**\n\n✓ Passing: ETH transfer, ERC-20 token transfer, ERC-721 NFT transfer, ERC-1155 token transfer, ZKSync USDC transfer, USDC approval, Aave supply and Failed transaction simulation\n\n⚠ Partial: Safe nested Aave supply (calldata not decoded), Safe nested multisend (calldata not decoded) and Nondeterministic transaction simulation (detected but no warning shown)\n\n\n**Message Signing**\n\n✓ Supported: EIP-712 structured data\n\n✗ Missing: Domain hash, Message hash and Safe hash\n", | |
| "howToImprove": "MetaMask should implement the following improvements:\n\n**Transaction Clarity:** Safe nested Aave supply (calldata not decoded), Safe nested multisend (calldata not decoded) and Nondeterministic transaction simulation (detected but no warning shown)\n\n**Message Signing:** Add support for displaying Domain hash, Message hash and Safe hash" | |
| } | |
| }, | |
| "hardwareWalletSupport": { | |
| "attribute": { | |
| "attributeDisplayName": "Hardware wallet support", | |
| "attributeId": "hardwareWalletSupport", | |
| "shortQuestion": "Does the wallet support connecting to hardware wallets?", | |
| "whyItMatters": "\nHardware wallets are physical devices that store a user's private keys offline,\nproviding an additional layer of security against online threats. By keeping\nprivate keys isolated from internet-connected devices, hardware wallets protect\nusers from malware, phishing attacks, and other security vulnerabilities that\ncould compromise their funds.\n\nWhen a software wallet supports hardware wallets, users can enjoy the\nconvenience and features of the software wallet while maintaining the\nsecurity benefits of keeping their private keys offline. This combination\noffers the best of both worlds: a user-friendly interface with enhanced security.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's hardware wallet support evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether it is possible to use them in\nconjunction with any physically-separate hardware wallet.\nThis means the software wallet must provide the same level of\nfunctionality as when not using a hardware wallet, and the private key\nmust never leave the hardware wallet.\n\nWallets that require the use of a separate software component (e.g.\nWalletConnect to an external desktop application that does the actual\ninterfacing with the hardware device) in order to use the hardware wallet\nget a partial rating. The need for this additional software component\nmeans the user has to do more work to get the hardware wallet working,\nwhich decreases the likelihood that users will actually do so in practice.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports hardware wallets.", | |
| "details": "MetaMask supports the following hardware wallets:\n\n* Ledger (directly via WebUSB)\n* Trezor (directly via WebUSB)\n* GridPlus (directly via WebUSB)\n* Keystone (directly via QR code)\n\t", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask supports Ledger, Trezor, Lattice (GridPlus), Keystone, OneKey, and KeepKey via its Hardware Wallet Hub.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/wallets/hardware-wallet-hub/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "passkeyImplementation": { | |
| "attribute": { | |
| "attributeDisplayName": "Passkey implementation", | |
| "attributeId": "passkeyImplementation", | |
| "shortQuestion": "Does MetaMask use a secure and efficient passkey verification library?", | |
| "whyItMatters": "\nPasskeys provide a secure and phishing-resistant way to authenticate users without relying on seed phrases. \nUsing gas-efficient and well-audited libraries for verification is crucial both for security and cost-effectiveness.\n\nP256 signature verification is computationally expensive on-chain, so using optimized libraries reduces transaction costs.\n\nSome verification libraries have undergone multiple security audits while others may have fewer or no publicly available audits.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's passkey implementation evaluated?", | |
| "methodology": "\nWallets are assessed based on the passkey verification library they use:\n\n1. **Pass (Best)**: Using the most gas-efficient and well-audited library like:\n\t- [Smooth Crypto Lib](https://github.com/get-smooth/crypto-lib)\n\t- [Daimo P256 verifier](https://github.com/daimo-eth/p256-verifier)\n\t- [OpenZeppelin P256 verifier](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/P256.sol)\n\t- [WebAuthn.sol](https://github.com/base/webauthn-sol) which falls back to Fresh Crypto Lib\n\n2. **Partial**: Using libraries that work but are less optimal:\n\t- [Fresh Crypto Lib](https://github.com/rdubois-crypto/FreshCryptoLib)\n\t- Other less common verification libraries\n\n3. **Fail**: Not implementing passkeys or using a non-recognized library.\n\nWallets that don't support smart contract accounts or are hardware wallets are exempt from this rating.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask does not implement passkeys or does not use a recognized verification library.", | |
| "details": "MetaMask either does not implement passkeys or does not use a recognized verification library for P256/R1 curve operations. Passkeys provide a more secure authentication method than traditional passwords, but proper implementation is crucial for security.", | |
| "howToImprove": "MetaMask should implement passkeys using a well-audited verification library such as [Smooth Crypto Lib](https://github.com/get-smooth/crypto-lib) 159K gas." | |
| } | |
| }, | |
| "accountRecovery": { | |
| "attribute": { | |
| "attributeDisplayName": "Account recovery", | |
| "attributeId": "accountRecovery", | |
| "shortQuestion": "How easy does the wallet make it to recover your account?", | |
| "whyItMatters": "\nWhat if you forget your seed phrase?\n\nSelf-custody is difficult and complicated for most normal users, relative\nto typical web2 accounts which often feature easy account recovery\nfeatures. Moreover, losing one's seed phrase can be a devastating\nand irrecoverable financial loss. Some users avoid self-custody due to\nthis concern.\n\n[Guardian-based recovery](https://vitalik.eth.limo/general/2021/01/11/recovery.html)\n(also known as \"Social recovery\") helps make self-custody safe and practical\nfor everyday users. Properly implemented, this keeps users safer while still\nproviding the self-sovereignty benefits of self-custody in the day-to-day.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account recovery evaluated?", | |
| "methodology": "\nWallets are evaluated based on their implementation of\n[guardian-based recovery](https://vitalik.eth.limo/general/2021/01/11/recovery.html).\n\nTo qualify, wallets must implement at least one form of guardian-based\nrecovery. They must also ensure that whatever option the user picks (as allowed by the\nwallet's onboarding flow), all the following prongs are satisfied:\n\n- If the user loses access to their device (which can include\n both their wallet's software and their passkeys), can they still recover their\n\taccount on a separate device?\n- If any single external provider goes out of business, can the user still\n recover their account?\n- If any single external provider is compromised or turns evil, can the\n user's account be taken over by that provider?\n\nThis attribute explicitly does **not** consider the scenario of the user's\nown self-custody key being compromised, as defenses against such scenarios\nare covered by a separate attribute in the Self-Sovereignty category.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "\nMetaMask's account recovery feature cannot be\nrelied upon in multiple scenarios.\n", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "urls": [ | |
| { | |
| "label": "MetaMask account recovery documentation", | |
| "url": "https://support.metamask.io/configure/wallet/social-login" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| "privacy": { | |
| "addressCorrelation": { | |
| "attribute": { | |
| "attributeDisplayName": "Wallet address privacy", | |
| "attributeId": "addressCorrelation", | |
| "shortQuestion": "Is your wallet address linkable to other information about yourself?", | |
| "whyItMatters": "\nYour wallet address is unique and permanent, which makes it easy for applications and companies\nlike Chainalysis to track your activity. In web-privacy terms, it is worse than cookies:\nwallet addresses are permanent, publicly visible, and can even be tracked across multiple\ndevices and websites.\nThe more personal information is linkable to your wallet address, the more effective such\ntracking can be. It is therefore important to use a wallet that protects your information\nfrom being linked to your wallet address.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is wallet address privacy evaluated?", | |
| "methodology": "\nIn order to qualify for a perfect rating on wallet address privacy, a\nwallet must not, *by default*, allow any external entity to link your\nwallet address to any personal information.\n\nAs Walletbeat only considers the wallet's *default* behavior, wallets may\nstill choose to offer features that allow external providers to link wallet\naddresses with personal information, so long as this is done with explicit\nuser opt-in.\n\nTo determine this, Walletbeat looks at the network requests made by\nwallets in their default configuration, and the contents of such requests.\nIf a request contains the user's wallet address, we look at whether it\nalso contains any other personal information, such as the user's name,\npseudonym, email address, phone number, CEX account information, etc.\n\nAdditionally, if such a request is not proxied, then it inherently reveals\nthe user's IP address and ties it with the user's wallet address, which is\nalso personal information.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "UNRATED", | |
| "shortExplanation": "Walletbeat lacks the information needed to determine this.", | |
| "details": "See full details on the wallet page." | |
| } | |
| }, | |
| "multiAddressCorrelation": { | |
| "attribute": { | |
| "attributeDisplayName": "Multi-address privacy", | |
| "attributeId": "multiAddressCorrelation", | |
| "shortQuestion": "Can your multiple wallet addresses be correlated with one another?", | |
| "whyItMatters": "\nYou probably have more than one wallet address configured in your wallet,\nwhich you use for different purposes and perhaps as different identities.\nThese wallet addresses all belong to you, but you would rather keep that\nfact private. It is therefore important to use a wallet that does not reveal that fact.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is multi-address privacy evaluated?", | |
| "methodology": "\nWallets are assessed based on whether an external provider can learn that\ntwo or more of the user's wallet addresses belong to the same user.\n\nAn external provider may learn of this correlation either through:\n\n- The wallet software explicitly sending this data (e.g. through\n analytics)\n- Requesting data about multiple wallet addresses in bulk, allowing\n the receiving endpoint to learn that all of these addresses belong to\n the same user. Similar correlations are also possible by IP and/or\n\ttime-based correlation of requests that each contain one wallet address.\n\nIn order to prevent this information from being revealed, wallets can\nuse a variety of strategies:\n\n* Wallets may offer the user to only have one active wallet address at\n\ta time, and only ever makes requests about the active wallet address.\n\tThe user is expected to not change their active address often.\n\tThe wallet should also ensure that any account-switching widget does\n\tnot cause bulk/simultaneous requests about multiple addresses to the\n\tsame endpoint, such as for refreshing balances.\n\tNote that this scheme, while simple to implement, is incompatible with\n\tstealth addresses. This is because stealth addresses inherently require\n\tthe user to simultaneously manage a range of addresses.\n* Wallets may look up information about multiple addresses by splitting\n\tup the requests such that each request only contains one address, then\n\tsending these requests over different proxy circuits in a manner that\n\tstaggers the requests over time. This ensures that the receiving\n\tendpoint cannot correlate addressed based on timing or IP address.\n* Wallets may distribute requests across multiple RPC endpoints owned by\n\tseparate entities for each wallet address, preventing each entity from\n\tlearning more than one wallet address.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "UNRATED", | |
| "shortExplanation": "Walletbeat lacks the information needed to determine this.", | |
| "details": "See full details on the wallet page." | |
| } | |
| }, | |
| "privateTransfers": { | |
| "attribute": { | |
| "attributeDisplayName": "Private token transfers", | |
| "attributeId": "privateTransfers", | |
| "shortQuestion": "Can you send and receive tokens without revealing your transaction history to others?", | |
| "whyItMatters": "\nData posted on public blockchains like Ethereum is publicly available to\neveryone. This means that anyone can see your transaction history.\nYou would not voluntarily post your bank statements or private purchase\nhistory online, yet this is what happens by default when transacting\non public blockchains.\n\nMany privacy solutions have emerged to solve this problem. However, to\nbe actually usable by users, **these solutions must be tightly integrated\nin wallets** and easy to use. Walletbeat looks at whether wallets\nlet users send, receive, and spend tokens privately by default.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is token transfer privacy evaluated?", | |
| "methodology": "\nIn order to get a passing rating, wallets must ensure that sending Ether\nor ERC-20 tokens to other addresses comes with privacy guarantees\n**by default**. In addition, they must ensure that users can receive and\nspend such tokens privately.\n\n\"Privately\" here means that other than the wallet user, no single entity\n(including any external provider) can infer or reconstruct the user's\ntransaction history.\n\nWalletbeat currently recognizes the following privacy-preserving token\ntransfer solutions:\n\n- [ERC-5564 Stealth Addresses](https://eips.ethereum.org/EIPS/eip-5564#wb-format=long)\n- [Tornado Cash Nova](https://nova.tornadocash.eth.limo/)\n- [Privacy Pools](https://privacypools.com/)\n- [Railgun](https://www.railgun.org/)\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask does not support private token transfers.", | |
| "details": "\nMetaMask does not support any type of private token transfers.\n\nThis means all token transfers made using MetaMask are public\ninformation and are recorded forever. Users should only make token\ntransfers if they would be comfortable publishing their bank statement\nor payment history online—their privacy level would be similar.\n", | |
| "impact": "\nAs all token transfers will be recorded publicly onchain forever,\nMetaMask should only be used for transactions where privacy is not\nand will never be needed, such as public DAO treasury operations.\n\nMetaMask **should not be used for peer-to-peer transfers**, and\nusers should keep their addresses to themselves to avoid creating\npermanent associations between their public transactions and their\npersonal identity.\n\nUsing MetaMask for real-world payments is especially **not advisable**.\nMerchants could look up a customer's balance and initiate a\n[**wrench attack**](https://github.com/jlopp/physical-bitcoin-attacks/blob/master/README.md).\nThis puts users at risk of physical and financial harm.\n", | |
| "howToImprove": "\nMetaMask should support some form of private token transfers,\nsuch as [ERC-5564: Stealth Addresses](https://eips.ethereum.org/EIPS/eip-5564#wb-format=short), and should make this the primary\nway to perform token transfers. Public token transfers should either be\nhidden under a power-user-only menu, come with important user safety\nwarnings, or deleted from the wallet's feature set.\n" | |
| } | |
| }, | |
| "appIsolation": { | |
| "attribute": { | |
| "attributeDisplayName": "App isolation", | |
| "attributeId": "appIsolation", | |
| "shortQuestion": "\nIf you connect to an app, will it be able to learn your past activity\nfrom other apps by default?\n", | |
| "whyItMatters": "\nOn the web, website `A` is not allowed to query your browsing history from\nwebsite `B` by default. This ensures your browsing activity remains private\nacross websites. This principle is enshrined in the HTTP protocol as the\n[**Same-Origin Policy**](hhttps://en.wikipedia.org/wiki/Same-origin_policy):\nby default, each website has its own isolated data about a user,\nand may not obtain any other information without explicit consent.\n\nIn web3, address reuse allows app to correlate your usage and browsing\nhistory across other apps. While this can be a useful feature that\nenables easy composability, it is also an irreversible privacy problem\nand a regression from web2-level privacy.\n\nFor web3 to avoid perpetuating this privacy problem, users need to be\nable to control the amount of information each new app may learn about\ntheir past onchain history.\n\nMaintaining per-app accounts creates complex fragmentation and UX issues\nwhich are difficult to abstract away from users. Nonetheless, address\nreuse creates an indelible data trail for users.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is app isolation evaluated?", | |
| "methodology": "\nWallets are assessed based on whether they make it easy for the user to\ncreate a distinct account for each new app they use, and whether this is\nthe default choice.\n\nWhen connecting to apps that the user previously connected to, the\nwallet must use the address(es) that were last used for this specific\napp.\n\nWallets that do not support connecting to apps are exempt from this\nattribute.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "\nMetaMask does not remember which set of addresses you last\nused when connecting to an app.\n", | |
| "details": "\nWhen connecting to an app you have connected to before,\nMetaMask does not default to the same set of addresses as you\nhad last selected.\n", | |
| "impact": "\nMetaMask makes it likely for the user to accidentally expose\nother addresses beyond the one they had initially intended for\nthe app to be able to access. Once connected, this allows the app to\ncorrelate more of the user's activity than the user had initially\nintended.\n", | |
| "howToImprove": "\nMetaMask should locally store the set of addresses that the\nuser selected when connecting to apps, and use this set of addresses\nby default when reconnecting to them.\n" | |
| } | |
| } | |
| }, | |
| "selfSovereignty": { | |
| "l1ProviderIndependence": { | |
| "attribute": { | |
| "attributeDisplayName": "L1 provider independence", | |
| "attributeId": "l1ProviderIndependence", | |
| "shortQuestion": "\nCan you use the wallet without relying on its default provider for\ninteracting with the L1 chain?\n", | |
| "whyItMatters": "\nEthereum's design goes to painstaking lengths to ensure that users can\nrun an Ethereum L1 node on commodity consumer-grade hardware and\nresidential Internet connections, and use it for interacting with L1.\n\nRunning your own node gives you several important benefits:\n\n* **Privacy**: Because the wallet can work directly on your own hardware\n\twith no outside dependencies, the wallet can query chain data without\n\trevealing private details (wallet address, IP address, etc.) to an\n\texternal RPC provider.\n* **Integrity**: Relying on an external RPC provider means that this\n\tprovider may return incorrect data about the state of the chain,\n\ttricking you into signing a transaction that ends up having a different\n\teffect than intended. Your own L1 node will verify the integrity of the\n\tchain, so such attacks cannot occur when using a self-hosted node.\n* **Censorship resistance**: Because an L1 node may broadcast transactions\n\tinto a shared mempool directly to other nodes in the network, your\n\ttransactions are not censorable by an external RPC provider that would\n\totherwise act as an intermediary.\n* **No downtime**: Because the L1 node is running on your own hardware,\n\tyou are not at risk of losing funds or opportunities due to downtime\n\tfrom an external RPC provider.\n\nHowever, **these advantages only matter if wallet users can actually take\nadvantage of them**. Thus, wallets must allow users to use a self-hosted\nnode for these benefits to be realized in practice, and must not\ncritically depend on external services to perform basic L1 interactions\nsuch as balance lookups and sending tokens.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is L1 provider independence evaluated?", | |
| "methodology": "\nIn order to qualify for this attribute, wallets must:\n\n- Allow the user to configure the L1 RPC endpoint to a self-hosted node\n before any request is made to that endpoint.\n- Support basic functions (account creation/import, balance lookups,\n token transfers) using nothing but the self-hosted node\n\t(no external services, no non-Ethereum-API calls), and whether\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "\nEven with your self-hosted node, MetaMask depends on external\nservices to perform basic tasks on Ethereum mainnet.\n", | |
| "details": "\nWhile MetaMask lets you use a self-hosted Ethereum node to\ninteract with mainnet, it still critically depends on external\nservices to perform the following basic operations:\n\n\n\n\n* Looking up your balance for an ERC-20 contract address\n* Sending ERC-20 tokens\n", | |
| "howToImprove": "\nMetaMask should ensure that basic operations work with no\nother dependency than the user-configured L1 RPC endpoint.\n", | |
| "references": [ | |
| { | |
| "explanation": "\n\t\t\t\t\t\tMetaMask lets users set custom RPC endpoints for any network,\n\t\t\t\t\t\tincluding mainnet. Before that, it contacts default endpoints\n\t\t\t\t\t\t(mainnet.infura.io and some L2s) for non-sensitive RPCs\n\t\t\t\t\t\t(`eth_blockNumber`, `net_version`).\n\t\t\t\t\t", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/configure/networks/how-to-add-a-custom-network-rpc/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "accountPortability": { | |
| "attribute": { | |
| "attributeDisplayName": "Account portability", | |
| "attributeId": "accountPortability", | |
| "shortQuestion": "\nAre you locked into this wallet?\nOr can you permissionlessly import your Ethereum account into another wallet?\n", | |
| "whyItMatters": "\nQuestion:\n**What if a wallet's dev team walked away or turned evil one day?**\n\nOne of Ethereum's core promises as an Internet upgrade is to avoid the\npossibility for user lock-in of web2. This is achieved by ensuring\naccounts are permissionlessly portable across wallets.\n\nEnsuring that accounts remain portable avoids wallets becoming lock-in\nvectors in web3. Permissionless account portability also keeps the wallet\necosystem healthy through open competition.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account portability evaluated?", | |
| "methodology": "\nWallets are rated based on whether accounts created within can be\nexported out of the wallet and imported into another, without requiring\npermission from the exporter wallet provider.\n\nFor EOA wallets based on private keys, this is relatively straightforward\nto determine. However, for more complex situations such as multisig\nwallets, Walletbeat considers whether such wallets can be made fully\nself-custodial, and whether assets and tokens can be permissionlessly\ntransferred out of the wallet.\n\nSpecifically:\n\n* **EOA wallets** are rated based on the exportability of their private\n\tkey material, and on whether such private key material is derived using\n\tthe following standards:\n\n\t* [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)\n\t\tfor deriving a binary seed from a seed phrase.\n\t* [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)\n\t\tfor deterministic hierarchical key derivation from the binary seed.\n\t* [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)\n\t\tas a standard when deriving hierarchical private keys.\n\n* **MPC wallets** are rated based on whether the user has a sufficient\n\tshares of the underlying key to have full control over the wallet in\n\ta self-custodial manner. Additionally, there must be a way for the user\n\tto generate a transaction (Walletbeat uses a token transfer out of the\n\twallet as the litmus transaction for this) without reliance on an\n\texternal API or proprietary application. The combination of these\n\tfactors ensures that the wallet remains self-custodial and that the\n\taccount cannot be frozen in-place due to an uncooperative external\n\tprovider.\n* [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short) (smart contract wallets) are rated based on\n\tthe level of control the user has over their account according to the\n\tsmart contract's control logic that the wallet uses. The user must be\n\t*in control of who controls their account* by default, and be able to\n\tpermissionlessly create asset transfer transactions. \n\tSpecifically, the rating considers:\n\n\t* Whether the user has the ability to change the cryptographic keys\n\t\tused to control the account in general, in a manner that does not\n\t\tinvolve relying on an external provider or proprietary software.\n\t* Whether the smart contract wallet's default configuration starts\n\t\tout with the user having self-custody of their account, for example\n\t\tby having a majority of the key shares in self-custody in a multisig\n\t\twallet.\n\t* Whether the generation of a token transfer transaction requires\n\t\trelying on an external provider or proprietary software, even if the\n\t\tuser has self-custody of all requisite cryptographic keys to sign\n\t\tsuch a transaction.\n\n* [EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) are not yet rated on account portability and\n\twill show up as \"Unrated\".\n\nIf a wallet supports multiple types of accounts, the rating for the account\ntype it supports that is *least* portable takes precedence. This makes the\nfinal rating act as an effective \"floor\" across the account types the\nwallet supports.\n\nIf a wallet supports multiple types of accounts and all of them have the\nsame level of portability, the account type that takes precedence is the\none that the wallet offers the user to create by default.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask follows EOA key derivation standards.", | |
| "details": "\nMetaMask generates EOA keys in a\nstandards-compliant way:\n\n* [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)\n\tfor deriving a binary seed from a seed phrase.\n* [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)\n\tfor deterministic hierarchical key derivation from the binary seed.\n* [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)\n\tas a standard when deriving hierarchical private keys.\n\nIn addition, seed phrases are exportable so that they can be\nimported into other wallets. This ensures your account is portable\nand avoids lock-in.\n\n" | |
| } | |
| }, | |
| "transactionInclusion": { | |
| "attribute": { | |
| "attributeDisplayName": "Transaction inclusion", | |
| "attributeId": "transactionInclusion", | |
| "shortQuestion": "Can the wallet withdraw L2 funds to Ethereum L1 without relying on intermediaries?", | |
| "whyItMatters": "\nOne of the core tenets of Ethereum is **censorship resistance**.\nThis means that users must be able to reliably get transactions\nincluded onchain, without the ability for intermediaries to prevent\nthis from happening.\n\nThis property is critical to ensure that all Ethereum participants are\nprovided equal-opportunity, unfettered access to Ethereum, and to ensure\nthat Ethereum is resilient to attackers that would want to prevent others\nfrom using Ethereum on such footing.\n\nIn order to uphold this property on Ethereum L2s, users must be able to\nforce transactions to be included on L2 chains as well. Most L2s\nimplement such functionality by allowing L2 transactions to be\nsubmitted on the L1, and enforcing that their sequencing logic must\nrespect such L1 force-inclusion requests by including them on the L2\nchain, typically within some fixed duration.\n\nBy verifying that the wallet supports L2 force-withdrawal transactions,\nthis attribute verifies censorship resistance at both levels: L1 and L2.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is transaction inclusion evaluated?", | |
| "methodology": "\nWallets are rated based on whether users need to trust any intermediary\nin order to withdraw their funds from L2s.\n\nThis fundamentally requires two major features:\n\n* A wallet must support the creation of an L1 transaction which forces the\n\tL2 to withdraw user funds back to the L1. This message is typically\n\tposted as an L1 transaction which forces the L2 sequencing process to\n\ttake it into account.\n* Since L2 force-withdrawal transactions require an L1 transaction, the\n\twallet must also be able to get this transaction included without\n\trelying on an external service to broadcast this transaction for block\n\tinclusion. Therefore, the wallet must also support either participating\n\tin Ethereum's L1 gossip network, or (for environments that do not\n\tsupport this such as browser extension wallets) support broadcasting\n\tL1 transactions through a user's self-hosted Ethereum node.\n\nWith these two features in place, users can withdraw their L2 funds\nwithout trusting intermediaries.\n\nWalletbeat currently only considers OP Stack chains and Arbitrum One for\nthis evaluation, but more L2 chains may be added as support for\nforce-withdrawal transaction becomes feasible for them.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "UNRATED", | |
| "shortExplanation": "Walletbeat lacks the information needed to determine this.", | |
| "details": "See full details on the wallet page." | |
| } | |
| }, | |
| "accountUnruggability": { | |
| "attribute": { | |
| "attributeDisplayName": "Account unruggability", | |
| "attributeId": "accountUnruggability", | |
| "shortQuestion": "Can the wallet developer take over your account without your consent?", | |
| "whyItMatters": "\nThe promise of crypto is to make your accounts and your funds truly yours.\nThis is what is most commonly referred to when discussing\n\"self-sovereignty\".\n\nThe underlying property that makes an account truly yours is the inability\nfor anyone other than yourself to act on your behalf or to take over your\naccount without prior consent.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account unruggability evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether there is any mechanism by which\nany entity other than the user may sign or approve transactions on behalf\nof the user's account, or can transfer ownership of the account away from\nthe user. This includes features like seed phrase backups where the wallet\ndeveloper gets to learn the user's seed phrase, or other account recovery\nfeatures that let the wallet developer unilaterally recover the user's\naccount.\n\nFully-custodial wallets (i.e. wallets where the signing key material\nresides entirely on external services) are also not self-sovereign\n(aka ruggable) by definition.\n\nFeatures that allow the user to pre-approve certain types of transactions\nahead of time are treated as maintaining self-sovereignty, so long as\nthe user controls their limits explicitly:\ntime-bound, amount-bound, destination/purpose-bound, etc.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "\nMetaMask does not allow any external service to take over\nyour account.\n", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "urls": [ | |
| { | |
| "label": "MetaMask account recovery documentation", | |
| "url": "https://support.metamask.io/configure/wallet/social-login" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| "transparency": { | |
| "openSource": { | |
| "attribute": { | |
| "attributeDisplayName": "Source code license", | |
| "attributeId": "openSource", | |
| "shortQuestion": "\nDoes the user have the ability to avoid lock-in and freely audit,\nmodify, and redistribute the wallet's source code?\n", | |
| "whyItMatters": "\n[Free & Open Source Software (FOSS) licensing](https://en.wikipedia.org/wiki/Open-source_license)\nallows a software project's source code to be freely used, modified and distributed.\nThis allows better collaboration, more transparency into the software development practices\nthat go into the project, and allows security researchers to more easily identify and report\nsecurity vulnerabilities. In short, it turns software projects into public goods.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is source code license evaluated?", | |
| "methodology": "\nWallets are assessed based whether the license of their source code meets\nthe [Open Source Initiative's definition of open source](https://en.wikipedia.org/wiki/The_Open_Source_Definition).\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask uses a proprietary license for some of its code.", | |
| "details": "\nWhile part of **MetaMask** is licensed under the\n[**MIT** license](https://spdx.org/licenses/MIT.html)\n(a Free & Open-Source (FOSS) license), others are not.\n", | |
| "howToImprove": "MetaMask should consider licensing all of its code under a Free & Open Source Software license." | |
| } | |
| }, | |
| "sourceVisibility": { | |
| "attribute": { | |
| "attributeDisplayName": "Source visibility", | |
| "attributeId": "sourceVisibility", | |
| "shortQuestion": "Is the source code for the wallet visible to the public?", | |
| "whyItMatters": "\nWhen using a wallet, users are entrusting it to preserve their funds\nsafely. This requires a high level of trust in the wallet's source code\nand in the wallet's development team. By making the wallet's source code\nvisible to the public, its source code can be more easily inspected for\nsecurity vulnerabilities and for potential malicious code.\nThis improves the wallet's security and trustworthiness.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is source visibility evaluated?", | |
| "methodology": "\nWallets are assessed based on whether or not their source code is\npublicly visible, irrespective of the license of the source code.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "\nThe source code for MetaMask is public.\n", | |
| "details": "\nThe source code for **MetaMask** is publicly viewable.\n", | |
| "impact": "\nThis allows its source code to be examined for security flaws and\nfor Walletbeat to review how the wallet works.\n", | |
| "references": [ | |
| { | |
| "explanation": "The MetaMask core repository contains various packages reused across all MetaMask versions, licensed under MIT.", | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/MetaMask/core/tree/main/packages" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "The MetaMask mobile app uses a proprietary source-available license.", | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/MetaMask/metamask-mobile/blob/main/LICENSE" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "funding": { | |
| "attribute": { | |
| "attributeDisplayName": "Funding", | |
| "attributeId": "funding", | |
| "shortQuestion": "How is the wallet's development team funded?", | |
| "whyItMatters": "\nWallets are complex, high-stakes pieces of software.\nThey must be maintained, regularly audited, and follow the continuous\nimprovements in the ecosystem.\nThis requires a reliable, transparent source of funding.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is funding evaluated?", | |
| "methodology": "\nWallets are assessed based on how sustainable, transparent, and\nuser-aligned their funding mechanisms are.\n\nWallets are typically funded by one or more of the following methods:\n\n* Self-funding from developers\n* Seeking donations from users\n* Seeking grants from foundations\n* Venture capital funding\n* Charging fees on convenience functions (e.g. swapping and bridging\n\ttokens)\n* Governance tokens\n* Commemorative NFT sales\n\nWalletbeat looks at each funding source of funding and verifies whether\nit is done transparently and in a user-aligned manner. In this context,\n\"user alignment\" refers to whether a source of funding grows as a\nfunction of the user's own goals, rather than being uncorrelated or\nanti-correlated. For example, funding acquired through hidden swap fees\nor governance token sales with undisclosed insider token allocations are\nnot user-aligned. Funding acquired through transparent swap fees, user\ndonations, or ecosystem grants are user-aligned.\n\nIn order to pass this criterion, wallets must have at least one source of\nfunding, and all of their sources of funding must be transparent to users.\nAdditionally, if the wallet is funded from multiple sources and some of\nthese sources are not user-aligned, the public must be able to determine\nthe proportion of each such funding source to the wallet's overall\nrevenue. Depending on the funding mechanism, this can be done through\npublication of a revenue breakdown page, public regulatory filings,\nor token allocation and vesting disclosures.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask is transparently funded.", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask is funded through transparent swap fees and venture capital with publicly disclosed funding rounds.", | |
| "urls": [ | |
| { | |
| "label": "consensys.io", | |
| "url": "https://consensys.io/blog/consensys-raises-450m-series-d-funding" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "feeTransparency": { | |
| "attribute": { | |
| "attributeDisplayName": "Fee transparency", | |
| "attributeId": "feeTransparency", | |
| "shortQuestion": "Does the wallet clearly display all transaction fees and their purpose?", | |
| "whyItMatters": "\nFee transparency is crucial for users to understand the full cost of their transactions.\nWithout clear fee information, users may be surprised by high transaction costs or\nhidden fees charged by the wallet.\n\nTransparent fee disclosure helps users make informed decisions about when to transact\nand which wallet to use. It also builds trust between users and wallet providers by\nensuring that all costs are clearly communicated upfront.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's fee transparency evaluated?", | |
| "methodology": "\nWallets are evaluated based on how transparently they display transaction fees and\ntransaction purposes to users.\n\nA wallet receives a passing rating if it provides comprehensive fee information,\nincluding detailed breakdowns of network fees, clear disclosure of any additional\nwallet fees. Fees may be aggregated down to one number, but a breakdown must be\navailable to the user within a single click.\n\nA wallet receives a partial rating if it provides an aggregate fee but does not\nlet the user get a detailed breakdown.\n\nA wallet fails this attribute if it provides minimal or no fee information before\ntransaction confirmation.\n\nVarious transaction types are tested: Ether and ERC-20 transfers on L1, built-in\nswaps or bridging transactions, DeFi transactions, private transactions if\nsupported. If a wallet displays fees differently depending on the type of\ntransaction, the transaction type with the **least clear** display level is\ntaken into consideration for the purpose of this attribute.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "\nMetaMask breaks down all transaction fees.\n", | |
| "details": "\nMetaMask shows a complete breakdown of all transaction\nfees by default.\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask has a built-in bridge feature that allows users to bridge assets between chains.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/learn/field-guide-to-bridges/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| "ecosystem": { | |
| "accountAbstraction": { | |
| "attribute": { | |
| "attributeDisplayName": "Account Abstraction", | |
| "attributeId": "accountAbstraction", | |
| "shortQuestion": "Is the wallet Account Abstraction ready?", | |
| "whyItMatters": "\nUser experience on Ethereum has historically suffered from the limitations of Externally-Owned Accounts (EOAs), which is the type of account most Ethereum users use today. By contrast, smart wallet accounts offer many UX and security improvements, such as the ability to:\n\n* Batch multiple transactions, removing the need for separate \"token approval\" transactions before every other token operation.\n* Pay gas fees in other tokens than Ether, or support sponsored transaction fees (with [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short))\n* Delegate some operation to trusted provider, such as allowing onchain games to withdraw small amounts of tokens without signing pop-ups for each and every transaction.\n* Change transaction authorization logic, enabling the use of Passkeys (and cellphone authentication methods) for signing transactions.\n* Update the set of keys used to control the wallet, enabling the switch to quantum-resistant encryption algorithms in the future.\n* Define account recovery rules, reducing the risk of losing access to your account when losing a private key or a device.\n\nHowever, smart wallet accounts have historically been an all-or-nothing, wallet-specific proposition for users. There was no transition path to such wallets.\n\nAs part of the [Pectra upgrade](https://eips.ethereum.org/EIPS/eip-7600),\n[EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) fixes this problem. It create a clean path for\nexisting EOAs to obtain all the UX benefits of smart wallet accounts\nand account abstraction, without the need for users to switch to a\ndifferent account address.\nThis represents a large User Experience upgrade for all Ethereum EOA users.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account abstraction support evaluated?", | |
| "methodology": "\nWallets are rated based on whether they make use of\n[EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) transactions (for EOA or MPC wallets),\nor if they support [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short) transactions\n(for smart contract wallets).\n\nThe user experience benefits of these enhancements are still in-flight\nand are expected to develop as these standards mature and are built on\ntop of. As such, Walletbeat does not currently consider *which*\nimprovements wallets provide for their users as a result of these new\ncapabilities. However, it is expected that a future version of this\nattribute would look at such improvements. For example: to verify\nthat users are able to update the signing authority of their wallets\nto a quantum-safe signature scheme.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports Account Abstraction via EIP-7702.", | |
| "details": "MetaMask supports Account Abstraction via [EIP-7702 Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=long)." | |
| } | |
| }, | |
| "addressResolution": { | |
| "attribute": { | |
| "attributeDisplayName": "Address resolution", | |
| "attributeId": "addressResolution", | |
| "shortQuestion": "Can you send funds to human-readable Ethereum addresses?", | |
| "whyItMatters": "\nEthereum addresses are hexadecimal strings (`0x...`) which are\nunreadable to humans. Phishing scams and exploits have used this to\ntrick users into sending funds to invalid addresses, for example by\ngenerating lookalike-addresses and tricking users into copy/pasting\nthem without noticing the difference.\n\nAdditionally, Ethereum's transition to layer 2 chains has changed user\nneeds when sending funds. The hexadecimal address isn't sufficient\nanymore; the user needs to ensure that they are sending funds to the\ncorrect hexadecimal address *on the correct chain*, increasing the\npotential for mistakenly sending funds to the wrong place or the wrong\nchain.\n\nAddress naming registries like ENS partially solve this problem by\nallowing more human-readable names like `username.eth` to be\nautomatically turned into the hexadecimal address. This is easier to\nshare and to accurately transfer by humans. Additionally, some address\nformat standards improve upon this further by including the destination\nchain information as part of the address itself. Such standards include:\n\n* [ERC-7828 Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=long): `user@l2chain.eth`\n* [ERC-7831 Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=long): `user.eth:l2chain`\n\nWallets that support either of these standards are able to automatically\ndetermine the destination address and chain from a human-readable string,\nand can bridge funds across chains as appropriate. This improves the user\nexperience of Ethereum and its layer 2 ecosystem while reducing the\npotential for mistakes when sending funds.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is address resolution evaluated?", | |
| "methodology": "\nWallets are rated based on the types of addresses they support sending\nfunds to.\n\nWalletbeat recognizes the following destination address formats:\n\n* Plain ENS addresses (`username.eth`) without destination chain information\n* [ERC-7828 Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=long): `user@l2chain.eth`\n* [ERC-7831 Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=long): `user.eth:l2chain`\n\nWallets receive a **pass** only if they support [ERC-7828: Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=short) or\n[ERC-7831: Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=short) (chain-specific human-readable addresses).\nWallets that support only plain ENS, with or without onchain resolution,\nreceive a **partial** rating.\n\nFor a pass, the mechanism used to perform the resolution must either:\n\n* Be done using onchain data and reusing the wallet's common chain\n interaction client, inheriting its verifiability (e.g. via light\n client) and privacy properties.\n* **OR** be done using an offchain external provider in such a way that\n the address returned by the external provider is verifiable, and\n without revealing the user's IP address to the provider.\n This ensures that:\n - The wallet cannot be tricked into sending funds to an attacker\n compromising the offchain provider's responses\n - The provider may not progressively learn the user's contacts list by\n associating its successive resolution queries by IP over time.\n\nFor addresses that **require** an offchain lookup (e.g. ENS names\nusing [offchain resolvers with CCIP-Read](https://docs.ens.domains/resolvers/ccip-read)),\nonly the portion of the work necessary to _arrive at the conclusion_\nthat an offchain lookup is necessary is considered.\nIn other words, wallets must verify that the CCIP-Read\n`OffchainLookup` details are as claimed and then perform the CCIP-Read\nthemselves, rather than trust an offchain provider to do so on their\nbehalf.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask supports sending to plain ENS addresses but not chain-specific human-readable addresses.", | |
| "details": "\nMetaMask supports sending funds to human-readable ENS addresses such as `username.eth`, but does not support chain-specific address formats that specify the destination chain.\n\nIt does so using onchain data sources using the same code as when interacting with the chain in general, inheriting its privacy and verifiability properties.\n", | |
| "howToImprove": "\nMetaMask may want to add support for sending funds to chain-specific human-readable addresses, as specified by either:\n\n* [ERC-7828 Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=long): `user@l2chain.eth`\n* [ERC-7831 Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=long): `user.eth:l2chain`\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask supports ENS domain resolution.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/learn/sending-or-receiving-a-transaction-with-ens/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "chainAbstraction": { | |
| "attribute": { | |
| "attributeDisplayName": "Chain abstraction", | |
| "attributeId": "chainAbstraction", | |
| "shortQuestion": "Does the wallet smooth out the complexities of dealing with multiple chains?", | |
| "whyItMatters": "\nEthereum activity is not limited to the main L1 chain; a lot of activity\nhas moved onto rollups and Layer 2 chains. This has allowed Ethereum to\nscale beyond what its L1 chain can handle, but has also introduced\ncomplexity and fragmentation for users and wallets to deal with.\nThey must now deal with token balances fragmented across multiple chains.\n\nTo address the UX impact of this complexity, wallets should provide\nfeatures to abstract away these issues, while remaining transparent to\nthe user when cross-chain bridging risks or fees are involved.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is chain abstraction evaluated?", | |
| "methodology": "\nWallets are rated based on how much of the complexity involved in dealing\nwith multiple chains is abstracted away from users, while keeping risks\nand fees transparent.\n\nTo get a passing rating, wallets must be cross-chain aware in how they\ndisplay account value and individual token balances:\n\n- When displaying the user account's total value, this value should sum\n\tup the user's valuations across all chains the wallet supports by\n\tdefault.\n- When displaying a specific token's balance, the balance should reflect\n\tthe user's total balance for this token across all wallet-supported\n\tchains (and on which the token exists). For rating purposes,\n\tWalletbeat looks specifically at Ether and USDT balances.\n\nIn addition, wallets must make it easy for users to move their assets\nacross chains when needed. To get a passing rating, wallets must provide\na built-in bridging feature.\n\n- This bridging feature must explain the risks involved in bridging assets\n\tacross chains. Our friends at [L2BEAT](https://l2beat.com/) do a\n\tfantastic job documenting this, but wallet developers also have a duty\n\tto explain these risks to their users.\n- For bridge operations where the net fee is larger than 1bps, the wallet\n\tmust display the fee breakdown by default.\n- When the user attempts to send tokens to an address on a chain where the\n\tuser's balance is insufficient, but for which they have sufficient tokens\n\ton another chain, the wallet should automatically propose to bridge them.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask does not add up token balances across chains.", | |
| "details": "\nMetaMask can display your account's total value across\nchains and per-chain token balances. It does not, however, show\nyour total balance for a given token (e.g. Ether or USDC) summed\nup across multiple chains. That makes it hard to see how much\nUSDC you have.\n\nCross-chain token balance awareness is one of many features that\nwallets need to be multi-chain-aware. This matters for the Ethereum\nL2 roadmap, which aims to make L2s seamless for users.\n", | |
| "howToImprove": "\nMetaMask should have a way to see token balances summed up\nacross chains.\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask displays tokens across multiple networks in a single aggregated view with estimated portfolio value", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/manage-crypto/tokens/how-to-view-your-token-balance-across-multiple-networks/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "MetaMask has a built-in bridge feature that allows users to bridge assets between chains.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/learn/field-guide-to-bridges/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "transactionBatching": { | |
| "attribute": { | |
| "attributeDisplayName": "Transaction batching", | |
| "attributeId": "transactionBatching", | |
| "shortQuestion": "Does the wallet support bundling multiple operations as a single transaction?", | |
| "whyItMatters": "\nTransaction batching is one of the longstanding features without which\nEthereum user experience (UX) has suffered. One of the most common pain\npoints for DeFi, for example, has been the need to perform separate\n\"token approval\" transactions, followed by a separate transaction to\nactually execute the user's original intent.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is transaction batching evaluated?", | |
| "methodology": "\nSmart account types such as [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short) and\n[EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) unlock the ability to perform multiple\noperations as a single transaction. This is exposed to applications\nthrough [EIP-5792 Wallet Call API](https://eips.ethereum.org/EIPS/eip-5792#wb-format=long).\n\nTo qualify for a passing rating, the wallet must:\n\n- Support at least one type of smart account.\n- Implement [EIP-5792 Wallet Call API](https://eips.ethereum.org/EIPS/eip-5792#wb-format=long).\n- Support atomic transaction bundles, as per the `atomic` capability\n declared in `wallet_getCapabilities`.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports transaction batching and atomic transaction bundles.", | |
| "details": "\nMetaMask implements [EIP-5792 Wallet Call API](https://eips.ethereum.org/EIPS/eip-5792#wb-format=long).\nThis means applications can request the wallet to bundle multiple\ntransactions into a single operation.\nFor example, this means token approval transactions need to be\nsubmitted separately from the transactions that spend these tokens.\n\nIn addition, MetaMask supports **atomic** transaction bundles.\nThis means that the wallet guarantees that a transaction bundle is\neither **all executed** or **all non-executed**. This enables some\nadvanced DeFi use-cases.\n" | |
| } | |
| }, | |
| "hardwareWalletInteroperability": { | |
| "attribute": { | |
| "attributeDisplayName": "Hardware wallet interoperability", | |
| "attributeId": "hardwareWalletInteroperability", | |
| "shortQuestion": "\nDoes the wallet support directly connecting to hardware wallets from a plurality of manufacturers?\n", | |
| "whyItMatters": "\nHardware wallets are physical devices that store a user's private keys offline,\nproviding an additional layer of security against online threats. By keeping\nprivate keys isolated from internet-connected devices, hardware wallets protect\nusers from malware, phishing attacks, and other security vulnerabilities that\ncould compromise their funds.\n\nSupporting multiple hardware wallet manufacturers preserves a healthy,\nopen, competitive, interoperable market for hardware wallets. It also\nincreases the total addressable market of users for the software wallet,\nas users that already own a specific hardware wallets will want to use a\nsoftware wallet that supports it.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's hardware wallet support evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether they directly integrate with\nhardware wallets from a plurality of major hardware wallet manufacturers.\n\nA wallet receives a passing rating if it supports hardware wallets from\nat least 3 major hardware wallet\nmanufacturers:\n\n\n* Ledger\n* Trezor\n* Keystone\n* GridPlus\n* imKey\n\nHardware wallets accessible only through WalletConnect are not counted,\nas they require relying on WalletConnect and external software beyond the\nwallet itself in order to function.\n\nA wallet receives a partial rating if it supports only two such\nhardware wallets manufacturers (without relying on WalletConnect or\nexternal software).\n\nA wallet fails this attribute if it only directly supports hardware wallets\nfrom a single manufacturer.\n\nWallets that do not directly support hardware wallets at all are exempt,\nas this check is only about hardware wallet *interoperability*.\nGeneral direct hardware wallet support is also part of Walletbeat's\nsecurity criteria as a separate attribute.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports a wide range of hardware wallets.", | |
| "details": "MetaMask supports the following hardware wallets:\n\n* Ledger (directly via WebUSB)\n* Trezor (directly via WebUSB)\n* GridPlus (directly via WebUSB)\n* Keystone (directly via QR code)\n\t", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask supports Ledger, Trezor, Lattice (GridPlus), Keystone, OneKey, and KeepKey via its Hardware Wallet Hub.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/wallets/hardware-wallet-hub/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| } | |
| }, | |
| "BROWSER": { | |
| "security": { | |
| "securityAudits": { | |
| "attribute": { | |
| "attributeDisplayName": "Security audits", | |
| "attributeId": "securityAudits", | |
| "shortQuestion": "Has the wallet's source code been reviewed by security auditors?", | |
| "whyItMatters": "\nWallets are high-stakes pieces of software that deal with sensitive\nuser data and funds. To ensure that their code is secure, industry best\npractices involve regularly submitting the wallet's source code for audit\nby an independent security auditor. These companies specialize in\nreviewing source code with an eye for security vulnerabilities. They\nreport their findings to the wallet's development team for consideration,\npointing out both flaws and potential security improvements.\n\nThese security audits matter in order to ensure the wallet's source code\nis secure, and remains that way over time. Wallet development teams\ntypically publish such audits so that wallet users can feel safer knowing\nthat the wallet's source code was independently audited.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's security auditing track record evaluated?", | |
| "methodology": "\nWallets are evaluated by their track record of published security audits.\n\nWalletbeat examines the set of published security audits of the wallet.\nTo qualify, a security audit must be publicly available, and must be\nfrom a security auditor that has a traceable corporate entity distinct\nfrom the wallet's own development team.\n\nSecurity audits typically come with one or more security flaws found,\ncategorized by level of severity. Definitions of severity vary across\nauditors, but generally anything \"medium\" or above is worth paying\nattention to.\n\nA wallet gets a passing rating if it has been audited at least once\nwithin the last 365 days, and that all medium-or-higher severity flaws\nthat were found across *all* audits (including older ones) are addressed.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask has undergone a recent security audit with all faults addressed.", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "urls": [ | |
| { | |
| "label": "assets.ctfassets.net", | |
| "url": "https://assets.ctfassets.net/clixtyxoaeas/21m4LE3WLYbgWjc33aDcp2/8252073e115688b1dc1500a9c2d33fe4/metamask-delegator-framework-audit-2024-10.pdf" | |
| } | |
| ] | |
| }, | |
| { | |
| "urls": [ | |
| { | |
| "label": "assets.ctfassets.net", | |
| "url": "https://assets.ctfassets.net/clixtyxoaeas/4sNMB55kkGw6BtAiIn08mm/f1f4a78d3901dd03848d070e15a1ff12/pentest-report_metamask-signing-snap.pdf" | |
| } | |
| ] | |
| }, | |
| { | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/Cyfrin/cyfrin-audit-reports/blob/main/reports/2025-03-18-cyfrin-Metamask-DelegationFramework1-v2.0.pdf" | |
| } | |
| ] | |
| }, | |
| { | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/Cyfrin/cyfrin-audit-reports/blob/main/reports/2025-04-01-cyfrin-Metamask-DelegationFramework2-v2.0.pdf" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "scamPrevention": { | |
| "attribute": { | |
| "attributeDisplayName": "Scam prevention", | |
| "attributeId": "scamPrevention", | |
| "shortQuestion": "Does the wallet warn the user about potential scams?", | |
| "whyItMatters": "Transactions in Ethereum are very difficult to reverse, and there is no shortage of scams. Wallets have a role to play in helping users avoid known scams ahead of the user making the transaction.", | |
| "howIsEvaluated": { | |
| "heading": "How is scam prevention evaluated?", | |
| "methodology": "\nWallets are rated based on whether they alert the user about potential\nscams. This is measured along three scenarios:\n**Does the wallet *warn* the user when...**\n\n* Sending funds to an address the user has never previously sent or\n\treceived funds from before\n* Interacting with a contract that is known to be a scam\n* Interacting with a contract that the user has never previously\n\tinteracted with before\n* Interacting with a contract that has only recently been deployed\n\tonchain\n* Connecting to an app that is known to be a scam\n\nFor payments-focused wallets that do not support interacting with\narbitrary contracts or external applications, only the payment scenario\napplies.\n\nNote that wallets should only *warn* the user about such scenarios, not\noutright *prevent* the user from making such transactions, as preventing\nthem entirely would limit the user's ability to have real sovereignty\nover their own wallet.\n\nWallets are also rated based on whether these warnings are implemented\nin a privacy-preserving manner. Specifically:\n\n* When sending funds, does the lookup for past interactions with that\n\taddress unconditionally reveal the sender and recipient addresses to an\n\texternal provider other than the wallet's default RPC provider for this\n\tchain?\n\n\t* Wallets can implement this feature in a privacy-preserving manner by\n\t\tmaintaining a local set of known addresses.\n\n* When interacting with a contract, does the check whether that contract\n\tis known to be a scam reveal the user's IP address together with the\n\tcontract address about to be interacted with?\n\n\t* This is a privacy leak similar to that of leaking the user's\n\t\tbrowsing history, as contract addresses are usually closely tied to\n\t\tthe application being visited.\n\t* Wallets can implement this feature in a privacy-preserving manner by\n\t\tmaintaining a local, frequently-updated cache of known-scam contract\n\t\taddresses.\n\n* When connecting to an application, does the check whether that\n\tapplication reveal the domain name or URL of the application being used?\n\n\t* If leaking full URLs, this is a privacy leak similar to that of\n\t\tleaking the user's browsing history.\n\t* If leaking domain names only, they must not be linkable to the\n\t\tuser's IP address or Ethereum address.\n\t* Wallets can implement this feature in a privacy-preserving manner by\n\t\tmaintaining a local, frequently-updated cache of known-scam contract\n\t\tURLs, or by looking up such a list based on a domain hash prefix\n\t\tlike [Safe Browsing](https://security.googleblog.com/2022/08/how-hash-based-safe-browsing-works-in.html).\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask warns the user about outgoing transactions to unknown addresses, transactions with potential scam contracts and connections to potential scam applications in a privacy-invasive way.", | |
| "details": "See full details on the wallet page.", | |
| "howToImprove": "\nMetaMask should ensure all scam alerting features are implemented in a privacy-preserving manner.\n\n\n* Checking arbitrary transactions for potential scams should not allow an external service to link your browsing history with your IP or Ethereum address.\n\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask provides address labeling and warns about address poisoning attacks using local address book and transaction history. For enhanced security validation, MetaMask may use Consensys services which share recipient and user addresses along with IP addresses. Users can disable external services to prevent this data sharing.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/configure/privacy/how-to-adjust-metamask-privacy-settings/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "MetaMask uses Blockaid integration to provide privacy-preserving transaction simulation and malicious contract detection without sharing transaction details with parties other than Consensys.", | |
| "urls": [ | |
| { | |
| "label": "metamask.io", | |
| "url": "https://metamask.io/news/latest/metamask-security-alerts-by-blockaid-the-new-normal-for-a-safer-transaction/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "MetaMask maintains a local phishing database to detect malicious apps and websites without revealing browsing activity to external services.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/ms/privacy-and-security/how-to-turn-on-security-alerts/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "Privacy preserving registry of malicious URLs implemented through eth-phishing-detect.", | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/MetaMask/eth-phishing-detect" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "chainVerification": { | |
| "attribute": { | |
| "attributeDisplayName": "Chain verification", | |
| "attributeId": "chainVerification", | |
| "shortQuestion": "Does the wallet verify the integrity of the chain(s) it interacts with?", | |
| "whyItMatters": "\n\"Trust but verify\" is one of the foundational principles of blockchains.\nIt refers to the ability for participants to verify that the chain data\nis valid when they interact with it.\n\nWithout such verification, users rely on trusted external providers to tell\nthem what the state of the blockchain is, similar to the web2 trust model.\nThis allows such external providers to trick wallet users into signing\ntransactions that do not end up having the user's intended effect.\n\nTo avoid this, Ethereum was designed to be verifiable on commodity\nhardware. Using a\n[light client](https://ethereum.org/en/developers/docs/nodes-and-clients/light-clients/),\nthis verification is possible without having to download the entire\nblockchain.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is chain verification evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether or not they integrate a light\nclient for verification of Ethereum L1 state.\n\n*Note*: Walletbeat currently only considers L1 chain state verification\nfor this criterion, not L2s. This is because L2 state verification is\nstill in its infancy. As L2 technology matures, Walletbeat will also\nstart requiring wallets to verify L2 chain state.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask does not verify chain integrity of the Ethereum L1.", | |
| "details": "\nMetaMask does not verify the integrity of the Ethereum L1 blockchain when retrieving chain state or simulating transactions.\n\nUsers may work around this by setting a custom RPC endpoint for the L1 chain and running their own node or external light client.\n", | |
| "howToImprove": "MetaMask should integrate [light client functionality](https://ethereum.org/en/developers/docs/nodes-and-clients/light-clients/) to verify the integrity of Ethereum chain data." | |
| } | |
| }, | |
| "transactionLegibility": { | |
| "attribute": { | |
| "attributeDisplayName": "Transaction Legibility", | |
| "attributeId": "transactionLegibility", | |
| "shortQuestion": "When signing a transaction, does the wallet show transaction details clearly?", | |
| "whyItMatters": "\nTransaction legibility is a critical security feature for wallets that allows users to verify\ntransaction details directly on their wallet's screen/window before signing. This verification\nstep is crucial for preventing attacks where malicious software might attempt to trick users\ninto signing transactions with different parameters than what they intended.\n\nWithout this, users are at the mercy of the app they are interacting with sending them a bad transactions, either because they have a bug, were hacked, or are malicious. Without a signer being able to verify if their transaction is correct, user should not send such a transaction.\n\nFull transaction legibility implementations ensure that all relevant transaction details (recipient\naddress, amount, fees, etc.) are clearly displayed on the wallet screen, EIP-712 message hashes,\nand decoded calldata, allowing users to make informed decisions before authorizing transactions.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet evaluated for clearly showing what users are signing?", | |
| "methodology": "\nWallets are evaluated based on key aspects of transaction legibility, with different criteria for software and hardware wallets:\n\n**Calldata Decoding/Display:**\nThe wallet's ability to decode and display calldata for various transaction types, including:\n- Simple transfers (ETH transfers, ERC-20 transfers, ERC-1155, and ERC-721 transfers)\n- Token approvals\n- DeFi interactions\n- Complex nested transactions\n\nFor software wallets, transaction details are evaluated according to the set of information they display:\n- For transfers (ETH transfers, ERC-20 transfers, ERC-721 transfers, ERC-1155 transfers): gas, nonce, sender, recipient, chain, amount. Some details may be collapsed by default (e.g. 'nonce'), but all of them must be accessible through the UI.\n- Non-transfer transactions (approvals, DeFi contract interactions, Safe multisig nested transactions): gas, nonce, from, chain. In addition, the wallet must explain the transaction outcome visually or in plain language; for example, for ERC-20 approvals, it should explain what token is being approved, for which contract, and for how many tokens.\n- If presented with a transaction that will revert if included onchain, the wallet must detect that the transaction would fail and warn the user beforehand.\n- If presented with a transaction for which the behavior would be nondeterministic based on predictably-changing parameters (e.g. block number), the wallet must detect that the transaction has a nondeterministic outcome and warn the user beforehand.\n\n**Software Wallet Specific Requirements:**\nFor software wallets, calldata must be displayed in multiple formats:\n- Raw hex format: Users can view the raw hexadecimal calldata\n- Formatted output: Users can view decoded, human-readable calldata\n- Copy to clipboard: Users can copy the calldata directly for verification\n\nSoftware wallets must also support calldata decoding for various transaction types, from basic token transfers to complex nested transactions.\n\n**Hardware Wallet Specific Requirements:**\nFor hardware wallets, the signature/transaction information *must* be visible on the hardware wallet device itself. Any data shown on a software wallet component is ignored for hardware wallet ratings.\n\nHardware wallets must also provide data extraction methods to allow users to independently verify transaction data:\n- Visual display: Users can view the data on the hardware wallet screen\n- QR code: Users can scan a QR code displayed on the device to extract data\n- Hashes: Users can compare hashes displayed on the device to verify data\n\n**Rating Criteria:**\n\nFor software wallets:\n- A wallet receives a passing rating if it displays calldata in all three formats (raw hex, formatted, copyable), displays all essential transaction details, and supports complex calldata decoding (including nested transactions).\n- A wallet receives a partial rating if it has some combination of these features but not all, or if calldata decoding data has not been provided.\n- A wallet receives a failing rating if it lacks calldata display capabilities or does not display essential transaction details.\n\nFor hardware wallets:\n- A wallet receives a passing rating if it supports decoding of complex nested transactions, displays all essential transaction details on the device, and provides comprehensive data extraction methods (QR codes and hashes, in addition to visual display).\n- A wallet receives a partial rating if it has some combination of these features (decoding support, transaction details display, or data extraction methods), but not all at the full level.\n- A wallet receives a failing rating if it lacks calldata decoding support, does not display essential transaction details on the device, and provides no effective data extraction methods.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask supports partial transaction legibility.", | |
| "details": "MetaMask supports some transaction legibility features, but not all. The wallet displays basic transaction details but may be missing calldata display formats, clear transaction outcome explanations for complex interactions, or simulation capabilities. Showing full transaction details is crucial for security.\n\n**Calldata Display**\n\n✓ Supported: Raw hex display, Formatted output and Copy to clipboard\n\n\n**Transaction Benchmarks**\n\n✓ Passing: ETH transfer, ERC-20 token transfer, ERC-721 NFT transfer, ERC-1155 token transfer, ZKSync USDC transfer, USDC approval, Aave supply and Failed transaction simulation\n\n⚠ Partial: Safe nested Aave supply (calldata not decoded), Safe nested multisend (calldata not decoded) and Nondeterministic transaction simulation (detected but no warning shown)\n\n\n**Message Signing**\n\n✓ Supported: EIP-712 structured data\n\n✗ Missing: Domain hash, Message hash and Safe hash\n", | |
| "howToImprove": "MetaMask should implement the following improvements:\n\n**Transaction Clarity:** Safe nested Aave supply (calldata not decoded), Safe nested multisend (calldata not decoded) and Nondeterministic transaction simulation (detected but no warning shown)\n\n**Message Signing:** Add support for displaying Domain hash, Message hash and Safe hash" | |
| } | |
| }, | |
| "hardwareWalletSupport": { | |
| "attribute": { | |
| "attributeDisplayName": "Hardware wallet support", | |
| "attributeId": "hardwareWalletSupport", | |
| "shortQuestion": "Does the wallet support connecting to hardware wallets?", | |
| "whyItMatters": "\nHardware wallets are physical devices that store a user's private keys offline,\nproviding an additional layer of security against online threats. By keeping\nprivate keys isolated from internet-connected devices, hardware wallets protect\nusers from malware, phishing attacks, and other security vulnerabilities that\ncould compromise their funds.\n\nWhen a software wallet supports hardware wallets, users can enjoy the\nconvenience and features of the software wallet while maintaining the\nsecurity benefits of keeping their private keys offline. This combination\noffers the best of both worlds: a user-friendly interface with enhanced security.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's hardware wallet support evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether it is possible to use them in\nconjunction with any physically-separate hardware wallet.\nThis means the software wallet must provide the same level of\nfunctionality as when not using a hardware wallet, and the private key\nmust never leave the hardware wallet.\n\nWallets that require the use of a separate software component (e.g.\nWalletConnect to an external desktop application that does the actual\ninterfacing with the hardware device) in order to use the hardware wallet\nget a partial rating. The need for this additional software component\nmeans the user has to do more work to get the hardware wallet working,\nwhich decreases the likelihood that users will actually do so in practice.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports hardware wallets.", | |
| "details": "MetaMask supports the following hardware wallets:\n\n* Ledger (directly via WebUSB)\n* Trezor (directly via WebUSB)\n* GridPlus (directly via WebUSB)\n* Keystone (directly via QR code)\n\t", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask supports Ledger, Trezor, Lattice (GridPlus), Keystone, OneKey, and KeepKey via its Hardware Wallet Hub.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/wallets/hardware-wallet-hub/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "passkeyImplementation": { | |
| "attribute": { | |
| "attributeDisplayName": "Passkey implementation", | |
| "attributeId": "passkeyImplementation", | |
| "shortQuestion": "Does MetaMask use a secure and efficient passkey verification library?", | |
| "whyItMatters": "\nPasskeys provide a secure and phishing-resistant way to authenticate users without relying on seed phrases. \nUsing gas-efficient and well-audited libraries for verification is crucial both for security and cost-effectiveness.\n\nP256 signature verification is computationally expensive on-chain, so using optimized libraries reduces transaction costs.\n\nSome verification libraries have undergone multiple security audits while others may have fewer or no publicly available audits.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's passkey implementation evaluated?", | |
| "methodology": "\nWallets are assessed based on the passkey verification library they use:\n\n1. **Pass (Best)**: Using the most gas-efficient and well-audited library like:\n\t- [Smooth Crypto Lib](https://github.com/get-smooth/crypto-lib)\n\t- [Daimo P256 verifier](https://github.com/daimo-eth/p256-verifier)\n\t- [OpenZeppelin P256 verifier](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/P256.sol)\n\t- [WebAuthn.sol](https://github.com/base/webauthn-sol) which falls back to Fresh Crypto Lib\n\n2. **Partial**: Using libraries that work but are less optimal:\n\t- [Fresh Crypto Lib](https://github.com/rdubois-crypto/FreshCryptoLib)\n\t- Other less common verification libraries\n\n3. **Fail**: Not implementing passkeys or using a non-recognized library.\n\nWallets that don't support smart contract accounts or are hardware wallets are exempt from this rating.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask does not implement passkeys or does not use a recognized verification library.", | |
| "details": "MetaMask either does not implement passkeys or does not use a recognized verification library for P256/R1 curve operations. Passkeys provide a more secure authentication method than traditional passwords, but proper implementation is crucial for security.", | |
| "howToImprove": "MetaMask should implement passkeys using a well-audited verification library such as [Smooth Crypto Lib](https://github.com/get-smooth/crypto-lib) 159K gas." | |
| } | |
| }, | |
| "accountRecovery": { | |
| "attribute": { | |
| "attributeDisplayName": "Account recovery", | |
| "attributeId": "accountRecovery", | |
| "shortQuestion": "How easy does the wallet make it to recover your account?", | |
| "whyItMatters": "\nWhat if you forget your seed phrase?\n\nSelf-custody is difficult and complicated for most normal users, relative\nto typical web2 accounts which often feature easy account recovery\nfeatures. Moreover, losing one's seed phrase can be a devastating\nand irrecoverable financial loss. Some users avoid self-custody due to\nthis concern.\n\n[Guardian-based recovery](https://vitalik.eth.limo/general/2021/01/11/recovery.html)\n(also known as \"Social recovery\") helps make self-custody safe and practical\nfor everyday users. Properly implemented, this keeps users safer while still\nproviding the self-sovereignty benefits of self-custody in the day-to-day.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account recovery evaluated?", | |
| "methodology": "\nWallets are evaluated based on their implementation of\n[guardian-based recovery](https://vitalik.eth.limo/general/2021/01/11/recovery.html).\n\nTo qualify, wallets must implement at least one form of guardian-based\nrecovery. They must also ensure that whatever option the user picks (as allowed by the\nwallet's onboarding flow), all the following prongs are satisfied:\n\n- If the user loses access to their device (which can include\n both their wallet's software and their passkeys), can they still recover their\n\taccount on a separate device?\n- If any single external provider goes out of business, can the user still\n recover their account?\n- If any single external provider is compromised or turns evil, can the\n user's account be taken over by that provider?\n\nThis attribute explicitly does **not** consider the scenario of the user's\nown self-custody key being compromised, as defenses against such scenarios\nare covered by a separate attribute in the Self-Sovereignty category.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "\nMetaMask's account recovery feature cannot be\nrelied upon in multiple scenarios.\n", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "urls": [ | |
| { | |
| "label": "MetaMask account recovery documentation", | |
| "url": "https://support.metamask.io/configure/wallet/social-login" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| "privacy": { | |
| "addressCorrelation": { | |
| "attribute": { | |
| "attributeDisplayName": "Wallet address privacy", | |
| "attributeId": "addressCorrelation", | |
| "shortQuestion": "Is your wallet address linkable to other information about yourself?", | |
| "whyItMatters": "\nYour wallet address is unique and permanent, which makes it easy for applications and companies\nlike Chainalysis to track your activity. In web-privacy terms, it is worse than cookies:\nwallet addresses are permanent, publicly visible, and can even be tracked across multiple\ndevices and websites.\nThe more personal information is linkable to your wallet address, the more effective such\ntracking can be. It is therefore important to use a wallet that protects your information\nfrom being linked to your wallet address.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is wallet address privacy evaluated?", | |
| "methodology": "\nIn order to qualify for a perfect rating on wallet address privacy, a\nwallet must not, *by default*, allow any external entity to link your\nwallet address to any personal information.\n\nAs Walletbeat only considers the wallet's *default* behavior, wallets may\nstill choose to offer features that allow external providers to link wallet\naddresses with personal information, so long as this is done with explicit\nuser opt-in.\n\nTo determine this, Walletbeat looks at the network requests made by\nwallets in their default configuration, and the contents of such requests.\nIf a request contains the user's wallet address, we look at whether it\nalso contains any other personal information, such as the user's name,\npseudonym, email address, phone number, CEX account information, etc.\n\nAdditionally, if such a request is not proxied, then it inherently reveals\nthe user's IP address and ties it with the user's wallet address, which is\nalso personal information.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "UNRATED", | |
| "shortExplanation": "Walletbeat lacks the information needed to determine this.", | |
| "details": "See full details on the wallet page." | |
| } | |
| }, | |
| "multiAddressCorrelation": { | |
| "attribute": { | |
| "attributeDisplayName": "Multi-address privacy", | |
| "attributeId": "multiAddressCorrelation", | |
| "shortQuestion": "Can your multiple wallet addresses be correlated with one another?", | |
| "whyItMatters": "\nYou probably have more than one wallet address configured in your wallet,\nwhich you use for different purposes and perhaps as different identities.\nThese wallet addresses all belong to you, but you would rather keep that\nfact private. It is therefore important to use a wallet that does not reveal that fact.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is multi-address privacy evaluated?", | |
| "methodology": "\nWallets are assessed based on whether an external provider can learn that\ntwo or more of the user's wallet addresses belong to the same user.\n\nAn external provider may learn of this correlation either through:\n\n- The wallet software explicitly sending this data (e.g. through\n analytics)\n- Requesting data about multiple wallet addresses in bulk, allowing\n the receiving endpoint to learn that all of these addresses belong to\n the same user. Similar correlations are also possible by IP and/or\n\ttime-based correlation of requests that each contain one wallet address.\n\nIn order to prevent this information from being revealed, wallets can\nuse a variety of strategies:\n\n* Wallets may offer the user to only have one active wallet address at\n\ta time, and only ever makes requests about the active wallet address.\n\tThe user is expected to not change their active address often.\n\tThe wallet should also ensure that any account-switching widget does\n\tnot cause bulk/simultaneous requests about multiple addresses to the\n\tsame endpoint, such as for refreshing balances.\n\tNote that this scheme, while simple to implement, is incompatible with\n\tstealth addresses. This is because stealth addresses inherently require\n\tthe user to simultaneously manage a range of addresses.\n* Wallets may look up information about multiple addresses by splitting\n\tup the requests such that each request only contains one address, then\n\tsending these requests over different proxy circuits in a manner that\n\tstaggers the requests over time. This ensures that the receiving\n\tendpoint cannot correlate addressed based on timing or IP address.\n* Wallets may distribute requests across multiple RPC endpoints owned by\n\tseparate entities for each wallet address, preventing each entity from\n\tlearning more than one wallet address.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "UNRATED", | |
| "shortExplanation": "Walletbeat lacks the information needed to determine this.", | |
| "details": "See full details on the wallet page." | |
| } | |
| }, | |
| "privateTransfers": { | |
| "attribute": { | |
| "attributeDisplayName": "Private token transfers", | |
| "attributeId": "privateTransfers", | |
| "shortQuestion": "Can you send and receive tokens without revealing your transaction history to others?", | |
| "whyItMatters": "\nData posted on public blockchains like Ethereum is publicly available to\neveryone. This means that anyone can see your transaction history.\nYou would not voluntarily post your bank statements or private purchase\nhistory online, yet this is what happens by default when transacting\non public blockchains.\n\nMany privacy solutions have emerged to solve this problem. However, to\nbe actually usable by users, **these solutions must be tightly integrated\nin wallets** and easy to use. Walletbeat looks at whether wallets\nlet users send, receive, and spend tokens privately by default.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is token transfer privacy evaluated?", | |
| "methodology": "\nIn order to get a passing rating, wallets must ensure that sending Ether\nor ERC-20 tokens to other addresses comes with privacy guarantees\n**by default**. In addition, they must ensure that users can receive and\nspend such tokens privately.\n\n\"Privately\" here means that other than the wallet user, no single entity\n(including any external provider) can infer or reconstruct the user's\ntransaction history.\n\nWalletbeat currently recognizes the following privacy-preserving token\ntransfer solutions:\n\n- [ERC-5564 Stealth Addresses](https://eips.ethereum.org/EIPS/eip-5564#wb-format=long)\n- [Tornado Cash Nova](https://nova.tornadocash.eth.limo/)\n- [Privacy Pools](https://privacypools.com/)\n- [Railgun](https://www.railgun.org/)\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask does not support private token transfers.", | |
| "details": "\nMetaMask does not support any type of private token transfers.\n\nThis means all token transfers made using MetaMask are public\ninformation and are recorded forever. Users should only make token\ntransfers if they would be comfortable publishing their bank statement\nor payment history online—their privacy level would be similar.\n", | |
| "impact": "\nAs all token transfers will be recorded publicly onchain forever,\nMetaMask should only be used for transactions where privacy is not\nand will never be needed, such as public DAO treasury operations.\n\nMetaMask **should not be used for peer-to-peer transfers**, and\nusers should keep their addresses to themselves to avoid creating\npermanent associations between their public transactions and their\npersonal identity.\n\nUsing MetaMask for real-world payments is especially **not advisable**.\nMerchants could look up a customer's balance and initiate a\n[**wrench attack**](https://github.com/jlopp/physical-bitcoin-attacks/blob/master/README.md).\nThis puts users at risk of physical and financial harm.\n", | |
| "howToImprove": "\nMetaMask should support some form of private token transfers,\nsuch as [ERC-5564: Stealth Addresses](https://eips.ethereum.org/EIPS/eip-5564#wb-format=short), and should make this the primary\nway to perform token transfers. Public token transfers should either be\nhidden under a power-user-only menu, come with important user safety\nwarnings, or deleted from the wallet's feature set.\n" | |
| } | |
| }, | |
| "appIsolation": { | |
| "attribute": { | |
| "attributeDisplayName": "App isolation", | |
| "attributeId": "appIsolation", | |
| "shortQuestion": "\nIf you connect to an app, will it be able to learn your past activity\nfrom other apps by default?\n", | |
| "whyItMatters": "\nOn the web, website `A` is not allowed to query your browsing history from\nwebsite `B` by default. This ensures your browsing activity remains private\nacross websites. This principle is enshrined in the HTTP protocol as the\n[**Same-Origin Policy**](hhttps://en.wikipedia.org/wiki/Same-origin_policy):\nby default, each website has its own isolated data about a user,\nand may not obtain any other information without explicit consent.\n\nIn web3, address reuse allows app to correlate your usage and browsing\nhistory across other apps. While this can be a useful feature that\nenables easy composability, it is also an irreversible privacy problem\nand a regression from web2-level privacy.\n\nFor web3 to avoid perpetuating this privacy problem, users need to be\nable to control the amount of information each new app may learn about\ntheir past onchain history.\n\nMaintaining per-app accounts creates complex fragmentation and UX issues\nwhich are difficult to abstract away from users. Nonetheless, address\nreuse creates an indelible data trail for users.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is app isolation evaluated?", | |
| "methodology": "\nWallets are assessed based on whether they make it easy for the user to\ncreate a distinct account for each new app they use, and whether this is\nthe default choice.\n\nWhen connecting to apps that the user previously connected to, the\nwallet must use the address(es) that were last used for this specific\napp.\n\nWallets that do not support connecting to apps are exempt from this\nattribute.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "\nMetaMask does not remember which set of addresses you last\nused when connecting to an app.\n", | |
| "details": "\nWhen connecting to an app you have connected to before,\nMetaMask does not default to the same set of addresses as you\nhad last selected.\n", | |
| "impact": "\nMetaMask makes it likely for the user to accidentally expose\nother addresses beyond the one they had initially intended for\nthe app to be able to access. Once connected, this allows the app to\ncorrelate more of the user's activity than the user had initially\nintended.\n", | |
| "howToImprove": "\nMetaMask should locally store the set of addresses that the\nuser selected when connecting to apps, and use this set of addresses\nby default when reconnecting to them.\n" | |
| } | |
| } | |
| }, | |
| "selfSovereignty": { | |
| "l1ProviderIndependence": { | |
| "attribute": { | |
| "attributeDisplayName": "L1 provider independence", | |
| "attributeId": "l1ProviderIndependence", | |
| "shortQuestion": "\nCan you use the wallet without relying on its default provider for\ninteracting with the L1 chain?\n", | |
| "whyItMatters": "\nEthereum's design goes to painstaking lengths to ensure that users can\nrun an Ethereum L1 node on commodity consumer-grade hardware and\nresidential Internet connections, and use it for interacting with L1.\n\nRunning your own node gives you several important benefits:\n\n* **Privacy**: Because the wallet can work directly on your own hardware\n\twith no outside dependencies, the wallet can query chain data without\n\trevealing private details (wallet address, IP address, etc.) to an\n\texternal RPC provider.\n* **Integrity**: Relying on an external RPC provider means that this\n\tprovider may return incorrect data about the state of the chain,\n\ttricking you into signing a transaction that ends up having a different\n\teffect than intended. Your own L1 node will verify the integrity of the\n\tchain, so such attacks cannot occur when using a self-hosted node.\n* **Censorship resistance**: Because an L1 node may broadcast transactions\n\tinto a shared mempool directly to other nodes in the network, your\n\ttransactions are not censorable by an external RPC provider that would\n\totherwise act as an intermediary.\n* **No downtime**: Because the L1 node is running on your own hardware,\n\tyou are not at risk of losing funds or opportunities due to downtime\n\tfrom an external RPC provider.\n\nHowever, **these advantages only matter if wallet users can actually take\nadvantage of them**. Thus, wallets must allow users to use a self-hosted\nnode for these benefits to be realized in practice, and must not\ncritically depend on external services to perform basic L1 interactions\nsuch as balance lookups and sending tokens.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is L1 provider independence evaluated?", | |
| "methodology": "\nIn order to qualify for this attribute, wallets must:\n\n- Allow the user to configure the L1 RPC endpoint to a self-hosted node\n before any request is made to that endpoint.\n- Support basic functions (account creation/import, balance lookups,\n token transfers) using nothing but the self-hosted node\n\t(no external services, no non-Ethereum-API calls), and whether\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "\nEven with your self-hosted node, MetaMask depends on external\nservices to perform basic tasks on Ethereum mainnet.\n", | |
| "details": "\nWhile MetaMask lets you use a self-hosted Ethereum node to\ninteract with mainnet, it still critically depends on external\nservices to perform the following basic operations:\n\n\n\n\n* Looking up your balance for an ERC-20 contract address\n* Sending ERC-20 tokens\n", | |
| "howToImprove": "\nMetaMask should ensure that basic operations work with no\nother dependency than the user-configured L1 RPC endpoint.\n", | |
| "references": [ | |
| { | |
| "explanation": "\n\t\t\t\t\t\tMetaMask lets users set custom RPC endpoints for any network,\n\t\t\t\t\t\tincluding mainnet. Before that, it contacts default endpoints\n\t\t\t\t\t\t(mainnet.infura.io and some L2s) for non-sensitive RPCs\n\t\t\t\t\t\t(`eth_blockNumber`, `net_version`).\n\t\t\t\t\t", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/configure/networks/how-to-add-a-custom-network-rpc/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "accountPortability": { | |
| "attribute": { | |
| "attributeDisplayName": "Account portability", | |
| "attributeId": "accountPortability", | |
| "shortQuestion": "\nAre you locked into this wallet?\nOr can you permissionlessly import your Ethereum account into another wallet?\n", | |
| "whyItMatters": "\nQuestion:\n**What if a wallet's dev team walked away or turned evil one day?**\n\nOne of Ethereum's core promises as an Internet upgrade is to avoid the\npossibility for user lock-in of web2. This is achieved by ensuring\naccounts are permissionlessly portable across wallets.\n\nEnsuring that accounts remain portable avoids wallets becoming lock-in\nvectors in web3. Permissionless account portability also keeps the wallet\necosystem healthy through open competition.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account portability evaluated?", | |
| "methodology": "\nWallets are rated based on whether accounts created within can be\nexported out of the wallet and imported into another, without requiring\npermission from the exporter wallet provider.\n\nFor EOA wallets based on private keys, this is relatively straightforward\nto determine. However, for more complex situations such as multisig\nwallets, Walletbeat considers whether such wallets can be made fully\nself-custodial, and whether assets and tokens can be permissionlessly\ntransferred out of the wallet.\n\nSpecifically:\n\n* **EOA wallets** are rated based on the exportability of their private\n\tkey material, and on whether such private key material is derived using\n\tthe following standards:\n\n\t* [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)\n\t\tfor deriving a binary seed from a seed phrase.\n\t* [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)\n\t\tfor deterministic hierarchical key derivation from the binary seed.\n\t* [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)\n\t\tas a standard when deriving hierarchical private keys.\n\n* **MPC wallets** are rated based on whether the user has a sufficient\n\tshares of the underlying key to have full control over the wallet in\n\ta self-custodial manner. Additionally, there must be a way for the user\n\tto generate a transaction (Walletbeat uses a token transfer out of the\n\twallet as the litmus transaction for this) without reliance on an\n\texternal API or proprietary application. The combination of these\n\tfactors ensures that the wallet remains self-custodial and that the\n\taccount cannot be frozen in-place due to an uncooperative external\n\tprovider.\n* [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short) (smart contract wallets) are rated based on\n\tthe level of control the user has over their account according to the\n\tsmart contract's control logic that the wallet uses. The user must be\n\t*in control of who controls their account* by default, and be able to\n\tpermissionlessly create asset transfer transactions. \n\tSpecifically, the rating considers:\n\n\t* Whether the user has the ability to change the cryptographic keys\n\t\tused to control the account in general, in a manner that does not\n\t\tinvolve relying on an external provider or proprietary software.\n\t* Whether the smart contract wallet's default configuration starts\n\t\tout with the user having self-custody of their account, for example\n\t\tby having a majority of the key shares in self-custody in a multisig\n\t\twallet.\n\t* Whether the generation of a token transfer transaction requires\n\t\trelying on an external provider or proprietary software, even if the\n\t\tuser has self-custody of all requisite cryptographic keys to sign\n\t\tsuch a transaction.\n\n* [EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) are not yet rated on account portability and\n\twill show up as \"Unrated\".\n\nIf a wallet supports multiple types of accounts, the rating for the account\ntype it supports that is *least* portable takes precedence. This makes the\nfinal rating act as an effective \"floor\" across the account types the\nwallet supports.\n\nIf a wallet supports multiple types of accounts and all of them have the\nsame level of portability, the account type that takes precedence is the\none that the wallet offers the user to create by default.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask follows EOA key derivation standards.", | |
| "details": "\nMetaMask generates EOA keys in a\nstandards-compliant way:\n\n* [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)\n\tfor deriving a binary seed from a seed phrase.\n* [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)\n\tfor deterministic hierarchical key derivation from the binary seed.\n* [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)\n\tas a standard when deriving hierarchical private keys.\n\nIn addition, seed phrases are exportable so that they can be\nimported into other wallets. This ensures your account is portable\nand avoids lock-in.\n\n" | |
| } | |
| }, | |
| "transactionInclusion": { | |
| "attribute": { | |
| "attributeDisplayName": "Transaction inclusion", | |
| "attributeId": "transactionInclusion", | |
| "shortQuestion": "Can the wallet withdraw L2 funds to Ethereum L1 without relying on intermediaries?", | |
| "whyItMatters": "\nOne of the core tenets of Ethereum is **censorship resistance**.\nThis means that users must be able to reliably get transactions\nincluded onchain, without the ability for intermediaries to prevent\nthis from happening.\n\nThis property is critical to ensure that all Ethereum participants are\nprovided equal-opportunity, unfettered access to Ethereum, and to ensure\nthat Ethereum is resilient to attackers that would want to prevent others\nfrom using Ethereum on such footing.\n\nIn order to uphold this property on Ethereum L2s, users must be able to\nforce transactions to be included on L2 chains as well. Most L2s\nimplement such functionality by allowing L2 transactions to be\nsubmitted on the L1, and enforcing that their sequencing logic must\nrespect such L1 force-inclusion requests by including them on the L2\nchain, typically within some fixed duration.\n\nBy verifying that the wallet supports L2 force-withdrawal transactions,\nthis attribute verifies censorship resistance at both levels: L1 and L2.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is transaction inclusion evaluated?", | |
| "methodology": "\nWallets are rated based on whether users need to trust any intermediary\nin order to withdraw their funds from L2s.\n\nThis fundamentally requires two major features:\n\n* A wallet must support the creation of an L1 transaction which forces the\n\tL2 to withdraw user funds back to the L1. This message is typically\n\tposted as an L1 transaction which forces the L2 sequencing process to\n\ttake it into account.\n* Since L2 force-withdrawal transactions require an L1 transaction, the\n\twallet must also be able to get this transaction included without\n\trelying on an external service to broadcast this transaction for block\n\tinclusion. Therefore, the wallet must also support either participating\n\tin Ethereum's L1 gossip network, or (for environments that do not\n\tsupport this such as browser extension wallets) support broadcasting\n\tL1 transactions through a user's self-hosted Ethereum node.\n\nWith these two features in place, users can withdraw their L2 funds\nwithout trusting intermediaries.\n\nWalletbeat currently only considers OP Stack chains and Arbitrum One for\nthis evaluation, but more L2 chains may be added as support for\nforce-withdrawal transaction becomes feasible for them.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "UNRATED", | |
| "shortExplanation": "Walletbeat lacks the information needed to determine this.", | |
| "details": "See full details on the wallet page." | |
| } | |
| }, | |
| "accountUnruggability": { | |
| "attribute": { | |
| "attributeDisplayName": "Account unruggability", | |
| "attributeId": "accountUnruggability", | |
| "shortQuestion": "Can the wallet developer take over your account without your consent?", | |
| "whyItMatters": "\nThe promise of crypto is to make your accounts and your funds truly yours.\nThis is what is most commonly referred to when discussing\n\"self-sovereignty\".\n\nThe underlying property that makes an account truly yours is the inability\nfor anyone other than yourself to act on your behalf or to take over your\naccount without prior consent.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account unruggability evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether there is any mechanism by which\nany entity other than the user may sign or approve transactions on behalf\nof the user's account, or can transfer ownership of the account away from\nthe user. This includes features like seed phrase backups where the wallet\ndeveloper gets to learn the user's seed phrase, or other account recovery\nfeatures that let the wallet developer unilaterally recover the user's\naccount.\n\nFully-custodial wallets (i.e. wallets where the signing key material\nresides entirely on external services) are also not self-sovereign\n(aka ruggable) by definition.\n\nFeatures that allow the user to pre-approve certain types of transactions\nahead of time are treated as maintaining self-sovereignty, so long as\nthe user controls their limits explicitly:\ntime-bound, amount-bound, destination/purpose-bound, etc.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "\nMetaMask does not allow any external service to take over\nyour account.\n", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "urls": [ | |
| { | |
| "label": "MetaMask account recovery documentation", | |
| "url": "https://support.metamask.io/configure/wallet/social-login" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| "transparency": { | |
| "openSource": { | |
| "attribute": { | |
| "attributeDisplayName": "Source code license", | |
| "attributeId": "openSource", | |
| "shortQuestion": "\nDoes the user have the ability to avoid lock-in and freely audit,\nmodify, and redistribute the wallet's source code?\n", | |
| "whyItMatters": "\n[Free & Open Source Software (FOSS) licensing](https://en.wikipedia.org/wiki/Open-source_license)\nallows a software project's source code to be freely used, modified and distributed.\nThis allows better collaboration, more transparency into the software development practices\nthat go into the project, and allows security researchers to more easily identify and report\nsecurity vulnerabilities. In short, it turns software projects into public goods.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is source code license evaluated?", | |
| "methodology": "\nWallets are assessed based whether the license of their source code meets\nthe [Open Source Initiative's definition of open source](https://en.wikipedia.org/wiki/The_Open_Source_Definition).\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "FAIL", | |
| "shortExplanation": "MetaMask uses a proprietary license for some of its code.", | |
| "details": "\nWhile part of **MetaMask** is licensed under the\n[**MIT** license](https://spdx.org/licenses/MIT.html)\n(a Free & Open-Source (FOSS) license), others are not.\n", | |
| "howToImprove": "MetaMask should consider licensing all of its code under a Free & Open Source Software license." | |
| } | |
| }, | |
| "sourceVisibility": { | |
| "attribute": { | |
| "attributeDisplayName": "Source visibility", | |
| "attributeId": "sourceVisibility", | |
| "shortQuestion": "Is the source code for the wallet visible to the public?", | |
| "whyItMatters": "\nWhen using a wallet, users are entrusting it to preserve their funds\nsafely. This requires a high level of trust in the wallet's source code\nand in the wallet's development team. By making the wallet's source code\nvisible to the public, its source code can be more easily inspected for\nsecurity vulnerabilities and for potential malicious code.\nThis improves the wallet's security and trustworthiness.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is source visibility evaluated?", | |
| "methodology": "\nWallets are assessed based on whether or not their source code is\npublicly visible, irrespective of the license of the source code.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "\nThe source code for MetaMask is public.\n", | |
| "details": "\nThe source code for **MetaMask** is publicly viewable.\n", | |
| "impact": "\nThis allows its source code to be examined for security flaws and\nfor Walletbeat to review how the wallet works.\n", | |
| "references": [ | |
| { | |
| "explanation": "The MetaMask core repository contains various packages reused across all MetaMask versions, licensed under MIT.", | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/MetaMask/core/tree/main/packages" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "The MetaMask browser extension uses a proprietary source-available license.", | |
| "urls": [ | |
| { | |
| "label": "GitHub", | |
| "url": "https://github.com/MetaMask/metamask-extension/blob/main/LICENSE" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "funding": { | |
| "attribute": { | |
| "attributeDisplayName": "Funding", | |
| "attributeId": "funding", | |
| "shortQuestion": "How is the wallet's development team funded?", | |
| "whyItMatters": "\nWallets are complex, high-stakes pieces of software.\nThey must be maintained, regularly audited, and follow the continuous\nimprovements in the ecosystem.\nThis requires a reliable, transparent source of funding.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is funding evaluated?", | |
| "methodology": "\nWallets are assessed based on how sustainable, transparent, and\nuser-aligned their funding mechanisms are.\n\nWallets are typically funded by one or more of the following methods:\n\n* Self-funding from developers\n* Seeking donations from users\n* Seeking grants from foundations\n* Venture capital funding\n* Charging fees on convenience functions (e.g. swapping and bridging\n\ttokens)\n* Governance tokens\n* Commemorative NFT sales\n\nWalletbeat looks at each funding source of funding and verifies whether\nit is done transparently and in a user-aligned manner. In this context,\n\"user alignment\" refers to whether a source of funding grows as a\nfunction of the user's own goals, rather than being uncorrelated or\nanti-correlated. For example, funding acquired through hidden swap fees\nor governance token sales with undisclosed insider token allocations are\nnot user-aligned. Funding acquired through transparent swap fees, user\ndonations, or ecosystem grants are user-aligned.\n\nIn order to pass this criterion, wallets must have at least one source of\nfunding, and all of their sources of funding must be transparent to users.\nAdditionally, if the wallet is funded from multiple sources and some of\nthese sources are not user-aligned, the public must be able to determine\nthe proportion of each such funding source to the wallet's overall\nrevenue. Depending on the funding mechanism, this can be done through\npublication of a revenue breakdown page, public regulatory filings,\nor token allocation and vesting disclosures.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask is transparently funded.", | |
| "details": "See full details on the wallet page.", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask is funded through transparent swap fees and venture capital with publicly disclosed funding rounds.", | |
| "urls": [ | |
| { | |
| "label": "consensys.io", | |
| "url": "https://consensys.io/blog/consensys-raises-450m-series-d-funding" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "feeTransparency": { | |
| "attribute": { | |
| "attributeDisplayName": "Fee transparency", | |
| "attributeId": "feeTransparency", | |
| "shortQuestion": "Does the wallet clearly display all transaction fees and their purpose?", | |
| "whyItMatters": "\nFee transparency is crucial for users to understand the full cost of their transactions.\nWithout clear fee information, users may be surprised by high transaction costs or\nhidden fees charged by the wallet.\n\nTransparent fee disclosure helps users make informed decisions about when to transact\nand which wallet to use. It also builds trust between users and wallet providers by\nensuring that all costs are clearly communicated upfront.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's fee transparency evaluated?", | |
| "methodology": "\nWallets are evaluated based on how transparently they display transaction fees and\ntransaction purposes to users.\n\nA wallet receives a passing rating if it provides comprehensive fee information,\nincluding detailed breakdowns of network fees, clear disclosure of any additional\nwallet fees. Fees may be aggregated down to one number, but a breakdown must be\navailable to the user within a single click.\n\nA wallet receives a partial rating if it provides an aggregate fee but does not\nlet the user get a detailed breakdown.\n\nA wallet fails this attribute if it provides minimal or no fee information before\ntransaction confirmation.\n\nVarious transaction types are tested: Ether and ERC-20 transfers on L1, built-in\nswaps or bridging transactions, DeFi transactions, private transactions if\nsupported. If a wallet displays fees differently depending on the type of\ntransaction, the transaction type with the **least clear** display level is\ntaken into consideration for the purpose of this attribute.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "\nMetaMask breaks down all transaction fees.\n", | |
| "details": "\nMetaMask shows a complete breakdown of all transaction\nfees by default.\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask has a built-in bridge feature that allows users to bridge assets between chains.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/learn/field-guide-to-bridges/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| "ecosystem": { | |
| "accountAbstraction": { | |
| "attribute": { | |
| "attributeDisplayName": "Account Abstraction", | |
| "attributeId": "accountAbstraction", | |
| "shortQuestion": "Is the wallet Account Abstraction ready?", | |
| "whyItMatters": "\nUser experience on Ethereum has historically suffered from the limitations of Externally-Owned Accounts (EOAs), which is the type of account most Ethereum users use today. By contrast, smart wallet accounts offer many UX and security improvements, such as the ability to:\n\n* Batch multiple transactions, removing the need for separate \"token approval\" transactions before every other token operation.\n* Pay gas fees in other tokens than Ether, or support sponsored transaction fees (with [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short))\n* Delegate some operation to trusted provider, such as allowing onchain games to withdraw small amounts of tokens without signing pop-ups for each and every transaction.\n* Change transaction authorization logic, enabling the use of Passkeys (and cellphone authentication methods) for signing transactions.\n* Update the set of keys used to control the wallet, enabling the switch to quantum-resistant encryption algorithms in the future.\n* Define account recovery rules, reducing the risk of losing access to your account when losing a private key or a device.\n\nHowever, smart wallet accounts have historically been an all-or-nothing, wallet-specific proposition for users. There was no transition path to such wallets.\n\nAs part of the [Pectra upgrade](https://eips.ethereum.org/EIPS/eip-7600),\n[EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) fixes this problem. It create a clean path for\nexisting EOAs to obtain all the UX benefits of smart wallet accounts\nand account abstraction, without the need for users to switch to a\ndifferent account address.\nThis represents a large User Experience upgrade for all Ethereum EOA users.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is account abstraction support evaluated?", | |
| "methodology": "\nWallets are rated based on whether they make use of\n[EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) transactions (for EOA or MPC wallets),\nor if they support [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short) transactions\n(for smart contract wallets).\n\nThe user experience benefits of these enhancements are still in-flight\nand are expected to develop as these standards mature and are built on\ntop of. As such, Walletbeat does not currently consider *which*\nimprovements wallets provide for their users as a result of these new\ncapabilities. However, it is expected that a future version of this\nattribute would look at such improvements. For example: to verify\nthat users are able to update the signing authority of their wallets\nto a quantum-safe signature scheme.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports Account Abstraction via EIP-7702.", | |
| "details": "MetaMask supports Account Abstraction via [EIP-7702 Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=long)." | |
| } | |
| }, | |
| "addressResolution": { | |
| "attribute": { | |
| "attributeDisplayName": "Address resolution", | |
| "attributeId": "addressResolution", | |
| "shortQuestion": "Can you send funds to human-readable Ethereum addresses?", | |
| "whyItMatters": "\nEthereum addresses are hexadecimal strings (`0x...`) which are\nunreadable to humans. Phishing scams and exploits have used this to\ntrick users into sending funds to invalid addresses, for example by\ngenerating lookalike-addresses and tricking users into copy/pasting\nthem without noticing the difference.\n\nAdditionally, Ethereum's transition to layer 2 chains has changed user\nneeds when sending funds. The hexadecimal address isn't sufficient\nanymore; the user needs to ensure that they are sending funds to the\ncorrect hexadecimal address *on the correct chain*, increasing the\npotential for mistakenly sending funds to the wrong place or the wrong\nchain.\n\nAddress naming registries like ENS partially solve this problem by\nallowing more human-readable names like `username.eth` to be\nautomatically turned into the hexadecimal address. This is easier to\nshare and to accurately transfer by humans. Additionally, some address\nformat standards improve upon this further by including the destination\nchain information as part of the address itself. Such standards include:\n\n* [ERC-7828 Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=long): `user@l2chain.eth`\n* [ERC-7831 Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=long): `user.eth:l2chain`\n\nWallets that support either of these standards are able to automatically\ndetermine the destination address and chain from a human-readable string,\nand can bridge funds across chains as appropriate. This improves the user\nexperience of Ethereum and its layer 2 ecosystem while reducing the\npotential for mistakes when sending funds.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is address resolution evaluated?", | |
| "methodology": "\nWallets are rated based on the types of addresses they support sending\nfunds to.\n\nWalletbeat recognizes the following destination address formats:\n\n* Plain ENS addresses (`username.eth`) without destination chain information\n* [ERC-7828 Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=long): `user@l2chain.eth`\n* [ERC-7831 Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=long): `user.eth:l2chain`\n\nWallets receive a **pass** only if they support [ERC-7828: Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=short) or\n[ERC-7831: Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=short) (chain-specific human-readable addresses).\nWallets that support only plain ENS, with or without onchain resolution,\nreceive a **partial** rating.\n\nFor a pass, the mechanism used to perform the resolution must either:\n\n* Be done using onchain data and reusing the wallet's common chain\n interaction client, inheriting its verifiability (e.g. via light\n client) and privacy properties.\n* **OR** be done using an offchain external provider in such a way that\n the address returned by the external provider is verifiable, and\n without revealing the user's IP address to the provider.\n This ensures that:\n - The wallet cannot be tricked into sending funds to an attacker\n compromising the offchain provider's responses\n - The provider may not progressively learn the user's contacts list by\n associating its successive resolution queries by IP over time.\n\nFor addresses that **require** an offchain lookup (e.g. ENS names\nusing [offchain resolvers with CCIP-Read](https://docs.ens.domains/resolvers/ccip-read)),\nonly the portion of the work necessary to _arrive at the conclusion_\nthat an offchain lookup is necessary is considered.\nIn other words, wallets must verify that the CCIP-Read\n`OffchainLookup` details are as claimed and then perform the CCIP-Read\nthemselves, rather than trust an offchain provider to do so on their\nbehalf.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask supports sending to plain ENS addresses but not chain-specific human-readable addresses.", | |
| "details": "\nMetaMask supports sending funds to human-readable ENS addresses such as `username.eth`, but does not support chain-specific address formats that specify the destination chain.\n\nIt does so using onchain data sources using the same code as when interacting with the chain in general, inheriting its privacy and verifiability properties.\n", | |
| "howToImprove": "\nMetaMask may want to add support for sending funds to chain-specific human-readable addresses, as specified by either:\n\n* [ERC-7828 Chain-specific addresses using ENS](https://eips.ethereum.org/EIPS/eip-7828#wb-format=long): `user@l2chain.eth`\n* [ERC-7831 Multi-chain addresses](https://eips.ethereum.org/EIPS/eip-7831#wb-format=long): `user.eth:l2chain`\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask supports ENS domain resolution.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/learn/sending-or-receiving-a-transaction-with-ens/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "browserIntegration": { | |
| "attribute": { | |
| "attributeDisplayName": "Browser integration", | |
| "attributeId": "browserIntegration", | |
| "shortQuestion": "Does the wallet comply with web browser integration standards?", | |
| "whyItMatters": "\nWeb applications that want to integrate with Ethereum should not have to\nwrite code specific to the wallet that the user has installed. For this\nreason, the Ethereum community has defined web browser integration\nstandards, which dictate how wallets and web pages can interact with each\nother.\n\nBy ensuring that wallets implement this standard interface, applications\nautomatically support all wallets that implement the interface. This\nensures compatibility across wallets, and ensures that the Ethereum wallet\necosystem remains competitive thanks to wallet interoperability.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is browser integration evaluated?", | |
| "methodology": "\nWallets are rated based on whether they implement the following Ethereum\nstandards for web browser integration:\n\n* [EIP-1193 JavaScript Provider API](https://eips.ethereum.org/EIPS/eip-1193#wb-format=long)\n* [EIP-2700 JavaScript Provider Events](https://eips.ethereum.org/EIPS/eip-2700#wb-format=long)\n* [EIP-6963 Multiple JavaScript Providers](https://eips.ethereum.org/EIPS/eip-6963#wb-format=long)\n\nFor multi-platform wallets, only the web browser version is assessed.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports all the prominent standards for web browser integration.", | |
| "details": "\nMetaMask supports all the prominent standards for web browser integration:\n\n* [EIP-1193 JavaScript Provider API](https://eips.ethereum.org/EIPS/eip-1193#wb-format=long)\n* [EIP-2700 JavaScript Provider Events](https://eips.ethereum.org/EIPS/eip-2700#wb-format=long)\n* [EIP-6963 Multiple JavaScript Providers](https://eips.ethereum.org/EIPS/eip-6963#wb-format=long)\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask browser extension supports standard Ethereum Provider APIs. Mobile app does not inject into web pages.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/hc/en-us/articles/360015489471" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "chainAbstraction": { | |
| "attribute": { | |
| "attributeDisplayName": "Chain abstraction", | |
| "attributeId": "chainAbstraction", | |
| "shortQuestion": "Does the wallet smooth out the complexities of dealing with multiple chains?", | |
| "whyItMatters": "\nEthereum activity is not limited to the main L1 chain; a lot of activity\nhas moved onto rollups and Layer 2 chains. This has allowed Ethereum to\nscale beyond what its L1 chain can handle, but has also introduced\ncomplexity and fragmentation for users and wallets to deal with.\nThey must now deal with token balances fragmented across multiple chains.\n\nTo address the UX impact of this complexity, wallets should provide\nfeatures to abstract away these issues, while remaining transparent to\nthe user when cross-chain bridging risks or fees are involved.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is chain abstraction evaluated?", | |
| "methodology": "\nWallets are rated based on how much of the complexity involved in dealing\nwith multiple chains is abstracted away from users, while keeping risks\nand fees transparent.\n\nTo get a passing rating, wallets must be cross-chain aware in how they\ndisplay account value and individual token balances:\n\n- When displaying the user account's total value, this value should sum\n\tup the user's valuations across all chains the wallet supports by\n\tdefault.\n- When displaying a specific token's balance, the balance should reflect\n\tthe user's total balance for this token across all wallet-supported\n\tchains (and on which the token exists). For rating purposes,\n\tWalletbeat looks specifically at Ether and USDT balances.\n\nIn addition, wallets must make it easy for users to move their assets\nacross chains when needed. To get a passing rating, wallets must provide\na built-in bridging feature.\n\n- This bridging feature must explain the risks involved in bridging assets\n\tacross chains. Our friends at [L2BEAT](https://l2beat.com/) do a\n\tfantastic job documenting this, but wallet developers also have a duty\n\tto explain these risks to their users.\n- For bridge operations where the net fee is larger than 1bps, the wallet\n\tmust display the fee breakdown by default.\n- When the user attempts to send tokens to an address on a chain where the\n\tuser's balance is insufficient, but for which they have sufficient tokens\n\ton another chain, the wallet should automatically propose to bridge them.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PARTIAL", | |
| "shortExplanation": "MetaMask does not add up token balances across chains.", | |
| "details": "\nMetaMask can display your account's total value across\nchains and per-chain token balances. It does not, however, show\nyour total balance for a given token (e.g. Ether or USDC) summed\nup across multiple chains. That makes it hard to see how much\nUSDC you have.\n\nCross-chain token balance awareness is one of many features that\nwallets need to be multi-chain-aware. This matters for the Ethereum\nL2 roadmap, which aims to make L2s seamless for users.\n", | |
| "howToImprove": "\nMetaMask should have a way to see token balances summed up\nacross chains.\n", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask displays tokens across multiple networks in a single aggregated view with estimated portfolio value", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/manage-crypto/tokens/how-to-view-your-token-balance-across-multiple-networks/" | |
| } | |
| ] | |
| }, | |
| { | |
| "explanation": "MetaMask has a built-in bridge feature that allows users to bridge assets between chains.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/learn/field-guide-to-bridges/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| }, | |
| "transactionBatching": { | |
| "attribute": { | |
| "attributeDisplayName": "Transaction batching", | |
| "attributeId": "transactionBatching", | |
| "shortQuestion": "Does the wallet support bundling multiple operations as a single transaction?", | |
| "whyItMatters": "\nTransaction batching is one of the longstanding features without which\nEthereum user experience (UX) has suffered. One of the most common pain\npoints for DeFi, for example, has been the need to perform separate\n\"token approval\" transactions, followed by a separate transaction to\nactually execute the user's original intent.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is transaction batching evaluated?", | |
| "methodology": "\nSmart account types such as [ERC-4337: Account Abstraction for smart contract wallets](https://eips.ethereum.org/EIPS/eip-4337#wb-format=short) and\n[EIP-7702: Account Abstraction via smart contract authority delegation](https://eips.ethereum.org/EIPS/eip-7702#wb-format=short) unlock the ability to perform multiple\noperations as a single transaction. This is exposed to applications\nthrough [EIP-5792 Wallet Call API](https://eips.ethereum.org/EIPS/eip-5792#wb-format=long).\n\nTo qualify for a passing rating, the wallet must:\n\n- Support at least one type of smart account.\n- Implement [EIP-5792 Wallet Call API](https://eips.ethereum.org/EIPS/eip-5792#wb-format=long).\n- Support atomic transaction bundles, as per the `atomic` capability\n declared in `wallet_getCapabilities`.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports transaction batching and atomic transaction bundles.", | |
| "details": "\nMetaMask implements [EIP-5792 Wallet Call API](https://eips.ethereum.org/EIPS/eip-5792#wb-format=long).\nThis means applications can request the wallet to bundle multiple\ntransactions into a single operation.\nFor example, this means token approval transactions need to be\nsubmitted separately from the transactions that spend these tokens.\n\nIn addition, MetaMask supports **atomic** transaction bundles.\nThis means that the wallet guarantees that a transaction bundle is\neither **all executed** or **all non-executed**. This enables some\nadvanced DeFi use-cases.\n" | |
| } | |
| }, | |
| "hardwareWalletInteroperability": { | |
| "attribute": { | |
| "attributeDisplayName": "Hardware wallet interoperability", | |
| "attributeId": "hardwareWalletInteroperability", | |
| "shortQuestion": "\nDoes the wallet support directly connecting to hardware wallets from a plurality of manufacturers?\n", | |
| "whyItMatters": "\nHardware wallets are physical devices that store a user's private keys offline,\nproviding an additional layer of security against online threats. By keeping\nprivate keys isolated from internet-connected devices, hardware wallets protect\nusers from malware, phishing attacks, and other security vulnerabilities that\ncould compromise their funds.\n\nSupporting multiple hardware wallet manufacturers preserves a healthy,\nopen, competitive, interoperable market for hardware wallets. It also\nincreases the total addressable market of users for the software wallet,\nas users that already own a specific hardware wallets will want to use a\nsoftware wallet that supports it.\n", | |
| "howIsEvaluated": { | |
| "heading": "How is a wallet's hardware wallet support evaluated?", | |
| "methodology": "\nWallets are evaluated based on whether they directly integrate with\nhardware wallets from a plurality of major hardware wallet manufacturers.\n\nA wallet receives a passing rating if it supports hardware wallets from\nat least 3 major hardware wallet\nmanufacturers:\n\n\n* Ledger\n* Trezor\n* Keystone\n* GridPlus\n* imKey\n\nHardware wallets accessible only through WalletConnect are not counted,\nas they require relying on WalletConnect and external software beyond the\nwallet itself in order to function.\n\nA wallet receives a partial rating if it supports only two such\nhardware wallets manufacturers (without relying on WalletConnect or\nexternal software).\n\nA wallet fails this attribute if it only directly supports hardware wallets\nfrom a single manufacturer.\n\nWallets that do not directly support hardware wallets at all are exempt,\nas this check is only about hardware wallet *interoperability*.\nGeneral direct hardware wallet support is also part of Walletbeat's\nsecurity criteria as a separate attribute.\n" | |
| } | |
| }, | |
| "rating": { | |
| "rating": "PASS", | |
| "shortExplanation": "MetaMask supports a wide range of hardware wallets.", | |
| "details": "MetaMask supports the following hardware wallets:\n\n* Ledger (directly via WebUSB)\n* Trezor (directly via WebUSB)\n* GridPlus (directly via WebUSB)\n* Keystone (directly via QR code)\n\t", | |
| "references": [ | |
| { | |
| "explanation": "MetaMask supports Ledger, Trezor, Lattice (GridPlus), Keystone, OneKey, and KeepKey via its Hardware Wallet Hub.", | |
| "urls": [ | |
| { | |
| "label": "support.metamask.io", | |
| "url": "https://support.metamask.io/more-web3/wallets/hardware-wallet-hub/" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment