-
-
Notifications
You must be signed in to change notification settings - Fork 40
Add makePermissionDecoderConfigs to resolve the PermissionDecoderConfigs to be used with @metamask/gator-permissions-controller
#259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
c2c1b68
251a766
2c4a780
1285930
e37bee7
64b1713
09f520e
1930bd9
0e9745c
60e34c6
862842f
7243adc
20aabd3
5227579
2c7dbd9
ec575ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,24 @@ | ||
| // eslint-disable-next-line | ||
| export { default } from '../../shared/config/base.eslint.mjs'; | ||
| // eslint-disable-next-line import-x/extensions | ||
| import baseConfig from '../../shared/config/base.eslint.mjs'; | ||
|
|
||
| const config = [ | ||
| ...baseConfig, | ||
| { | ||
| files: ['test/**/*.ts'], | ||
| languageOptions: { | ||
| parserOptions: { | ||
| projectService: false, | ||
| project: ['./tsconfig.eslint.json'], | ||
| }, | ||
| }, | ||
| settings: { | ||
| 'import/resolver': { | ||
| typescript: { | ||
| project: './tsconfig.eslint.json', | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| ]; | ||
|
|
||
| export default config; |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good call! These are the types that I mentioned this morning :) Updated! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| import { expiryRule } from '../rules/expiry'; | ||
| import { erc20PayeeRuleDecoder } from '../rules/payee'; | ||
| import { redeemerRuleDecoder } from '../rules/redeemer'; | ||
| import type { | ||
| ChecksumCaveat, | ||
| ChecksumEnforcersByChainId, | ||
| DecodedPermissionData, | ||
| MakePermissionDecoderConfig, | ||
| } from '../types'; | ||
| import { | ||
| getByteLength, | ||
| getTermsByEnforcer, | ||
| splitHex, | ||
| UINT256_MAX, | ||
| ZERO_32_BYTES, | ||
| } from '../utils'; | ||
|
|
||
| /** | ||
| * Builds the configuration for the erc20-token-allowance permission decoder. | ||
| * | ||
| * @param contractAddresses - Checksummed enforcer addresses for the chain. | ||
| * @returns The erc20-token-allowance permission decoder configuration. | ||
| */ | ||
| export function makeErc20TokenAllowanceDecoderConfig( | ||
| contractAddresses: ChecksumEnforcersByChainId, | ||
| ): MakePermissionDecoderConfig { | ||
| const { | ||
| timestampEnforcer, | ||
| erc20PeriodicEnforcer, | ||
| valueLteEnforcer, | ||
| nonceEnforcer, | ||
| allowedCalldataEnforcer, | ||
| redeemerEnforcer, | ||
| } = contractAddresses; | ||
|
|
||
| return { | ||
| permissionType: 'erc20-token-allowance', | ||
| contractAddresses, | ||
| optionalEnforcers: [ | ||
| timestampEnforcer, // expiry rule | ||
| redeemerEnforcer, // redeemer rule | ||
| allowedCalldataEnforcer, // payee rule | ||
| ], | ||
| requiredEnforcers: { | ||
| [erc20PeriodicEnforcer]: 1, | ||
| [valueLteEnforcer]: 1, | ||
| [nonceEnforcer]: 1, | ||
| }, | ||
| rules: [expiryRule, redeemerRuleDecoder, erc20PayeeRuleDecoder], | ||
| validateAndDecodeData, | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * Decodes erc20-token-allowance permission data from caveats; throws on invalid. | ||
| * | ||
| * @param caveats - Caveats from the permission context (checksummed). | ||
| * @param contractAddresses - Checksummed enforcer addresses for the chain. | ||
| * @returns Decoded allowance terms. | ||
| */ | ||
| function validateAndDecodeData( | ||
| caveats: ChecksumCaveat[], | ||
| contractAddresses: ChecksumEnforcersByChainId, | ||
| ): DecodedPermissionData { | ||
| const { erc20PeriodicEnforcer, valueLteEnforcer } = contractAddresses; | ||
|
|
||
| const valueLteTerms = getTermsByEnforcer({ | ||
| caveats, | ||
| enforcer: valueLteEnforcer, | ||
| }); | ||
| if (valueLteTerms !== ZERO_32_BYTES) { | ||
| throw new Error(`Invalid value-lte terms: must be ${ZERO_32_BYTES}`); | ||
| } | ||
|
|
||
| const terms = getTermsByEnforcer({ | ||
| caveats, | ||
| enforcer: erc20PeriodicEnforcer, | ||
| }); | ||
|
|
||
| const EXPECTED_TERMS_BYTELENGTH = 116; // 20 + 32 + 32 + 32 | ||
|
|
||
| if (getByteLength(terms) !== EXPECTED_TERMS_BYTELENGTH) { | ||
| throw new Error('Invalid erc20-token-allowance terms: expected 116 bytes'); | ||
| } | ||
|
|
||
| const [tokenAddress, allowanceAmount, periodDurationRaw, startTimeRaw] = | ||
| splitHex(terms, [20, 32, 32, 32]); | ||
| if ( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as above - fixed with an update to |
||
| !tokenAddress || | ||
| !allowanceAmount || | ||
| !periodDurationRaw || | ||
| !startTimeRaw | ||
| ) { | ||
| throw new Error('Invalid erc20-token-allowance terms'); | ||
| } | ||
|
|
||
| if (periodDurationRaw.toLowerCase() !== UINT256_MAX) { | ||
| throw new Error( | ||
| 'Invalid erc20-token-allowance terms: periodDuration must be UINT256_MAX', | ||
| ); | ||
| } | ||
|
|
||
| const startTime = Number.parseInt(startTimeRaw, 16); | ||
|
cursor[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| if (startTime === 0) { | ||
| throw new Error( | ||
| 'Invalid erc20-token-allowance terms: startTime must be a positive number', | ||
| ); | ||
| } | ||
|
|
||
| if (allowanceAmount === ZERO_32_BYTES) { | ||
| throw new Error( | ||
| 'Invalid erc20-token-allowance terms: allowanceAmount must be a positive number', | ||
| ); | ||
| } | ||
|
|
||
| return { tokenAddress, allowanceAmount, startTime }; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| import { decodeERC20TokenPeriodTransferTerms } from '@metamask/delegation-core'; | ||
|
|
||
| import { expiryRule } from '../rules/expiry'; | ||
| import { erc20PayeeRuleDecoder } from '../rules/payee'; | ||
| import { redeemerRuleDecoder } from '../rules/redeemer'; | ||
| import type { | ||
| ChecksumCaveat, | ||
| ChecksumEnforcersByChainId, | ||
| DecodedPermissionData, | ||
| MakePermissionDecoderConfig, | ||
| } from '../types'; | ||
| import { | ||
| getTermsByEnforcer, | ||
| MAX_PERIOD_DURATION, | ||
| ZERO_32_BYTES, | ||
| } from '../utils'; | ||
|
|
||
| /** | ||
| * Builds the configuration for the erc20-token-periodic permission decoder. | ||
| * | ||
| * @param contractAddresses - Checksummed enforcer addresses for the chain. | ||
| * @returns The erc20-token-periodic permission decoder configuration. | ||
| */ | ||
| export function makeErc20TokenPeriodicDecoderConfig( | ||
| contractAddresses: ChecksumEnforcersByChainId, | ||
| ): MakePermissionDecoderConfig { | ||
| const { | ||
| timestampEnforcer, | ||
| erc20PeriodicEnforcer, | ||
| valueLteEnforcer, | ||
| nonceEnforcer, | ||
| allowedCalldataEnforcer, | ||
| redeemerEnforcer, | ||
| } = contractAddresses; | ||
|
|
||
| return { | ||
| permissionType: 'erc20-token-periodic', | ||
| contractAddresses, | ||
| optionalEnforcers: [ | ||
| timestampEnforcer, // expiry rule | ||
| redeemerEnforcer, // redeemer rule | ||
| allowedCalldataEnforcer, // payee rule | ||
| ], | ||
| requiredEnforcers: { | ||
| [erc20PeriodicEnforcer]: 1, | ||
| [valueLteEnforcer]: 1, | ||
| [nonceEnforcer]: 1, | ||
| }, | ||
| rules: [expiryRule, redeemerRuleDecoder, erc20PayeeRuleDecoder], | ||
| validateAndDecodeData, | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * Decodes erc20-token-periodic permission data from caveats; throws on invalid. | ||
| * | ||
| * @param caveats - Caveats from the permission context (checksummed). | ||
| * @param contractAddresses - Checksummed enforcer addresses for the chain. | ||
| * @returns Decoded periodic terms. | ||
| */ | ||
| function validateAndDecodeData( | ||
| caveats: ChecksumCaveat[], | ||
| contractAddresses: ChecksumEnforcersByChainId, | ||
| ): DecodedPermissionData { | ||
| const { erc20PeriodicEnforcer, valueLteEnforcer } = contractAddresses; | ||
|
|
||
| const valueLteTerms = getTermsByEnforcer({ | ||
| caveats, | ||
| enforcer: valueLteEnforcer, | ||
| }); | ||
| if (valueLteTerms !== ZERO_32_BYTES) { | ||
| throw new Error(`Invalid value-lte terms: must be ${ZERO_32_BYTES}`); | ||
| } | ||
|
|
||
| const terms = getTermsByEnforcer({ | ||
| caveats, | ||
| enforcer: erc20PeriodicEnforcer, | ||
| }); | ||
|
|
||
| const { | ||
| tokenAddress, | ||
| periodAmount, | ||
| periodDuration, | ||
| startDate: startTime, | ||
| } = decodeERC20TokenPeriodTransferTerms(terms); | ||
|
|
||
| if (periodAmount === 0n) { | ||
| throw new Error( | ||
| 'Invalid erc20-token-periodic terms: periodAmount must be a positive number', | ||
| ); | ||
| } | ||
|
|
||
| if (periodDuration === 0) { | ||
| throw new Error( | ||
| 'Invalid erc20-token-periodic terms: periodDuration must be a positive number', | ||
| ); | ||
| } | ||
|
|
||
| if (periodDuration > MAX_PERIOD_DURATION) { | ||
| throw new Error( | ||
| 'Invalid erc20-token-periodic terms: periodDuration must be less than or equal to MAX_PERIOD_DURATION', | ||
| ); | ||
| } | ||
|
|
||
| if (startTime === 0) { | ||
| throw new Error( | ||
| 'Invalid erc20-token-periodic terms: startTime must be a positive number', | ||
| ); | ||
| } | ||
|
|
||
| return { tokenAddress, periodAmount, periodDuration, startTime }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move
@metamask/delegation-deploymentstodevDependencies. I think it’s only used for tests.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
I think we could potentially remove the dependency entirely - we don't strictly need the dependency, as we could make up environment values, but it's easier to import 🤷