Skip to content

Commit 7fa5f96

Browse files
authored
Add erc-20-token-periodic permission type (#106)
* Add erc-20-token-periodic permission type * Update test expecting registered permission types
1 parent e1f993e commit 7fa5f96

19 files changed

Lines changed: 1999 additions & 2 deletions

File tree

packages/gator-permissions-snap/snap.manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"url": "https://github.com/MetaMask/snap-7715-permissions.git"
88
},
99
"source": {
10-
"shasum": "wxFuepgNYszIuMhyZUUKI3m8UQQAL7uEsuQO0oBrYKQ=",
10+
"shasum": "tmWf9Cs6ZEvAWQ3dATmdBU8nIH8BjJsUHuJfaRcnsZs=",
1111
"location": {
1212
"npm": {
1313
"filePath": "dist/bundle.js",

packages/gator-permissions-snap/src/core/permissionHandlerFactory.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { PermissionRequest } from '@metamask/7715-permissions-shared/types'
22
import { extractPermissionName } from '@metamask/7715-permissions-shared/utils';
33

44
import type { AccountController } from '../accountController';
5+
import { erc20TokenPeriodicPermissionDefinition } from '../permissions/erc20TokenPeriodic';
56
import { erc20TokenStreamPermissionDefinition } from '../permissions/erc20TokenStream';
67
import { nativeTokenPeriodicPermissionDefinition } from '../permissions/nativeTokenPeriodic';
78
import { nativeTokenStreamPermissionDefinition } from '../permissions/nativeTokenStream';
@@ -104,6 +105,11 @@ export class PermissionHandlerFactory {
104105
case 'erc20-token-stream':
105106
handler = createPermissionHandler(erc20TokenStreamPermissionDefinition);
106107
break;
108+
case 'erc20-token-periodic':
109+
handler = createPermissionHandler(
110+
erc20TokenPeriodicPermissionDefinition,
111+
);
112+
break;
107113
default:
108114
throw new Error(`Unsupported permission type: ${type}`);
109115
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type { CoreCaveatBuilder } from '@metamask/delegation-toolkit';
2+
3+
import type { PopulatedErc20TokenPeriodicPermission } from './types';
4+
5+
/**
6+
* Appends permission-specific caveats to the caveat builder.
7+
* @param options0 - The options object containing the permission and caveat builder.
8+
* @param options0.permission - The complete ERC20 token periodic permission containing periodic parameters.
9+
* @param options0.caveatBuilder - The core caveat builder to append caveats to.
10+
* @returns The modified caveat builder with appended ERC20 token periodic caveats.
11+
*/
12+
export async function appendCaveats({
13+
permission,
14+
caveatBuilder,
15+
}: {
16+
permission: PopulatedErc20TokenPeriodicPermission;
17+
caveatBuilder: CoreCaveatBuilder;
18+
}): Promise<CoreCaveatBuilder> {
19+
const { periodAmount, periodDuration, startTime, tokenAddress } =
20+
permission.data;
21+
22+
caveatBuilder
23+
.addCaveat(
24+
'erc20PeriodTransfer',
25+
tokenAddress,
26+
BigInt(periodAmount),
27+
periodDuration,
28+
startTime,
29+
)
30+
.addCaveat('valueLte', 0n);
31+
32+
return caveatBuilder;
33+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import type { GenericSnapElement } from '@metamask/snaps-sdk/jsx';
2+
import { Box, Section } from '@metamask/snaps-sdk/jsx';
3+
4+
import { getChainName } from '../../../../shared/src/utils/common';
5+
import { JUSTIFICATION_SHOW_MORE_BUTTON_NAME } from '../../core/permissionHandler';
6+
import { renderRules } from '../../core/rules';
7+
import { AccountDetails } from '../../ui/components/AccountDetails';
8+
import type { ItemDetails } from '../../ui/components/RequestDetails';
9+
import { RequestDetails } from '../../ui/components/RequestDetails';
10+
import {
11+
periodAmountRule,
12+
periodTypeRule,
13+
periodDurationRule,
14+
startTimeRule,
15+
expiryRule,
16+
} from './rules';
17+
import type {
18+
Erc20TokenPeriodicContext,
19+
Erc20TokenPeriodicMetadata,
20+
} from './types';
21+
22+
/**
23+
* Creates UI content for an ERC20 token periodic permission confirmation.
24+
*
25+
* @param args - The configuration for the confirmation content.
26+
* @param args.context - The context containing permission details.
27+
* @param args.metadata - Metadata including derived values and validation errors.
28+
* @param args.isJustificationCollapsed - Whether the justification section is collapsed.
29+
* @param args.origin - The origin requesting the permission.
30+
* @param args.chainId - The chain ID for the permission.
31+
* @returns A Promise that resolves to the UI element for the confirmation dialog.
32+
*/
33+
export async function createConfirmationContent({
34+
context,
35+
metadata,
36+
isJustificationCollapsed,
37+
origin,
38+
chainId,
39+
}: {
40+
context: Erc20TokenPeriodicContext;
41+
metadata: Erc20TokenPeriodicMetadata;
42+
isJustificationCollapsed: boolean;
43+
origin: string;
44+
chainId: number;
45+
}): Promise<GenericSnapElement> {
46+
const networkName = getChainName(chainId);
47+
48+
const itemDetails: ItemDetails[] = [
49+
{
50+
label: 'Recipient',
51+
text: origin,
52+
tooltipText: 'The site requesting the permission',
53+
},
54+
{
55+
label: 'Network',
56+
text: networkName,
57+
tooltipText: 'The network on which the permission is being requested',
58+
},
59+
{
60+
label: 'Token',
61+
text: context.tokenMetadata.symbol,
62+
iconData: context.tokenMetadata.iconDataBase64
63+
? {
64+
iconDataBase64: context.tokenMetadata.iconDataBase64,
65+
altText: context.tokenMetadata.symbol,
66+
}
67+
: undefined,
68+
},
69+
];
70+
71+
return (
72+
<Box>
73+
<Box direction="vertical">
74+
<RequestDetails
75+
itemDetails={itemDetails}
76+
justification={context.justification}
77+
isJustificationShowMoreCollapsed={isJustificationCollapsed}
78+
justificationShowMoreElementName={JUSTIFICATION_SHOW_MORE_BUTTON_NAME}
79+
/>
80+
<AccountDetails
81+
account={context.accountDetails}
82+
tokenMetadata={context.tokenMetadata}
83+
title="Transfer from"
84+
tooltip="The account that the token transfers come from."
85+
/>
86+
<Section>
87+
{renderRules({
88+
rules: [
89+
startTimeRule,
90+
periodAmountRule,
91+
periodTypeRule,
92+
periodDurationRule,
93+
],
94+
context,
95+
metadata,
96+
})}
97+
</Section>
98+
99+
<Section>
100+
{renderRules({
101+
rules: [expiryRule],
102+
context,
103+
metadata,
104+
})}
105+
</Section>
106+
</Box>
107+
</Box>
108+
);
109+
}

0 commit comments

Comments
 (0)