Skip to content

Commit 482adef

Browse files
authored
Move permission schema metadata into 7715 permission types (#267)
* feat: add permission schema and MetaMask facilitator address utilities * feat: enhance permission schema validation and add tests for inherited properties * feat: add ERC20 and native token permission schemas - Introduced new schemas for ERC20 token allowances, periodic permissions, and streaming permissions. - Added native token schemas for allowances, periodic permissions, and streaming permissions. - Created utility sections for handling justification, permission info, and review summaries. - Implemented token approval revocation schema to manage various token approval methods. - Added handling for unknown permission types with appropriate schema structure. - Refactored utility functions for parsing hex permission amounts. * feat: refine permission schema types and deprecate unused entries * feat: deprecate 'erc20-token-revocation' in permission schema and update registry type
1 parent bc5b896 commit 482adef

18 files changed

Lines changed: 1293 additions & 0 deletions

packages/7715-permission-types/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
- `createNativeTokenAllowanceCaveats()`
1919
- `createTokenApprovalRevocationCaveats()`
2020
- Add `makePermissionDecoderConfigs` to resolve the `PermissionDecoderConfig`s to be used with @metamask/gator-permissions-controller ([#259](https://github.com/MetaMask/smart-accounts-kit/pull/259))
21+
- Add permission schema metadata and MetaMask facilitator address utilities ([#267](https://github.com/MetaMask/smart-accounts-kit/pull/267))
2122

2223
## [0.7.1]
2324

packages/7715-permission-types/src/index.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,49 @@ export {
4040
type DeployedContractsByName,
4141
type PermissionDecoderConfig,
4242
} from './permissions';
43+
export {
44+
DAY,
45+
FORTNIGHT,
46+
HOUR,
47+
MAX_UINT256,
48+
MONTH,
49+
SECOND,
50+
WEEK,
51+
YEAR,
52+
ALL_METAMASK_FACILITATOR_ADDRESSES,
53+
METAMASK_FACILITATOR_ADDRESSES,
54+
METAMASK_FACILITATOR_ADDRESSES_DEV,
55+
areOnlyMetaMaskFacilitatorAddresses,
56+
isMetaMaskFacilitatorAddress,
57+
convertAmountPerSecondToAmountPerPeriod,
58+
convertMillisecondsToSeconds,
59+
formatPermissionPeriodDuration,
60+
getPeriodFrequencyValueTranslationKey,
61+
parseHexPermissionAmount,
62+
getPermissionSchemaEntry,
63+
} from './permissions/schema';
64+
export type {
65+
AccountField,
66+
AddressField,
67+
AmountField,
68+
DateField,
69+
DividerElement,
70+
ExpiryField,
71+
FieldView,
72+
I18nFunction,
73+
JustificationField,
74+
ListField,
75+
NetworkField,
76+
OriginField,
77+
PermissionRenderContext,
78+
PermissionSchemaEntry,
79+
PermissionSchemaRegistry,
80+
RawTextField,
81+
ReviewFieldView,
82+
RuleAddressField,
83+
SchemaElement,
84+
SchemaSection,
85+
TextField,
86+
TokenResolution,
87+
TokenVariant,
88+
} from './permissions/schema';

packages/7715-permission-types/src/permissions/index.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,52 @@ export type { ExpiryRule } from './rules/expiry';
4141
export type { PayeeRule } from './rules/payee';
4242
export type { RedeemerRule } from './rules/redeemer';
4343
export type { DeployedContractsByName, PermissionDecoderConfig };
44+
export {
45+
DAY,
46+
FORTNIGHT,
47+
HOUR,
48+
MAX_UINT256,
49+
MONTH,
50+
SECOND,
51+
WEEK,
52+
YEAR,
53+
ALL_METAMASK_FACILITATOR_ADDRESSES,
54+
METAMASK_FACILITATOR_ADDRESSES,
55+
METAMASK_FACILITATOR_ADDRESSES_DEV,
56+
areOnlyMetaMaskFacilitatorAddresses,
57+
isMetaMaskFacilitatorAddress,
58+
convertAmountPerSecondToAmountPerPeriod,
59+
convertMillisecondsToSeconds,
60+
formatPermissionPeriodDuration,
61+
getPeriodFrequencyValueTranslationKey,
62+
parseHexPermissionAmount,
63+
getPermissionSchemaEntry,
64+
} from './schema';
65+
export type {
66+
AccountField,
67+
AddressField,
68+
AmountField,
69+
DateField,
70+
DividerElement,
71+
ExpiryField,
72+
FieldView,
73+
I18nFunction,
74+
JustificationField,
75+
ListField,
76+
NetworkField,
77+
OriginField,
78+
PermissionRenderContext,
79+
PermissionSchemaEntry,
80+
PermissionSchemaRegistry,
81+
RawTextField,
82+
ReviewFieldView,
83+
RuleAddressField,
84+
SchemaElement,
85+
SchemaSection,
86+
TextField,
87+
TokenResolution,
88+
TokenVariant,
89+
} from './schema';
4490
/**
4591
* Builds the canonical set of permission decoders for a chain.
4692
*
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/** Milliseconds in common time periods. */
2+
export const SECOND = 1000;
3+
export const HOUR = 60 * 60 * SECOND;
4+
export const DAY = 24 * HOUR;
5+
export const WEEK = 7 * DAY;
6+
export const FORTNIGHT = 2 * WEEK;
7+
export const MONTH = 30 * DAY;
8+
export const YEAR = 365 * DAY;
9+
10+
/** Maximum uint256 value as lowercase hex. */
11+
export const MAX_UINT256 =
12+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {
2+
allowanceDetailsSection,
3+
justificationSection,
4+
permissionInfoSection,
5+
requireStartTime,
6+
reviewSummaryAccountSection,
7+
} from './sections';
8+
import type { PermissionSchemaEntry } from './types';
9+
10+
export const erc20TokenAllowanceSchema: PermissionSchemaEntry = {
11+
tokenVariant: 'erc20',
12+
tokenResolution: {
13+
kind: 'erc20',
14+
getTokenAddress: (permission) => permission.data.tokenAddress as string,
15+
},
16+
validate: requireStartTime,
17+
sections: [
18+
justificationSection,
19+
permissionInfoSection,
20+
allowanceDetailsSection(
21+
'erc20-token-allowance-details-section',
22+
'tokenAddress',
23+
),
24+
reviewSummaryAccountSection,
25+
],
26+
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {
2+
justificationSection,
3+
periodicDetailsSection,
4+
permissionInfoSection,
5+
requireStartTime,
6+
reviewSummaryAccountSection,
7+
} from './sections';
8+
import type { PermissionSchemaEntry } from './types';
9+
10+
export const erc20TokenPeriodicSchema: PermissionSchemaEntry = {
11+
tokenVariant: 'erc20',
12+
tokenResolution: {
13+
kind: 'erc20',
14+
getTokenAddress: (permission) => permission.data.tokenAddress as string,
15+
},
16+
validate: requireStartTime,
17+
sections: [
18+
justificationSection,
19+
permissionInfoSection,
20+
periodicDetailsSection(
21+
'erc20-token-periodic-details-section',
22+
'tokenAddress',
23+
),
24+
reviewSummaryAccountSection,
25+
],
26+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {
2+
justificationSection,
3+
permissionInfoSection,
4+
requireStartTime,
5+
reviewSummaryAccountSection,
6+
streamDetailsSection,
7+
streamRateSection,
8+
} from './sections';
9+
import type { PermissionSchemaEntry } from './types';
10+
11+
export const erc20TokenStreamSchema: PermissionSchemaEntry = {
12+
tokenVariant: 'erc20',
13+
tokenResolution: {
14+
kind: 'erc20',
15+
getTokenAddress: (permission) => permission.data.tokenAddress as string,
16+
},
17+
validate: requireStartTime,
18+
sections: [
19+
justificationSection,
20+
permissionInfoSection,
21+
streamDetailsSection('erc20-token-stream-details-section', 'tokenAddress'),
22+
streamRateSection('erc20-token-stream-stream-rate-section', 'tokenAddress'),
23+
reviewSummaryAccountSection,
24+
],
25+
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
export const ALL_METAMASK_FACILITATOR_ADDRESSES = [
12+
...METAMASK_FACILITATOR_ADDRESSES,
13+
...METAMASK_FACILITATOR_ADDRESSES_DEV,
14+
] as const;
15+
16+
const METAMASK_FACILITATOR_ADDRESSES_LOWERCASE = new Set<string>(
17+
ALL_METAMASK_FACILITATOR_ADDRESSES.map((address) => address.toLowerCase()),
18+
);
19+
20+
/**
21+
* Checks whether an address is a known MetaMask facilitator address.
22+
*
23+
* @param address - Address to check.
24+
* @returns True if the address is a known MetaMask facilitator address.
25+
*/
26+
export function isMetaMaskFacilitatorAddress(address: string): boolean {
27+
return METAMASK_FACILITATOR_ADDRESSES_LOWERCASE.has(address.toLowerCase());
28+
}
29+
30+
/**
31+
* Checks whether every provided address is a known MetaMask facilitator address.
32+
*
33+
* @param addresses - Addresses to check.
34+
* @returns True when the list is non-empty and all entries are known facilitators.
35+
*/
36+
export function areOnlyMetaMaskFacilitatorAddresses(
37+
addresses: string[] | null | undefined,
38+
): boolean {
39+
if (!addresses?.length) {
40+
return false;
41+
}
42+
43+
return addresses.every(isMetaMaskFacilitatorAddress);
44+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { erc20TokenAllowanceSchema } from './erc20TokenAllowance';
2+
import { erc20TokenPeriodicSchema } from './erc20TokenPeriodic';
3+
import { erc20TokenStreamSchema } from './erc20TokenStream';
4+
import { nativeTokenAllowanceSchema } from './nativeTokenAllowance';
5+
import { nativeTokenPeriodicSchema } from './nativeTokenPeriodic';
6+
import { nativeTokenStreamSchema } from './nativeTokenStream';
7+
import { tokenApprovalRevocationSchema } from './tokenApprovalRevocation';
8+
import type { PermissionSchemaEntry, PermissionSchemaRegistry } from './types';
9+
import { unknownPermissionTypeSchema } from './unknownPermissionType';
10+
11+
export {
12+
DAY,
13+
FORTNIGHT,
14+
HOUR,
15+
MAX_UINT256,
16+
MONTH,
17+
SECOND,
18+
WEEK,
19+
YEAR,
20+
} from './constants';
21+
export {
22+
ALL_METAMASK_FACILITATOR_ADDRESSES,
23+
METAMASK_FACILITATOR_ADDRESSES,
24+
METAMASK_FACILITATOR_ADDRESSES_DEV,
25+
areOnlyMetaMaskFacilitatorAddresses,
26+
isMetaMaskFacilitatorAddress,
27+
} from './facilitatorAddresses';
28+
export type {
29+
AccountField,
30+
AddressField,
31+
AmountField,
32+
DateField,
33+
DividerElement,
34+
ExpiryField,
35+
FieldView,
36+
I18nFunction,
37+
I18nValue,
38+
JustificationField,
39+
ListField,
40+
NetworkField,
41+
OriginField,
42+
PermissionRenderContext,
43+
PermissionSchemaEntry,
44+
PermissionSchemaRegistry,
45+
RawTextField,
46+
ReviewFieldView,
47+
RuleAddressField,
48+
SchemaElement,
49+
SchemaSection,
50+
TextField,
51+
TokenResolution,
52+
TokenVariant,
53+
} from './types';
54+
export {
55+
convertAmountPerSecondToAmountPerPeriod,
56+
convertMillisecondsToSeconds,
57+
formatPermissionPeriodDuration,
58+
getPeriodFrequencyValueTranslationKey,
59+
parseHexPermissionAmount,
60+
} from './utils';
61+
62+
const PERMISSION_SCHEMAS: PermissionSchemaRegistry = {
63+
'native-token-periodic': nativeTokenPeriodicSchema,
64+
'native-token-stream': nativeTokenStreamSchema,
65+
'native-token-allowance': nativeTokenAllowanceSchema,
66+
'erc20-token-periodic': erc20TokenPeriodicSchema,
67+
'erc20-token-stream': erc20TokenStreamSchema,
68+
'erc20-token-allowance': erc20TokenAllowanceSchema,
69+
'token-approval-revocation': tokenApprovalRevocationSchema,
70+
};
71+
72+
/**
73+
* Gets the schema entry for a permission type.
74+
*
75+
* @param permissionType - Permission type identifier.
76+
* @param throwIfUnknown - Whether to throw instead of returning the unknown schema.
77+
* @returns The matching schema, or the unknown permission schema fallback.
78+
*/
79+
export function getPermissionSchemaEntry(
80+
permissionType: string,
81+
throwIfUnknown: boolean = false,
82+
): PermissionSchemaEntry {
83+
if (
84+
Object.prototype.hasOwnProperty.call(PERMISSION_SCHEMAS, permissionType)
85+
) {
86+
return (PERMISSION_SCHEMAS as Record<string, PermissionSchemaEntry>)[
87+
permissionType
88+
] as PermissionSchemaEntry;
89+
}
90+
if (throwIfUnknown) {
91+
throw new Error(`Unknown permission type: ${permissionType}`);
92+
}
93+
94+
return unknownPermissionTypeSchema;
95+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {
2+
allowanceDetailsSection,
3+
justificationSection,
4+
permissionInfoSection,
5+
requireStartTime,
6+
reviewSummaryAccountSection,
7+
} from './sections';
8+
import type { PermissionSchemaEntry } from './types';
9+
10+
export const nativeTokenAllowanceSchema: PermissionSchemaEntry = {
11+
tokenVariant: 'native',
12+
tokenResolution: { kind: 'native' },
13+
validate: requireStartTime,
14+
sections: [
15+
justificationSection,
16+
permissionInfoSection,
17+
allowanceDetailsSection('native-token-allowance-details-section'),
18+
reviewSummaryAccountSection,
19+
],
20+
};

0 commit comments

Comments
 (0)