Skip to content

Commit ebc6f30

Browse files
authored
refactor: Support permitted chains on permission confirmation page (#30443)
## **Description** The permissions confirmation page currently ignores the `requestedChainIds` prop when the connection is confirmed. This hasn't resulted in a bug because this page is only used for snap permissions. Permission requests for `eth_account` or `endowment:permitted-chains` are handled by the "ChooseAccount" or "ConnectPage" components (the former if a snap is also requested alongside, the latter otherwise). This PR fixes the problem regardless, as it's confusing for the component to have this prop but to ignore it when processing the confirmation. This was extracted from #27782 [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/30443?quickstart=1) ## **Related issues** See this comment for some additional context: https://github.com/MetaMask/metamask-extension/pull/27782/files#r1936463248 ## **Manual testing steps** N/A, the impacted functionality is unreachable. ## **Screenshots/Recordings** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/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-extension/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.
1 parent e98d34d commit ebc6f30

File tree

5 files changed

+117
-45
lines changed

5 files changed

+117
-45
lines changed

ui/components/app/permission-page-container/permission-page-container.component.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ import {
44
SnapCaveatType,
55
WALLET_SNAP_PERMISSION_KEY,
66
} from '@metamask/snaps-rpc-methods';
7-
import {
8-
Caip25EndowmentPermissionName,
9-
getPermittedEthChainIds,
10-
} from '@metamask/multichain';
7+
import { Caip25EndowmentPermissionName } from '@metamask/multichain';
118
import { SubjectType } from '@metamask/permission-controller';
129
import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics';
1310
import { PageContainerFooter } from '../../ui/page-container';
@@ -24,7 +21,7 @@ import {
2421
} from '../../../helpers/constants/design-system';
2522
import { Box } from '../../component-library';
2623
import {
27-
getRequestedSessionScopes,
24+
getRequestedCaip25CaveatValue,
2825
getCaip25PermissionsResponse,
2926
} from '../../../pages/permissions-connect/connect-page/utils';
3027
import { containsEthPermissionsAndNonEvmAccount } from '../../../helpers/utils/permissions';
@@ -145,22 +142,26 @@ export default class PermissionPageContainer extends Component {
145142
approvePermissionsRequest,
146143
rejectPermissionsRequest,
147144
selectedAccounts,
145+
requestedChainIds,
148146
} = this.props;
149147

150148
const approvedAccounts = selectedAccounts.map(
151149
(selectedAccount) => selectedAccount.address,
152150
);
153151

154-
const requestedSessionsScopes = getRequestedSessionScopes(
155-
_request.permission,
152+
const requestedCaip25CaveatValue = getRequestedCaip25CaveatValue(
153+
_request.permissions,
156154
);
157-
const approvedChainIds = getPermittedEthChainIds(requestedSessionsScopes);
158155

159156
const request = {
160157
..._request,
161158
permissions: {
162159
..._request.permissions,
163-
...getCaip25PermissionsResponse(approvedAccounts, approvedChainIds),
160+
...getCaip25PermissionsResponse(
161+
requestedCaip25CaveatValue,
162+
approvedAccounts,
163+
requestedChainIds,
164+
),
164165
},
165166
};
166167

ui/pages/permissions-connect/connect-page/connect-page.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ import {
6363
import { MetaMetricsContext } from '../../../contexts/metametrics';
6464
import {
6565
getCaip25PermissionsResponse,
66-
getRequestedSessionScopes,
6766
PermissionsRequest,
67+
getRequestedCaip25CaveatValue,
6868
} from './utils';
6969

7070
export type ConnectPageRequest = {
@@ -98,11 +98,11 @@ export const ConnectPage: React.FC<ConnectPageProps> = ({
9898
const t = useI18nContext();
9999
const trackEvent = useContext(MetaMetricsContext);
100100

101-
const requestedSessionsScopes = getRequestedSessionScopes(
101+
const requestedCaip25CaveatValue = getRequestedCaip25CaveatValue(
102102
request.permissions,
103103
);
104-
const requestedAccounts = getEthAccounts(requestedSessionsScopes);
105-
const requestedChainIds = getPermittedEthChainIds(requestedSessionsScopes);
104+
const requestedAccounts = getEthAccounts(requestedCaip25CaveatValue);
105+
const requestedChainIds = getPermittedEthChainIds(requestedCaip25CaveatValue);
106106

107107
const networkConfigurations = useSelector(getNetworkConfigurationsByChainId);
108108
const [nonTestNetworks, testNetworks] = useMemo(
@@ -180,6 +180,7 @@ export const ConnectPage: React.FC<ConnectPageProps> = ({
180180
permissions: {
181181
...request.permissions,
182182
...getCaip25PermissionsResponse(
183+
requestedCaip25CaveatValue,
183184
selectedAccountAddresses as Hex[],
184185
selectedChainIds,
185186
),

ui/pages/permissions-connect/connect-page/utils.test.ts

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,24 @@ import { Hex } from '@metamask/utils';
66
import { CHAIN_IDS } from '../../../../shared/constants/network';
77
import { getCaip25PermissionsResponse } from './utils';
88

9+
const baseCaip25CaveatValue = {
10+
requiredScopes: {},
11+
optionalScopes: {
12+
'wallet:eip155': {
13+
accounts: [],
14+
},
15+
},
16+
isMultichainOrigin: false,
17+
};
18+
919
describe('getCaip25PermissionsResponse', () => {
1020
describe('No accountAddresses or chainIds requested', () => {
1121
it(`should construct a valid ${Caip25EndowmentPermissionName} empty permission`, () => {
12-
const result = getCaip25PermissionsResponse([], []);
22+
const result = getCaip25PermissionsResponse(
23+
baseCaip25CaveatValue,
24+
[],
25+
[],
26+
);
1327

1428
expect(result).toEqual({
1529
[Caip25EndowmentPermissionName]: {
@@ -35,7 +49,11 @@ describe('getCaip25PermissionsResponse', () => {
3549
describe('Request approval for chainIds', () => {
3650
it(`should construct a valid ${Caip25EndowmentPermissionName} permission from the passed chainIds`, () => {
3751
const hexChainIds: Hex[] = [CHAIN_IDS.ARBITRUM];
38-
const result = getCaip25PermissionsResponse([], hexChainIds);
52+
const result = getCaip25PermissionsResponse(
53+
baseCaip25CaveatValue,
54+
[],
55+
hexChainIds,
56+
);
3957

4058
expect(result).toEqual({
4159
[Caip25EndowmentPermissionName]: {
@@ -60,11 +78,16 @@ describe('getCaip25PermissionsResponse', () => {
6078
});
6179
});
6280
});
81+
6382
describe('Request approval for accountAddresses', () => {
6483
it(`should construct a valid ${Caip25EndowmentPermissionName} permission from the passed accountAddresses`, () => {
6584
const addresses: Hex[] = ['0x4c286da233db3d63d44dc2ec8adc8b6dfb595cb4'];
6685

67-
const result = getCaip25PermissionsResponse(addresses, []);
86+
const result = getCaip25PermissionsResponse(
87+
baseCaip25CaveatValue,
88+
addresses,
89+
[],
90+
);
6891

6992
expect(result).toEqual({
7093
[Caip25EndowmentPermissionName]: {
@@ -88,12 +111,17 @@ describe('getCaip25PermissionsResponse', () => {
88111
});
89112
});
90113
});
114+
91115
describe('Request approval for accountAddresses and chainIds', () => {
92116
it(`should construct a valid ${Caip25EndowmentPermissionName} permission from the passed accountAddresses and chainIds`, () => {
93117
const addresses: Hex[] = ['0x4c286da233db3d63d44dc2ec8adc8b6dfb595cb4'];
94118
const hexChainIds: Hex[] = [CHAIN_IDS.ARBITRUM, CHAIN_IDS.LINEA_MAINNET];
95119

96-
const result = getCaip25PermissionsResponse(addresses, hexChainIds);
120+
const result = getCaip25PermissionsResponse(
121+
baseCaip25CaveatValue,
122+
addresses,
123+
hexChainIds,
124+
);
97125

98126
expect(result).toEqual({
99127
[Caip25EndowmentPermissionName]: {
@@ -127,4 +155,54 @@ describe('getCaip25PermissionsResponse', () => {
127155
});
128156
});
129157
});
158+
159+
describe('Request approval including non-evm scopes', () => {
160+
it('only modifies evm related scopes', () => {
161+
const addresses: Hex[] = ['0x4c286da233db3d63d44dc2ec8adc8b6dfb595cb4'];
162+
const hexChainIds: Hex[] = ['0x1'];
163+
164+
const result = getCaip25PermissionsResponse(
165+
{
166+
...baseCaip25CaveatValue,
167+
requiredScopes: {
168+
'bip122:000000000019d6689c085ae165831e93': {
169+
accounts: [],
170+
},
171+
},
172+
},
173+
addresses,
174+
hexChainIds,
175+
);
176+
177+
expect(result).toEqual({
178+
[Caip25EndowmentPermissionName]: {
179+
caveats: [
180+
{
181+
type: Caip25CaveatType,
182+
value: {
183+
requiredScopes: {
184+
'bip122:000000000019d6689c085ae165831e93': {
185+
accounts: [],
186+
},
187+
},
188+
optionalScopes: {
189+
'wallet:eip155': {
190+
accounts: [
191+
'wallet:eip155:0x4c286da233db3d63d44dc2ec8adc8b6dfb595cb4',
192+
],
193+
},
194+
'eip155:1': {
195+
accounts: [
196+
'eip155:1:0x4c286da233db3d63d44dc2ec8adc8b6dfb595cb4',
197+
],
198+
},
199+
},
200+
isMultichainOrigin: false,
201+
},
202+
},
203+
],
204+
},
205+
});
206+
});
207+
});
130208
});

ui/pages/permissions-connect/connect-page/utils.ts

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,57 +13,49 @@ export type PermissionsRequest = Record<
1313
>;
1414

1515
/**
16-
* Takes in an incoming {@link PermissionsRequest} and attempts to return the {@link Caip25CaveatValue} with the Ethereum accounts set.
16+
* Takes in an incoming {@link PermissionsRequest} and attempts to return the {@link Caip25CaveatValue}.
1717
*
1818
* @param permissions - The {@link PermissionsRequest} with the target name of the {@link Caip25EndowmentPermissionName}.
19-
* @returns The {@link Caip25CaveatValue} with the Ethereum accounts set.
19+
* @returns The {@link Caip25CaveatValue}.
2020
*/
21-
export function getRequestedSessionScopes(
21+
export function getRequestedCaip25CaveatValue(
2222
permissions?: PermissionsRequest,
23-
): Pick<Caip25CaveatValue, 'requiredScopes' | 'optionalScopes'> {
23+
): Caip25CaveatValue {
2424
return (
2525
permissions?.[Caip25EndowmentPermissionName]?.caveats?.find(
2626
(caveat) => caveat.type === Caip25CaveatType,
2727
)?.value ?? {
2828
optionalScopes: {},
2929
requiredScopes: {},
30+
isMultichainOrigin: false,
3031
}
3132
);
3233
}
3334

3435
/**
35-
* Parses the CAIP-25 authorized permissions object after UI confirmation.
36+
* Modifies the requested CAIP-25 permissions object after UI confirmation.
3637
*
37-
* @param addresses - The list of permitted addresses.
38-
* @param hexChainIds - The list of permitted chains.
39-
* @returns The granted permissions with the target name of the {@link Caip25EndowmentPermissionName}.
38+
* @param caip25CaveatValue - The requested CAIP-25 caveat value to modify.
39+
* @param ethAccountAddresses - The list of permitted eth addresses.
40+
* @param ethChainIds - The list of permitted eth chainIds.
4041
*/
4142
export function getCaip25PermissionsResponse(
42-
addresses: Hex[],
43-
hexChainIds: Hex[],
43+
caip25CaveatValue: Caip25CaveatValue,
44+
ethAccountAddresses: Hex[],
45+
ethChainIds: Hex[],
4446
): {
4547
[Caip25EndowmentPermissionName]: {
4648
caveats: [{ type: string; value: Caip25CaveatValue }];
4749
};
4850
} {
49-
const caveatValue: Caip25CaveatValue = {
50-
requiredScopes: {},
51-
optionalScopes: {
52-
'wallet:eip155': {
53-
accounts: [],
54-
},
55-
},
56-
isMultichainOrigin: false,
57-
};
58-
5951
const caveatValueWithChains = setPermittedEthChainIds(
60-
caveatValue,
61-
hexChainIds,
52+
caip25CaveatValue,
53+
ethChainIds,
6254
);
6355

6456
const caveatValueWithAccounts = setEthAccounts(
6557
caveatValueWithChains,
66-
addresses,
58+
ethAccountAddresses,
6759
);
6860

6961
return {

ui/pages/permissions-connect/permissions-connect.component.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ import SnapInstall from './snaps/snap-install';
2020
import SnapUpdate from './snaps/snap-update';
2121
import SnapResult from './snaps/snap-result';
2222
import { ConnectPage } from './connect-page/connect-page';
23-
import { getRequestedSessionScopes } from './connect-page/utils';
23+
import { getRequestedCaip25CaveatValue } from './connect-page/utils';
2424

2525
const APPROVE_TIMEOUT = MILLISECOND * 1200;
2626

2727
function getDefaultSelectedAccounts(currentAddress, permissions) {
28-
const requestedSessionsScopes = getRequestedSessionScopes(permissions);
29-
const requestedAccounts = getEthAccounts(requestedSessionsScopes);
28+
const requestedCaip25CaveatValue = getRequestedCaip25CaveatValue(permissions);
29+
const requestedAccounts = getEthAccounts(requestedCaip25CaveatValue);
3030

3131
if (requestedAccounts.length > 0) {
3232
return new Set(
@@ -42,8 +42,8 @@ function getDefaultSelectedAccounts(currentAddress, permissions) {
4242
}
4343

4444
function getRequestedChainIds(permissions) {
45-
const requestedSessionsScopes = getRequestedSessionScopes(permissions);
46-
return getPermittedEthChainIds(requestedSessionsScopes);
45+
const requestedCaip25CaveatValue = getRequestedCaip25CaveatValue(permissions);
46+
return getPermittedEthChainIds(requestedCaip25CaveatValue);
4747
}
4848

4949
export default class PermissionConnect extends Component {

0 commit comments

Comments
 (0)