Skip to content

perf(transaction-controller): cache EIP-7702 contract signature verification - #10397

Merged
matthewwalsh0 merged 3 commits into
mainfrom
perf/cache-eip7702-contract-signature-verification
Sep 24, 2026
Merged

matthewwalsh0 merged 3 commits into
mainfrom
perf/cache-eip7702-contract-signature-verification

Conversation

@matthewwalsh0

@matthewwalsh0 matthewwalsh0 commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Explanation

EIP-7702 capability lookups verify the signature of every contract configured for a chain, on every call, with no reuse between calls. Each verification is a full elliptic curve public key recovery.

These lookups run synchronously, and the callers fan out: isAtomicBatchSupported resolves the upgrade contract address in addition to checking the account's delegation, and getCapabilities is invoked per account across every requested chain. The same recoveries are therefore repeated many times over within a single request, which can block the JavaScript thread for a noticeable period on mobile.

Two changes:

  • Memoize the verification result. isValidSignature is a pure function of the data, signature and public key, so a cached entry can never become stale and requires no invalidation — new feature flag data simply produces new keys. The cache is bounded as a precaution. Each configured contract is now verified at most once for the lifetime of the process, regardless of how many chains, accounts or callers are involved.
  • Stop verifying contracts that cannot be returned. getEIP7702UpgradeContractAddress verified every contract configured for a chain in order to return the first authentic one. It now stops at the first match. Behaviour is unchanged, including the existing fall-through when the first configured contract fails verification.

There is no change to public API or to the result of any existing call.

References

N/A

Checklist

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

Note

Low Risk
Performance-only refactor with unchanged public API and intended identical results; cache keys include public key and separate multi-part data entries to avoid stale or colliding hits.

Overview
Reduces synchronous work on EIP-7702 capability lookups by avoiding repeated elliptic-curve signature recovery for the same contract configuration.

isValidSignature now memoizes results (data + signature + public key), with a bounded cache and a test-only clearSignatureCache. getEIP7702UpgradeContractAddress no longer validates every configured contract just to return the first authentic one—it stops after the first valid match, while getEIP7702ContractAddresses still filters the full list via shared getEIP7702Contracts / isContractAuthentic helpers. Changelog and tests cover cache behavior and the early-exit upgrade lookup.

Reviewed by Cursor Bugbot for commit 63f644a. Bugbot is set up for automated code reviews on this repo. Configure here.

…ication

EIP-7702 capability lookups verify the signature of every contract configured
for a chain on every call, with no reuse between calls. Each verification is a
full elliptic curve public key recovery, and the lookups run synchronously on
paths that fan out across chains and accounts, so the same recoveries are
repeated many times over.

Memoize the verification result. It is a pure function of the data, signature
and public key, so a cached entry can never become stale and needs no
invalidation.

Also stop `getEIP7702UpgradeContractAddress` verifying every contract for a
chain when it only returns the first authentic one.
@matthewwalsh0
matthewwalsh0 marked this pull request as ready for review September 23, 2026 15:35
@matthewwalsh0
matthewwalsh0 requested review from a team as code owners September 23, 2026 15:35
@matthewwalsh0
matthewwalsh0 added this pull request to the merge queue Sep 24, 2026
Merged via the queue into main with commit 6371d73 Sep 24, 2026
117 checks passed
@matthewwalsh0
matthewwalsh0 deleted the perf/cache-eip7702-contract-signature-verification branch September 24, 2026 12:28
@pedronfigueiredo pedronfigueiredo mentioned this pull request Sep 24, 2026
2 of 3 tasks
pull Bot pushed a commit to Reality2byte/core that referenced this pull request Sep 24, 2026
## Explanation

Prepare monorepo release **1285.0.0** for
`@metamask/transaction-controller@72.0.0` and all **19 direct workspace
dependents**. `perps-controller` is now included for the consumer-facing
HIP-3 snapshot fix merged in MetaMask#10429, not merely for its development
dependencies; `earn-controller` also has an existing production
dependency bump. This branch incorporates current `main`, including
MetaMask#10429 and MetaMask#10419. No source-code changes are introduced by this PR
relative to current `main`.

### Versions in this release

