Skip to content

Comments

feat(transaction-pay-controller): live token balances#7935

Merged
matthewwalsh0 merged 3 commits intomainfrom
feat/transaction-pay-live-balances
Feb 20, 2026
Merged

feat(transaction-pay-controller): live token balances#7935
matthewwalsh0 merged 3 commits intomainfrom
feat/transaction-pay-live-balances

Conversation

@matthewwalsh0
Copy link
Member

@matthewwalsh0 matthewwalsh0 commented Feb 13, 2026

Explanation

Use live on-chain balance checks to improve stability:

  • Before each quote update, refresh the payment token balance via balanceOf or eth_getBalance.
  • Before submitting relay deposit transactions, validate the source balance is sufficient.

References

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

Medium Risk
Touches quote-refresh and Relay deposit submission paths and introduces new RPC reads/permission requirements, so failures or latency could block quoting or submission if not handled as expected.

Overview
Adds live on-chain balance reads to pay flows: updateQuotes now refreshes the selected payment token balance from chain before building quote requests, and Relay submissions now validate the quote’s sourceAmount.raw against a live balance check to fail fast with a descriptive error.

Introduces new token utilities (getLiveTokenBalance using ethers provider/balanceOf, plus shared computeTokenAmounts) and refactors existing balance/amount computations to use them; updates tests accordingly and tightens TransactionPayController’s “payment token changed” detection to compare address (case-insensitive) and chainId. Also adds @ethersproject/providers dependency and documents the breaking messenger permission requirement for NetworkController:getNetworkClientById.

Written by Cursor Bugbot for commit 3246505. This will update automatically on new commits. Configure here.

@matthewwalsh0 matthewwalsh0 changed the title feat: Add live on-chain balance validation for pay transactions feat(transaction-pay-controller): live token balances Feb 13, 2026
@matthewwalsh0 matthewwalsh0 force-pushed the feat/transaction-pay-live-balances branch from 44986a4 to 3084450 Compare February 13, 2026 23:59
@matthewwalsh0 matthewwalsh0 marked this pull request as ready for review February 14, 2026 00:06
@matthewwalsh0 matthewwalsh0 requested review from a team as code owners February 14, 2026 00:06
@matthewwalsh0 matthewwalsh0 force-pushed the feat/transaction-pay-live-balances branch from 8b48e2c to e7b1aa6 Compare February 16, 2026 12:04
@matthewwalsh0
Copy link
Member Author

@metamaskbot publish-preview

@github-actions
Copy link
Contributor

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

Expand for full list of packages and versions.
{
  "@metamask-previews/account-tree-controller": "4.1.1-preview-e7b1aa6",
  "@metamask-previews/accounts-controller": "36.0.0-preview-e7b1aa6",
  "@metamask-previews/address-book-controller": "7.0.1-preview-e7b1aa6",
  "@metamask-previews/ai-controllers": "0.0.0-preview-e7b1aa6",
  "@metamask-previews/analytics-controller": "1.0.0-preview-e7b1aa6",
  "@metamask-previews/analytics-data-regulation-controller": "0.0.0-preview-e7b1aa6",
  "@metamask-previews/announcement-controller": "8.0.0-preview-e7b1aa6",
  "@metamask-previews/app-metadata-controller": "2.0.0-preview-e7b1aa6",
  "@metamask-previews/approval-controller": "8.0.0-preview-e7b1aa6",
  "@metamask-previews/assets-controller": "1.0.0-preview-e7b1aa6",
  "@metamask-previews/assets-controllers": "99.3.2-preview-e7b1aa6",
  "@metamask-previews/base-controller": "9.0.0-preview-e7b1aa6",
  "@metamask-previews/bridge-controller": "66.1.1-preview-e7b1aa6",
  "@metamask-previews/bridge-status-controller": "66.0.2-preview-e7b1aa6",
  "@metamask-previews/build-utils": "3.0.4-preview-e7b1aa6",
  "@metamask-previews/chain-agnostic-permission": "1.4.0-preview-e7b1aa6",
  "@metamask-previews/claims-controller": "0.4.2-preview-e7b1aa6",
  "@metamask-previews/composable-controller": "12.0.0-preview-e7b1aa6",
  "@metamask-previews/connectivity-controller": "0.1.0-preview-e7b1aa6",
  "@metamask-previews/controller-utils": "11.18.0-preview-e7b1aa6",
  "@metamask-previews/core-backend": "5.1.1-preview-e7b1aa6",
  "@metamask-previews/delegation-controller": "2.0.1-preview-e7b1aa6",
  "@metamask-previews/earn-controller": "11.1.0-preview-e7b1aa6",
  "@metamask-previews/eip-5792-middleware": "2.1.0-preview-e7b1aa6",
  "@metamask-previews/eip-7702-internal-rpc-middleware": "0.1.0-preview-e7b1aa6",
  "@metamask-previews/eip1193-permission-middleware": "1.0.3-preview-e7b1aa6",
  "@metamask-previews/ens-controller": "19.0.2-preview-e7b1aa6",
  "@metamask-previews/error-reporting-service": "3.0.1-preview-e7b1aa6",
  "@metamask-previews/eth-block-tracker": "15.0.1-preview-e7b1aa6",
  "@metamask-previews/eth-json-rpc-middleware": "23.1.0-preview-e7b1aa6",
  "@metamask-previews/eth-json-rpc-provider": "6.0.0-preview-e7b1aa6",
  "@metamask-previews/foundryup": "1.0.1-preview-e7b1aa6",
  "@metamask-previews/gas-fee-controller": "26.0.2-preview-e7b1aa6",
  "@metamask-previews/gator-permissions-controller": "1.1.2-preview-e7b1aa6",
  "@metamask-previews/json-rpc-engine": "10.2.2-preview-e7b1aa6",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.8-preview-e7b1aa6",
  "@metamask-previews/keyring-controller": "25.1.0-preview-e7b1aa6",
  "@metamask-previews/logging-controller": "7.0.1-preview-e7b1aa6",
  "@metamask-previews/message-manager": "14.1.0-preview-e7b1aa6",
  "@metamask-previews/messenger": "0.3.0-preview-e7b1aa6",
  "@metamask-previews/multichain-account-service": "7.0.0-preview-e7b1aa6",
  "@metamask-previews/multichain-api-middleware": "1.2.6-preview-e7b1aa6",
  "@metamask-previews/multichain-network-controller": "3.0.3-preview-e7b1aa6",
  "@metamask-previews/multichain-transactions-controller": "7.0.1-preview-e7b1aa6",
  "@metamask-previews/name-controller": "9.0.0-preview-e7b1aa6",
  "@metamask-previews/network-controller": "29.0.0-preview-e7b1aa6",
  "@metamask-previews/network-enablement-controller": "4.1.0-preview-e7b1aa6",
  "@metamask-previews/notification-services-controller": "22.0.0-preview-e7b1aa6",
  "@metamask-previews/permission-controller": "12.2.0-preview-e7b1aa6",
  "@metamask-previews/permission-log-controller": "5.0.0-preview-e7b1aa6",
  "@metamask-previews/perps-controller": "0.0.0-preview-e7b1aa6",
  "@metamask-previews/phishing-controller": "16.2.0-preview-e7b1aa6",
  "@metamask-previews/polling-controller": "16.0.2-preview-e7b1aa6",
  "@metamask-previews/preferences-controller": "22.1.0-preview-e7b1aa6",
  "@metamask-previews/profile-metrics-controller": "3.0.1-preview-e7b1aa6",
  "@metamask-previews/profile-sync-controller": "27.1.0-preview-e7b1aa6",
  "@metamask-previews/ramps-controller": "8.0.0-preview-e7b1aa6",
  "@metamask-previews/rate-limit-controller": "7.0.0-preview-e7b1aa6",
  "@metamask-previews/remote-feature-flag-controller": "4.0.0-preview-e7b1aa6",
  "@metamask-previews/sample-controllers": "4.0.2-preview-e7b1aa6",
  "@metamask-previews/seedless-onboarding-controller": "8.0.0-preview-e7b1aa6",
  "@metamask-previews/selected-network-controller": "26.0.2-preview-e7b1aa6",
  "@metamask-previews/shield-controller": "5.0.1-preview-e7b1aa6",
  "@metamask-previews/signature-controller": "39.0.2-preview-e7b1aa6",
  "@metamask-previews/storage-service": "1.0.0-preview-e7b1aa6",
  "@metamask-previews/subscription-controller": "6.0.0-preview-e7b1aa6",
  "@metamask-previews/transaction-controller": "62.17.0-preview-e7b1aa6",
  "@metamask-previews/transaction-pay-controller": "15.0.1-preview-e7b1aa6",
  "@metamask-previews/user-operation-controller": "41.0.2-preview-e7b1aa6"
}

OGPoyraz
OGPoyraz previously approved these changes Feb 18, 2026
@matthewwalsh0 matthewwalsh0 added this pull request to the merge queue Feb 20, 2026
Merged via the queue into main with commit 9797a6a Feb 20, 2026
310 checks passed
@matthewwalsh0 matthewwalsh0 deleted the feat/transaction-pay-live-balances branch February 20, 2026 10:56
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.


updateTransactionData(transactionId, (data) => {
data.paymentToken = updatedToken;
});
Copy link

Choose a reason for hiding this comment

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

Stale balance refresh can revert user's token selection

Medium Severity

refreshPaymentTokenBalance unconditionally writes data.paymentToken = updatedToken after the async getLiveTokenBalance RPC call, where updatedToken is derived from the token captured before the await. If the user selects a different payment token during that async gap, this write overwrites their new selection with the stale token (plus refreshed balance). Because #updateTransactionData detects the address/chainId change, it then triggers a new updateQuotes for the wrong token — effectively reverting the user's choice with no cancellation mechanism in place.

Fix in Cursor Fix in Web

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