Skip to content

Commit 5b84ef7

Browse files
chore(runway): cherry-pick fix(perps): geo-restrict modify and close cp-7.63.0 (#25328)
- fix(perps): geo-restrict modify and close cp-7.63.0 (#25314) ## **Description** Implements geo-restriction for 'close position' and 'modify' actions in Perps trading to ensure compliance with regional regulations. **Problem:** Currently, there is no geo-restriction check for the 'close position' and 'modify' actions. Users in geo-restricted regions can access these features, which should be blocked for compliance. **Solution:** Added geo-restriction checks to both `handleClosePosition` and `handleModifyPress` handlers in `PerpsMarketDetailsView`. When a geo-restricted user taps either button: 1. The geo-block bottom sheet is displayed 2. The action is blocked (no navigation occurs) 3. Analytics event is tracked with the specific action source for monitoring ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: #25315 Jira: https://consensyssoftware.atlassian.net/browse/TAT-2449 ## **Manual testing steps** ```gherkin Feature: Geo-restriction for close position and modify actions Scenario: Geo-restricted user tries to close position Given user is in a geo-restricted region And user has an open position in Perps When user taps the "Close" button on the market details screen Then the geo-restriction bottom sheet is displayed And the close position flow is not initiated Scenario: Geo-restricted user tries to modify position Given user is in a geo-restricted region And user has an open position in Perps When user taps the "Modify" button on the market details screen Then the geo-restriction bottom sheet is displayed And the modify action sheet is not opened Scenario: Eligible user can close position Given user is NOT in a geo-restricted region And user has an open position in Perps When user taps the "Close" button on the market details screen Then user is navigated to the close position flow Scenario: Eligible user can modify position Given user is NOT in a geo-restricted region And user has an open position in Perps When user taps the "Modify" button on the market details screen Then the modify action sheet is opened ``` ## **Screenshots/Recordings** ### **Before** Geo-restricted users could tap Close/Modify buttons and proceed with the actions. ### **After** Geo-restricted users see the geo-block bottom sheet when tapping Close or Modify buttons. ## **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 - [ ] 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** - [ ] 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. [4d2533f](4d2533f) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Implements geo-restriction gating for position management on the Perps market details screen. > > - Blocks `close` and `modify` actions when `isEligible` is false: shows `geo_block` bottom sheet and tracks `PERPS_SCREEN_VIEWED` with `SCREEN_TYPE` `geo_block_notif` and new sources `close_position_action` / `modify_position_action` > - Updates `handleClosePosition` and `handleModifyPress` to include eligibility checks and tracking > - Extends analytics constants with `SOURCE.CLOSE_POSITION_ACTION` and `SOURCE.MODIFY_POSITION_ACTION` > - Adds tests verifying geo-block modal appears and navigation/sheets don’t open for ineligible users on `close` and `modify` > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 59adc5d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Alejandro Garcia Anglada <aganglada@gmail.com>
1 parent ef19971 commit 5b84ef7

3 files changed

Lines changed: 142 additions & 2 deletions

File tree

app/components/UI/Perps/Views/PerpsMarketDetailsView/PerpsMarketDetailsView.test.tsx

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,117 @@ describe('PerpsMarketDetailsView', () => {
13721372

13731373
expect(queryByText('Geo Block Tooltip')).toBeNull();
13741374
});
1375+
1376+
// TAT-2449: Geo-restriction tests for close/modify actions
1377+
it('shows geo block modal when close position button is pressed and user is not eligible', () => {
1378+
const { useSelector } = jest.requireMock('react-redux');
1379+
const mockSelectPerpsEligibility = jest.requireMock(
1380+
'../../selectors/perpsController',
1381+
).selectPerpsEligibility;
1382+
useSelector.mockImplementation((selector: unknown) => {
1383+
if (selector === mockSelectPerpsEligibility) {
1384+
return false;
1385+
}
1386+
return undefined;
1387+
});
1388+
1389+
// Set up existing position to show close button
1390+
mockUseHasExistingPosition.mockReturnValue({
1391+
hasPosition: true,
1392+
isLoading: false,
1393+
error: null,
1394+
existingPosition: {
1395+
symbol: 'BTC',
1396+
size: '0.5',
1397+
entryPrice: '44000',
1398+
positionValue: '22000',
1399+
unrealizedPnl: '50',
1400+
marginUsed: '500',
1401+
leverage: { type: 'isolated', value: 5 },
1402+
liquidationPrice: '40000',
1403+
maxLeverage: 20,
1404+
returnOnEquity: '1.14',
1405+
cumulativeFunding: {
1406+
allTime: '0',
1407+
sinceOpen: '0',
1408+
sinceChange: '0',
1409+
},
1410+
},
1411+
refreshPosition: jest.fn(),
1412+
});
1413+
1414+
const { getByTestId, getByText } = renderWithProvider(
1415+
<PerpsConnectionProvider>
1416+
<PerpsMarketDetailsView />
1417+
</PerpsConnectionProvider>,
1418+
{
1419+
state: initialState,
1420+
},
1421+
);
1422+
1423+
const closeButton = getByTestId(
1424+
PerpsMarketDetailsViewSelectorsIDs.CLOSE_BUTTON,
1425+
);
1426+
fireEvent.press(closeButton);
1427+
1428+
expect(getByText('Geo Block Tooltip')).toBeTruthy();
1429+
expect(mockNavigate).not.toHaveBeenCalled();
1430+
});
1431+
1432+
it('shows geo block modal when modify button is pressed and user is not eligible', () => {
1433+
const { useSelector } = jest.requireMock('react-redux');
1434+
const mockSelectPerpsEligibility = jest.requireMock(
1435+
'../../selectors/perpsController',
1436+
).selectPerpsEligibility;
1437+
useSelector.mockImplementation((selector: unknown) => {
1438+
if (selector === mockSelectPerpsEligibility) {
1439+
return false;
1440+
}
1441+
return undefined;
1442+
});
1443+
1444+
// Set up existing position to show modify button
1445+
mockUseHasExistingPosition.mockReturnValue({
1446+
hasPosition: true,
1447+
isLoading: false,
1448+
error: null,
1449+
existingPosition: {
1450+
symbol: 'BTC',
1451+
size: '0.5',
1452+
entryPrice: '44000',
1453+
positionValue: '22000',
1454+
unrealizedPnl: '50',
1455+
marginUsed: '500',
1456+
leverage: { type: 'isolated', value: 5 },
1457+
liquidationPrice: '40000',
1458+
maxLeverage: 20,
1459+
returnOnEquity: '1.14',
1460+
cumulativeFunding: {
1461+
allTime: '0',
1462+
sinceOpen: '0',
1463+
sinceChange: '0',
1464+
},
1465+
},
1466+
refreshPosition: jest.fn(),
1467+
});
1468+
1469+
const { getByTestId, getByText } = renderWithProvider(
1470+
<PerpsConnectionProvider>
1471+
<PerpsMarketDetailsView />
1472+
</PerpsConnectionProvider>,
1473+
{
1474+
state: initialState,
1475+
},
1476+
);
1477+
1478+
const modifyButton = getByTestId(
1479+
PerpsMarketDetailsViewSelectorsIDs.MODIFY_BUTTON,
1480+
);
1481+
fireEvent.press(modifyButton);
1482+
1483+
expect(getByText('Geo Block Tooltip')).toBeTruthy();
1484+
// Modify sheet should NOT open when user is not eligible
1485+
});
13751486
});
13761487

