Skip to content

Commit 9b8734a

Browse files
authored
fix: getcandidatesubscriptionid silent auth if no subscription in state (#22124)
## **Description** Very soon there will be multiple places to opt into rewards, which requires a small change in the `getCandidateSubscriptionId` controller function. In that function, we detect a subscription id in via `/ois` and we don't have a subscription object in our store state, we should do a silent auth for the account tied to the subscription. This will (re)populate the store state appropriately. ## **Changelog** CHANGELOG entry: null ## **Pre-merge author checklist** - [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. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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] > Perform silent auth during candidate subscription discovery when state lacks the subscription, try all accounts and set a sensible activeAccount fallback, reduce opt‑in cache staleness to 1h, and make invalidation async with token reset; update tests accordingly. > > - **RewardsController**: > - **Candidate Subscription**: `getCandidateSubscriptionId` now returns `sids[i]` only if a valid token exists AND the subscription is in state; otherwise performs `performSilentAuth` for that account. > - **Auth Flow**: `handleAuthenticationTrigger` iterates all accounts, captures the first success, and sets `activeAccount` to the first success or the first account; calls `performSilentAuth(account, false, true)`. > - **Cache/Thresholds**: Shorten not‑opted‑in opt‑in status stale threshold to 1 hour (`NOT_OPTED_IN_OIS_STALE_CACHE_THRESHOLD_MS`). > - **Invalidation**: `invalidateAccountsAndSubscriptions` is now `async`, also clears `lastFreshOptInStatusCheck`, and awaits `resetAllSubscriptionTokens`; consumers updated to `await` it (e.g., 403 path in `getSeasonStatus`). > - **Safety/Refactors**: Null-safety tweaks (e.g., `ois?.[0]`) and clearer CAIP coercion logic in perps discount; small readability fixes. > - **Tests**: > - Add/expand coverage for multi-account silent auth behavior, active account fallback, 1h threshold logic, async invalidation with token reset, and new `getCandidateSubscriptionId` behavior (silent auth when `sids` not in state). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 45a6464. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent a1730dc commit 9b8734a

File tree

3 files changed

+290
-68
lines changed

3 files changed

+290
-68
lines changed

app/components/UI/Rewards/components/Tabs/LevelsTab/UpcomingRewards.test.tsx

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ jest.mock('../../../../../../reducers/rewards/selectors', () => ({
3434
selectSeasonStartDate: jest.fn(),
3535
}));
3636

37-
jest.mock('../../../../../../selectors/rewards', () => ({
38-
selectRewardsActiveAccountAddress: jest.fn(),
39-
}));
40-
4137
// Mock RewardsErrorBanner
4238
jest.mock('../../RewardsErrorBanner', () => {
4339
const ReactActual = jest.requireActual('react');
@@ -110,8 +106,6 @@ import {
110106
selectSeasonStartDate,
111107
} from '../../../../../../reducers/rewards/selectors';
112108

113-
import { selectRewardsActiveAccountAddress } from '../../../../../../selectors/rewards';
114-
115109
const mockSelectSeasonTiers = selectSeasonTiers as jest.MockedFunction<
116110
typeof selectSeasonTiers
117111
>;
@@ -129,10 +123,6 @@ const mockSelectSeasonStatusError =
129123
const mockSelectSeasonStartDate = selectSeasonStartDate as jest.MockedFunction<
130124
typeof selectSeasonStartDate
131125
>;
132-
const mockSelectRewardsActiveAccountAddress =
133-
selectRewardsActiveAccountAddress as jest.MockedFunction<
134-
typeof selectRewardsActiveAccountAddress
135-
>;
136126

137127
// Mock theme
138128
jest.mock('../../../../../../util/theme', () => ({
@@ -242,15 +232,13 @@ describe('UpcomingRewards', () => {
242232
mockSelectSeasonStatusLoading.mockReturnValue(false);
243233
mockSelectSeasonStatusError.mockReturnValue('');
244234
mockSelectSeasonStartDate.mockReturnValue(new Date('2024-01-01'));
245-
mockSelectRewardsActiveAccountAddress.mockReturnValue('0x123');
246235
mockUseSelector.mockImplementation((selector) => {
247236
if (selector === selectSeasonTiers)
248237
return [mockCurrentTier, mockSeasonTier];
249238
if (selector === selectCurrentTier) return mockCurrentTier;
250239
if (selector === selectSeasonStatusLoading) return false;
251240
if (selector === selectSeasonStatusError) return false;
252241
if (selector === selectSeasonStartDate) return new Date('2024-01-01');
253-
if (selector === selectRewardsActiveAccountAddress) return '0x123';
254242
return [];
255243
});
256244
});

0 commit comments

Comments
 (0)