Skip to content

Commit fe39cab

Browse files
authored
feat: render known facilitator redeemers by name (#354)
* feat: add MetaMask facilitator addresses and update rendering logic in permission handler * Update facilitator tooltip and refine RedeemerField rendering logic * Remove facilitator tooltip and update RedeemerField rendering logic
1 parent 83856eb commit fe39cab

5 files changed

Lines changed: 131 additions & 6 deletions

File tree

packages/gator-permissions-snap/locales/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@
7676
"redeemerTooltip": {
7777
"message": "Only these addresses may redeem this permission."
7878
},
79+
"facilitatorValue": {
80+
"message": "MetaMask facilitator"
81+
},
7982
"payeeLabel": {
8083
"message": "Payees"
8184
},
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export const METAMASK_FACILITATOR_ADDRESSES = [
2+
'0xB01caEa8c6C47bbf4F4b4c5080Ca642043359C2E',
3+
'0xC066ac5D385419B1A8c43A0E146fA439837a8B8c',
4+
'0xB42F812A44c22cc6b861478900401ee759EbEAD6',
5+
] as const;
6+
7+
export const METAMASK_FACILITATOR_ADDRESSES_DEV = [
8+
'0xb4827A2a066CD2Ef88560EFdf063dD05C6c41cC7',
9+
] as const;
10+
11+
const METAMASK_FACILITATOR_ADDRESSES_LOWERCASE = new Set<string>(
12+
[
13+
...METAMASK_FACILITATOR_ADDRESSES,
14+
...METAMASK_FACILITATOR_ADDRESSES_DEV,
15+
].map((address) => address.toLowerCase()),
16+
);
17+
18+
/**
19+
* Checks whether an address is a known MetaMask facilitator signer.
20+
*
21+
* @param address - Address to check.
22+
* @returns Whether the address is a known MetaMask facilitator signer.
23+
*/
24+
export function isMetaMaskFacilitatorAddress(address: string): boolean {
25+
return METAMASK_FACILITATOR_ADDRESSES_LOWERCASE.has(address.toLowerCase());
26+
}

packages/gator-permissions-snap/src/core/permissionHandlerContent.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import { parseCaipAssetType } from '@metamask/utils';
1616

1717
import { ConfirmationDialog } from './confirmation';
18+
import { isMetaMaskFacilitatorAddress } from './facilitatorAddresses';
1819
import { JUSTIFICATION_SHOW_MORE_BUTTON_NAME } from './permissionHandler';
1920
import type { BaseContext, IconData } from './types';
2021
import {
@@ -197,10 +198,14 @@ export const PermissionHandlerContent = ({
197198
/>
198199
);
199200

201+
const shouldRenderRedeemersAsFacilitators =
202+
context.redeemerAddresses?.every(isMetaMaskFacilitatorAddress) ?? false;
203+
200204
const redeemerField = context.redeemerAddresses?.length ? (
201205
<RedeemerField
202206
label={t('redeemerLabel')}
203207
addresses={context.redeemerAddresses}
208+
shouldRenderRedeemersAsFacilitators={shouldRenderRedeemersAsFacilitators}
204209
tooltip={t('redeemerTooltip')}
205210
/>
206211
) : null;
Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
1-
import { Address, Box } from '@metamask/snaps-sdk/jsx';
1+
import { Address, Box, Text } from '@metamask/snaps-sdk/jsx';
22
import type { Hex } from '@metamask/utils';
33

44
import { Field } from './Field';
5+
import { t } from '../../utils/i18n';
56

67
export type RedeemerFieldParams = {
78
label: string;
89
addresses: string[];
910
tooltip?: string | undefined;
11+
shouldRenderRedeemersAsFacilitators?: boolean;
1012
};
1113

1214
export const RedeemerField = ({
1315
label,
1416
addresses,
1517
tooltip,
18+
shouldRenderRedeemersAsFacilitators = false,
1619
}: RedeemerFieldParams): JSX.Element | null => {
1720
if (addresses.length === 0) {
1821
return null;
1922
}
2023

2124
return (
2225
<Field label={label} tooltip={tooltip} variant="display">
23-
<Box direction="vertical">
24-
{addresses.map((addr) => (
25-
<Address key={addr} address={addr as Hex} displayName={true} />
26-
))}
27-
</Box>
26+
{shouldRenderRedeemersAsFacilitators ? (
27+
<Text alignment="end">{t('facilitatorValue')}</Text>
28+
) : (
29+
<Box direction="vertical">
30+
{addresses.map((addr) => (
31+
<Address key={addr} address={addr as Hex} displayName={true} />
32+
))}
33+
</Box>
34+
)}
2835
</Field>
2936
);
3037
};

packages/gator-permissions-snap/test/core/permissionHandler.test.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { AddressScanResultType } from '../../src/clients/trustSignalsClient';
66
import type { TokenBalanceAndMetadata } from '../../src/clients/types';
77
import type { AccountController } from '../../src/core/accountController';
88
import { ExistingPermissionsState } from '../../src/core/existingpermissions/existingPermissionsState';
9+
import { METAMASK_FACILITATOR_ADDRESSES } from '../../src/core/facilitatorAddresses';
910
import { PermissionHandler } from '../../src/core/permissionHandler';
1011
import type { PermissionRequestLifecycleOrchestrator } from '../../src/core/permissionRequestLifecycleOrchestrator';
1112
import type {
@@ -472,6 +473,89 @@ describe('PermissionHandler', () => {
472473
const serialized = JSON.stringify(result);
473474
expect(serialized).toContain('Malicious address');
474475
});
476+
477+
it('renders redeemer addresses as redeemers when no payee rule is present', async () => {
478+
const { permissionHandler, getLifecycleHandlers } = setupTest();
479+
480+
await permissionHandler.handlePermissionRequest(mockOrigin);
481+
482+
const lifecycleHandlers = getLifecycleHandlers();
483+
484+
const result = await lifecycleHandlers.createConfirmationContent({
485+
context: {
486+
...mockContext,
487+
redeemerAddresses: ['0x1111111111111111111111111111111111111111'],
488+
},
489+
metadata: mockMetadata,
490+
origin: mockOrigin,
491+
chainId: 1,
492+
scanDappUrlResult: null,
493+
scanAddressResult: null,
494+
existingPermissionsStatus: ExistingPermissionsState.None,
495+
isGrantDisabled: false,
496+
});
497+
498+
const serialized = JSON.stringify(result);
499+
expect(serialized).toContain('Redeemers');
500+
expect(serialized).not.toContain('Facilitators');
501+
});
502+
503+
it('renders known MetaMask facilitator redeemer addresses as a MetaMask facilitator redeemer', async () => {
504+
const { permissionHandler, getLifecycleHandlers } = setupTest();
505+
506+
await permissionHandler.handlePermissionRequest(mockOrigin);
507+
508+
const lifecycleHandlers = getLifecycleHandlers();
509+
510+
const result = await lifecycleHandlers.createConfirmationContent({
511+
context: {
512+
...mockContext,
513+
redeemerAddresses: [...METAMASK_FACILITATOR_ADDRESSES],
514+
},
515+
metadata: mockMetadata,
516+
origin: mockOrigin,
517+
chainId: 1,
518+
scanDappUrlResult: null,
519+
scanAddressResult: null,
520+
existingPermissionsStatus: ExistingPermissionsState.None,
521+
isGrantDisabled: false,
522+
});
523+
524+
const serialized = JSON.stringify(result);
525+
expect(serialized).toContain('Redeemers');
526+
expect(serialized).toContain('MetaMask facilitator');
527+
expect(serialized).toContain(
528+
'Only these addresses may redeem this permission.',
529+
);
530+
expect(serialized).not.toContain('Facilitators');
531+
});
532+
533+
it('does not render arbitrary redeemer addresses as facilitators when a payee rule is present', async () => {
534+
const { permissionHandler, getLifecycleHandlers } = setupTest();
535+
536+
await permissionHandler.handlePermissionRequest(mockOrigin);
537+
538+
const lifecycleHandlers = getLifecycleHandlers();
539+
540+
const result = await lifecycleHandlers.createConfirmationContent({
541+
context: {
542+
...mockContext,
543+
redeemerAddresses: ['0x1111111111111111111111111111111111111111'],
544+
payeeAddresses: ['0x2222222222222222222222222222222222222222'],
545+
},
546+
metadata: mockMetadata,
547+
origin: mockOrigin,
548+
chainId: 1,
549+
scanDappUrlResult: null,
550+
scanAddressResult: null,
551+
existingPermissionsStatus: ExistingPermissionsState.None,
552+
isGrantDisabled: false,
553+
});
554+
555+
const serialized = JSON.stringify(result);
556+
expect(serialized).toContain('Redeemers');
557+
expect(serialized).not.toContain('Facilitators');
558+
});
475559
});
476560

477561
describe('onConfirmationCreated', () => {

0 commit comments

Comments
 (0)