13771488
describe('Notification tooltip functionality', () => {

app/components/UI/Perps/Views/PerpsMarketDetailsView/PerpsMarketDetailsView.tsx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -784,14 +784,40 @@ const PerpsMarketDetailsView: React.FC<PerpsMarketDetailsViewProps> = () => {
784784
// Close position handler
785785
const handleClosePosition = useCallback(() => {
786786
if (!existingPosition) return;
787+
788+
// Geo-restriction check for close position action
789+
if (!isEligible) {
790+
track(MetaMetricsEvents.PERPS_SCREEN_VIEWED, {
791+
[PerpsEventProperties.SCREEN_TYPE]:
792+
PerpsEventValues.SCREEN_TYPE.GEO_BLOCK_NOTIF,
793+
[PerpsEventProperties.SOURCE]:
794+
PerpsEventValues.SOURCE.CLOSE_POSITION_ACTION,
795+
});
796+
setIsEligibilityModalVisible(true);
797+
return;
798+
}
799+
787800
navigateToClosePosition(existingPosition);
788-
}, [existingPosition, navigateToClosePosition]);
801+
}, [existingPosition, navigateToClosePosition, isEligible, track]);
789802

790803
// Modify position handler - opens the modify action sheet
791804
const handleModifyPress = useCallback(() => {
792805
if (!existingPosition) return;
806+
807+
// Geo-restriction check for modify position action
808+
if (!isEligible) {
809+
track(MetaMetricsEvents.PERPS_SCREEN_VIEWED, {
810+
[PerpsEventProperties.SCREEN_TYPE]:
811+
PerpsEventValues.SCREEN_TYPE.GEO_BLOCK_NOTIF,
812+
[PerpsEventProperties.SOURCE]:
813+
PerpsEventValues.SOURCE.MODIFY_POSITION_ACTION,
814+
});
815+
setIsEligibilityModalVisible(true);
816+
return;
817+
}
818+
793819
openModifySheet();
794-
}, [existingPosition, openModifySheet]);
820+
}, [existingPosition, openModifySheet, isEligible, track]);
795821

796822
// Handler for "Add Margin" from stop loss prompt banner
797823
const handleAddMarginFromBanner = useCallback(() => {

app/components/UI/Perps/constants/eventNames.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,9 @@ export const PerpsEventValues = {
211211
ADD_FUNDS_ACTION: 'add_funds_action',
212212
CANCEL_ORDER: 'cancel_order',
213213
ASSET_DETAIL_SCREEN: 'asset_detail_screen',
214+
// TAT-2449: Geo-block sources for close/modify actions
215+
CLOSE_POSITION_ACTION: 'close_position_action',
216+
MODIFY_POSITION_ACTION: 'modify_position_action',
214217
},
215218
WARNING_TYPE: {
216219
MINIMUM_DEPOSIT: 'minimum_deposit',

0 commit comments

Comments
 (0)