| Package | Version | Rationale |
| --- | --- | --- |
| `transaction-controller` | **72.0.0** | Breaking revert of
approval-time sponsorship/signing hooks (MetaMask#10420) |
| `subscription-controller` | **10.0.0** | Existing Unreleased breaking
subscription type changes (MetaMask#10305, MetaMask#10416) |
| `wallet` | **15.0.0** | Its exported default instance/state types
expose the breaking subscription and transaction-controller changes |
| `transaction-pay-controller` | **29.2.0** | Additional supported
pay-strategy flows and server-quote behavior (MetaMask#10342) |
| `assets-controller` | 16.1.1 | Dependency updates and previously
merged fixes |
| `assets-controllers` | 112.0.3 | Dependency updates |
| `bridge-controller` | 81.3.1 | Dependency updates |
| `bridge-status-controller` | 76.3.1 | Dependency updates |
| `client-utils` | 3.0.3 | Dependency update |
| `earn-controller` | 13.0.1 | Existing production
`account-tree-controller` bump; transaction-controller is dev-only here
|
| `eip-5792-middleware` | 4.0.1 | Dependency updates |
| `gator-permissions-controller` | 6.0.1 | Dependency updates |
| `money-account-utils` | 2.0.1 | Dependency updates |
| `network-enablement-controller` | 7.0.1 | Dependency updates |
| `perps-controller` | **18.0.1** | Fix Terminal v3 HIP-3 snapshot
validation (MetaMask#10429); patch bump |
| `phishing-controller` | 18.1.1 | Dependency update |
| `profile-metrics-controller` | 5.1.1 | Dependency updates |
| `shield-controller` | 7.0.2 | Dependency updates |
| `smart-transactions-controller` | 27.0.2 | Dependency updates |
| `user-operation-controller` | 42.0.1 | Dependency updates |

Dependent packages have their Unreleased changelog entries moved to
their new release sections. Additional *non-released* transitive
dependents receive compatible workspace ranges
(`money-account-upgrade-controller`,
`network-connection-banner-controller`, `signature-controller`, and
unpublished `wallet-cli`); the three published packages receive
Unreleased dependency changelog entries. `yarn.lock` is synchronized.
Changes to `perps-controller`'s development dependencies are
intentionally omitted from its changelog.

**Coordination before merge:** The transaction-controller hook revert
and the subscription-controller's existing breaking type changes affect
consumers. Confirm Extension and Mobile migrations before publishing
these three major versions. This is a release candidate, not a published
release.

## References

- Breaking revert: MetaMask#10420; original published API: MetaMask#10109.
- EIP-7702 performance change: MetaMask#10397.
- Perps HIP-3 snapshot fix: MetaMask#10429.
- Subscription breaking changes: MetaMask#10305, MetaMask#10416.
- Client adoption PRs to coordinate: [Extension
#46060](MetaMask/metamask-extension#46060),
[Mobile #35754](MetaMask/metamask-mobile#35754).
They adopt the removed hooks; they are **not** migrations for this
revert.

## Validation

- `yarn build`
- `yarn workspace @metamask/transaction-controller run test`
- `yarn workspace @metamask/subscription-controller run test`
- `yarn workspace @metamask/transaction-pay-controller run test`
- `yarn workspace @metamask/wallet run test`
- `yarn workspace @metamask/perps-controller run test` (after
incorporating MetaMask#10429)
- `yarn changelog:validate`, `yarn constraints`, `yarn install
--immutable`, `yarn dedupe --check`
- `yarn lint:dependencies` (after removing stale generated
bridge-controller `dist` output)
- `git diff --check`

## Checklist

- [x] Changelogs describe the breaking changes in
transaction-controller, subscription-controller, and wallet.
- [x] Direct workspace dependents are included, with perps now having a
consumer-facing fix (MetaMask#10429).
- [ ] Extension and Mobile consumers have been coordinated for these
breaking changes before merging this release.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Publishes breaking majors for transaction signing/sponsorship and
subscription types that require coordinated Extension/Mobile migrations
before consumers upgrade `@metamask/wallet` or
`@metamask/transaction-controller`.
> 
> **Overview**
> Prepares **monorepo release 1285.0.0** by bumping package versions,
moving Unreleased changelog notes into release sections, aligning
workspace dependency ranges, and refreshing `yarn.lock`. There are **no
application source edits** in this diff—only release metadata for work
already on `main`.
> 
> The release centers on **`@metamask/transaction-controller@72.0.0`**,
which **reverts** the approval-time `isSponsored` / `shouldSign` hooks
in favor of metadata-driven **`isGasFeeSponsored`** and
**`isExternalSign`**, drops related exports and
`isGasFeeSponsoredAvailable`, and again **requires** a `hooks` object
(use `hooks: {}` when empty).
**`@metamask/subscription-controller@10.0.0`** ships existing breaking
subscription/payment-token type changes (optional period fields,
vault-share detection via `isVaultShareToken`, crypto payment failure
types). **`@metamask/wallet@15.0.0`** bumps those majors plus related
dependents.
> 
> Nineteen direct workspace dependents get compatible semver bumps
(mostly patch dependency realignments to
`@metamask/transaction-controller@^72.0.0`). Notable published notes
include **`@metamask/perps-controller@18.0.1`** (HIP-3 Terminal snapshot
validation fix) and **`@metamask/transaction-pay-controller@29.2.0`**
(server pay-strategy quoting/submit fixes). Unpublished/transitive
packages (`wallet-cli`, `money-account-upgrade-controller`, etc.) get
range updates without always cutting new versions.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
6017d49. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Baptiste Marchand <75846779+baptiste-marchand@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
default-branch — 63f644a0 Deployed Sep 23, 2026 by matthewwalsh0 via Determine whether this PR is a release PR #4514
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants