Skip to content

feat(signature-controller): allow EIP-7702 self-signatures where verifyingContract equals signer#7836

Open
zerodustxyz wants to merge 1 commit intoMetaMask:mainfrom
zerodustxyz:feat/eip-7702-verifying-contract-exception
Open

feat(signature-controller): allow EIP-7702 self-signatures where verifyingContract equals signer#7836
zerodustxyz wants to merge 1 commit intoMetaMask:mainfrom
zerodustxyz:feat/eip-7702-verifying-contract-exception

Conversation

@zerodustxyz
Copy link

@zerodustxyz zerodustxyz commented Feb 4, 2026

Summary

This PR adds an exception to the validateVerifyingContract function in the signature-controller to support EIP-7702 delegated accounts, enabling MetaMask users to interact with next-generation protocols that leverage temporary smart contract delegation.

The Problem: Dust Across Many Chains

Users accumulate small native token balances ("dust") across dozens of chains that are too small to bridge or swap due to gas costs. Until now, there was no way to sweep these balances to exactly zero.

With EIP-7702 (EIP-7702: Set EOA account code), protocols can now offer sponsored transactions where a third party pays gas on behalf of the user. However, when signing EIP-712 typed data in this context, the verifyingContract in the domain is legitimately the user's own address (because their EOA is temporarily acting as a contract).

Currently, MetaMask blocks these signatures with the error:

External signature requests cannot use internal accounts as the verifying contract.

This security check is important for preventing phishing attacks, but it incorrectly blocks legitimate EIP-7702 use cases.

The Solution

Add an exception when the verifyingContract equals the signerAddress (the from field in the message params). This is a safe exception because:

  1. The user is signing for themselves: The signature is being made by the same address that is the verifying contract
  2. This is the expected EIP-7702 flow: When an EOA delegates to a contract via EIP-7702, that EOA becomes the verifying contract for signatures
  3. No additional attack surface: A malicious dApp cannot exploit this because the user would need to have already delegated their EOA to a contract, and the signature is for their own address

User Flow with This Fix

First Approval - EIP-712 Sweep Intent

The user signs a typed data message specifying the sweep parameters. Note how the verifyingContract is the user's own address:

Sweep intent signature - top Sweep intent signature - bottom

Second Approval - Transaction Confirmation

Standard transaction confirmation for executing the sweep:

Transaction confirmation - top Transaction confirmation - bottom

Changes

  • Added signerAddress parameter to validateVerifyingContract function
  • Added logic to allow signatures when verifyingContract === signerAddress (case-insensitive)
  • Added comprehensive test coverage for the new behavior

Testing

Added two test cases:

  1. Verifies that EIP-7702 self-signatures are allowed
  2. Verifies case-insensitive address comparison works correctly

Related

…fyingContract equals signer

With EIP-7702, EOAs can temporarily delegate to smart contracts, making the
user's address itself become a contract. Protocols using EIP-7702 (like
account abstraction and sponsored transactions) need to sign EIP-712 messages
where the verifyingContract is the user's own address.

This change adds an exception to the verifying contract validation: when the
signer's address matches the verifyingContract, the signature is allowed.
This is safe because:

1. The user is signing for their own address (not someone else's)
2. EIP-7702 delegation is a legitimate use case enabled by Pectra
3. The existing check still blocks external requests from using OTHER
   internal accounts as verifyingContract

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@zerodustxyz zerodustxyz requested a review from a team as a code owner February 4, 2026 12:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant