You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(swaps): show fee rebate banner in Swaps (SWAPS-5293) - #47618
Adds the fee rebate banner, "You’re getting X% back on fees", directly above the CTA button in Swaps. This mirrors Mobile's implementation (metamask-mobile#37623). Users who are eligible for a rebate see what share of the MetaMask fee they'll get back, paid to their Money account.
How it works:
useSwapsRebate hook: calls RewardsMoneyController:getSwapsRebateQuote (already in the extension) with the active quote, through a route messenger that allows only that action.
It calls once when the banner mounts, and again only when the MetaMask fee token changes. It never refetches on quote refresh.
It returns rebateBips / 100, but only when eligible is true and reason is null.
Any error hides the banner and is not retried. The CTA button never waits on the request.
SwapsRebateBanner: shows the message, the existing money.png icon, and a "Trading Rewards" info tooltip. It renders nothing when there's no rebate. The tooltip popover is given zIndex: 20 so it paints above the sticky CTA footer.
Feature flag: the feature is behind the version-gated swapsRebateBannerEnabled remote flag ({ enabled, minimumVersion }), the same key Mobile uses. It defaults to off, and when it's off the endpoint isn't called. The flag is registered as inProd: false in feature-flag-registry.ts.
Changelog
CHANGELOG entry: Added a fee rebate banner to Swaps for users eligible for a MetaMask fee rebate
Until the endpoint returns a rebate for your account, you can force one by temporarily replacing the controller call in ui/hooks/bridge/useSwapsRebate.ts with Promise.resolve({ eligible: true, rebateBips: 1000, reason: null }).
Enable the swapsRebateBannerEnabled remote flag, for example in .manifest-overrides.json with { "enabled": true, "minimumVersion": "0.0.0" }.
Run the extension and open Swaps.
Pick a token pair that charges a MetaMask fee and enter an amount.
Verify that "You’re getting 10% back on fees" appears above the CTA button.
Hover the info icon and verify that the "Trading Rewards" tooltip appears above the footer.
Wait for the quote to refresh and verify that the banner stays and the rebate endpoint is not called again.
Disable the flag, or have the endpoint return eligible: false or an error, and verify that no banner is shown and the swap flow is unchanged.
I've completed the PR template to the best of my ability
I’ve included tests if applicable
I’ve documented my code using JSDoc format if applicable
I’ve applied the right labels on the PR (see labeling guidelines). Not required for external contributors.
Pre-merge reviewer checklist
I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.
Note
Low Risk
Promotional UI behind a remote flag that fails closed; it uses an existing rewards endpoint and does not gate or alter swap execution.
Overview
Adds an optional Trading Rewards banner above the Swaps prepare CTA that tells eligible users what % of the MetaMask fee they’ll get back (paid in mUSD to Money), aligned with Mobile.
The flow is gated by the remote swapsRebateBannerEnabled flag (defaults off). When enabled, useSwapsRebate calls RewardsMoneyController:getSwapsRebateQuote via a scoped route messenger, converts eligible rebateBips to a display percentage, and does not block the swap button. Rebates are fetched on mount and only when the MetaMask fee token changes (not on quote refresh); failures or ineligibility hide the banner. SwapsRebateBanner renders the message, Money icon, and tooltip (with elevated z-index over the sticky footer). New locale strings and unit/component tests cover the hook and banner.
Reviewed by Cursor Bugbot for commit 63cdc7d. Bugbot is set up for automated code reviews on this repo. Configure here.
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
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds the fee rebate banner, "You’re getting X% back on fees", directly above the CTA button in Swaps. This mirrors Mobile's implementation (metamask-mobile#37623). Users who are eligible for a rebate see what share of the MetaMask fee they'll get back, paid to their Money account.
How it works:
useSwapsRebatehook: callsRewardsMoneyController:getSwapsRebateQuote(already in the extension) with the active quote, through a route messenger that allows only that action.rebateBips / 100, but only wheneligibleis true andreasonis null.SwapsRebateBanner: shows the message, the existingmoney.pngicon, and a "Trading Rewards" info tooltip. It renders nothing when there's no rebate. The tooltip popover is givenzIndex: 20so it paints above the sticky CTA footer.swapsRebateBannerEnabledremote flag ({ enabled, minimumVersion }), the same key Mobile uses. It defaults to off, and when it's off the endpoint isn't called. The flag is registered asinProd: falseinfeature-flag-registry.ts.Changelog
CHANGELOG entry: Added a fee rebate banner to Swaps for users eligible for a MetaMask fee rebate
Related issues
Fixes: SWAPS-5293
Manual testing steps
Until the endpoint returns a rebate for your account, you can force one by temporarily replacing the controller call in
ui/hooks/bridge/useSwapsRebate.tswithPromise.resolve({ eligible: true, rebateBips: 1000, reason: null }).swapsRebateBannerEnabledremote flag, for example in.manifest-overrides.jsonwith{ "enabled": true, "minimumVersion": "0.0.0" }.eligible: falseor an error, and verify that no banner is shown and the swap flow is unchanged.Pre-merge author checklist
Pre-merge reviewer checklist
Note
Low Risk
Promotional UI behind a remote flag that fails closed; it uses an existing rewards endpoint and does not gate or alter swap execution.
Overview
Adds an optional Trading Rewards banner above the Swaps prepare CTA that tells eligible users what % of the MetaMask fee they’ll get back (paid in mUSD to Money), aligned with Mobile.
The flow is gated by the remote
swapsRebateBannerEnabledflag (defaults off). When enabled,useSwapsRebatecallsRewardsMoneyController:getSwapsRebateQuotevia a scoped route messenger, converts eligiblerebateBipsto a display percentage, and does not block the swap button. Rebates are fetched on mount and only when the MetaMask fee token changes (not on quote refresh); failures or ineligibility hide the banner.SwapsRebateBannerrenders the message, Money icon, and tooltip (with elevated z-index over the sticky footer). New locale strings and unit/component tests cover the hook and banner.Reviewed by Cursor Bugbot for commit 63cdc7d. Bugbot is set up for automated code reviews on this repo. Configure here.