Skip to content

Commit 85dc04e

Browse files
authored
feat(card): enable cashback for US users (#29138)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> This PR enables the Card Cashback feature for US users, removing the location verification from the BaanxProvider capabilities. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Enable Card Cashback for US users ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes the card capability contract and removes location-based overrides, which could affect downstream UI/feature gating for providers if any relied on per-location capability resolution. > > **Overview** > Enables cashback for US users by removing Baanx’s US-specific capability overrides and making `CardController.getCapabilities()` always return the provider’s static `capabilities`. > > This drops the `ICardProvider.resolveCapabilities()` hook entirely and updates tests to no longer assert location-dependent capability behavior. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ba8235a. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent f560f16 commit 85dc04e

4 files changed

Lines changed: 3 additions & 67 deletions

File tree

app/core/Engine/controllers/card-controller/CardController.test.ts

Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,57 +1373,14 @@ describe('CardController — getCapabilities', () => {
13731373
supportsCashback: true,
13741374
};
13751375

1376-
it('returns base capabilities when provider has no resolveCapabilities', () => {
1377-
// Provider without resolveCapabilities → controller falls back to capabilities
1376+
it('returns base capabilities', () => {
13781377
const provider = buildMockProvider({ capabilities: baseCapabilities });
1379-
const controller = buildController(provider, {
1380-
providerData: { baanx: { location: 'international' } },
1381-
});
1378+
const controller = buildController(provider);
13821379

13831380
const caps = controller.getCapabilities();
13841381
expect(caps.supportsPinView).toBe(false);
13851382
expect(caps.supportsCashback).toBe(true);
13861383
});
1387-
1388-
it('delegates to resolveCapabilities with the current location', () => {
1389-
const resolved = {
1390-
...baseCapabilities,
1391-
supportsPinView: true,
1392-
supportsCashback: false,
1393-
};
1394-
const provider = buildMockProvider({
1395-
capabilities: baseCapabilities,
1396-
resolveCapabilities: jest.fn().mockReturnValue(resolved),
1397-
});
1398-
const controller = buildController(provider, {
1399-
providerData: { baanx: { location: 'us' } },
1400-
});
1401-
1402-
const caps = controller.getCapabilities();
1403-
expect(provider.resolveCapabilities).toHaveBeenCalledWith('us');
1404-
expect(caps.supportsPinView).toBe(true);
1405-
expect(caps.supportsCashback).toBe(false);
1406-
});
1407-
1408-
it('forces supportsPinView true and supportsCashback false for US', () => {
1409-
// Use a provider that implements the Baanx-style location override logic
1410-
const provider = buildMockProvider({
1411-
capabilities: baseCapabilities,
1412-
resolveCapabilities: jest.fn((location: string) => ({
1413-
...baseCapabilities,
1414-
supportsPinView: location === 'us' || baseCapabilities.supportsPinView,
1415-
supportsCashback:
1416-
location !== 'us' && baseCapabilities.supportsCashback,
1417-
})),
1418-
});
1419-
const controller = buildController(provider, {
1420-
providerData: { baanx: { location: 'us' } },
1421-
});
1422-
1423-
const caps = controller.getCapabilities();
1424-
expect(caps.supportsPinView).toBe(true);
1425-
expect(caps.supportsCashback).toBe(false);
1426-
});
14271384
});
14281385

14291386
describe('CardController — data pass-throughs', () => {

app/core/Engine/controllers/card-controller/CardController.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -642,12 +642,7 @@ export class CardController extends BaseController<
642642

643643
getCapabilities(): CardProviderCapabilities {
644644
const provider = this.getActiveProvider();
645-
const pid = this.state.activeProviderId ?? '';
646-
const provData = this.state.providerData[pid] as
647-
| { location?: string }
648-
| undefined;
649-
const location = provData?.location ?? '';
650-
return provider.resolveCapabilities?.(location) ?? provider.capabilities;
645+
return provider.capabilities;
651646
}
652647

653648
async getCardHomeData(address: string): Promise<CardHomeData> {

app/core/Engine/controllers/card-controller/provider-types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,6 @@ export interface RegistrationStatus {
325325
export interface ICardProvider {
326326
readonly id: CardProviderId;
327327
readonly capabilities: CardProviderCapabilities;
328-
resolveCapabilities?(location: string): CardProviderCapabilities;
329328

330329
initiateAuth(country: string): Promise<CardAuthSession>;
331330
submitCredentials(

app/core/Engine/controllers/card-controller/providers/BaanxProvider.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -231,21 +231,6 @@ export class BaanxProvider implements ICardProvider {
231231
supportsPinView: true,
232232
supportsCashback: true,
233233
};
234-
235-
/**
236-
* Applies Baanx-specific location overrides:
237-
* - US users always get PIN view (regardless of base flag).
238-
* - US users do not have cashback (only available outside the US).
239-
*/
240-
resolveCapabilities(location: string): CardProviderCapabilities {
241-
const isUS = location === 'us';
242-
return {
243-
...this.capabilities,
244-
supportsPinView: isUS || this.capabilities.supportsPinView,
245-
supportsCashback: !isUS && this.capabilities.supportsCashback,
246-
};
247-
}
248-
249234
private readonly service: BaanxService;
250235
private readonly cardFeatureFlag: CardFeatureFlag | null;
251236

0 commit comments

Comments
 (0)