Skip to content

feat: adds utility functions to create caveats array for each permission type#265

Open
jeffsmale90 wants to merge 4 commits into
mainfrom
feat/permission-caveat-builders
Open

feat: adds utility functions to create caveats array for each permission type#265
jeffsmale90 wants to merge 4 commits into
mainfrom
feat/permission-caveat-builders

Conversation

@jeffsmale90

@jeffsmale90 jeffsmale90 commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

📝 Description

This PR adds utility functions to create caveats array for each permission type to @metamask/7715-permission-types. These were migrated from @metamask/gator-permissions-snap.

🔄 What Changed?

Adds new utility functions that accept a populated permission object, and specific caveat addresses, and returns the Caveat<Hex>[] representing that permission.

  • createErc20TokenStreamCaveats()
  • createErc20TokenPeriodicCaveats()
  • createErc20TokenAllowanceCaveats()
  • createNativeTokenStreamCaveats()
  • createNativeTokenPeriodicCaveats()
  • createNativeTokenAllowanceCaveats()
  • createTokenApprovalRevocationCaveats()

🚀 Why?

Presently when adding new permission types to MetaMask Advanced Permissions, changes must be made across a number of different repositories. By centralising the permission definitions into a single repository, it allows us to add a permission definition in one place (@metamask/7715-permission-types), and simply update dependencies across @metamask/gator-permissions-controller, @metamask/gator-permissions-snap, @metamask/smart-accounts-kit, and MetaMask clients.

This change is migrating one of the components needed to achieve that vision.

🧪 How to Test?

The changes in this PR are integrated into @metamask/gator-permissions-snap in this draft PR MetaMask/snap-7715-permissions#363. Adding a reference to @metamask/7715-permission-types with the changes from this PR, then validate with the following steps:

  • Grant each of the permission types, with varying options selected
  • Ensure that the signature confirmation matches the snap confirmation (this is dependent on the caveats encoding implemented in this pr)
  • Validate the decoded caveat terms on the snap development page

⚠️ Breaking Changes

List any breaking changes:

  • No breaking changes
  • Breaking changes (describe below):

📋 Checklist

Check off completed items:

  • Code follows the project's coding standards
  • Self-review completed
  • Documentation updated (if needed)
  • Tests added/updated
  • Changelog updated (if needed)
  • All CI checks pass

🔗 Related Issues

Link to related issues:
Closes #
Related to #

📚 Additional Notes

Any additional information, concerns, or context:


Note

High Risk
Builders define delegation caveat bytes that constrain token and approval-revocation execution; encoding mistakes could misrepresent granted permissions on-chain despite matching existing snap behavior and decoder tests.

Overview
Adds encode-side helpers in @metamask/7715-permission-types (migrated from @metamask/gator-permissions-snap) so callers can turn a fully specified ERC-7715 permission into the on-chain Caveat[] for that type.

Seven new create*Caveats() functions live next to the existing decoders: ERC-20 stream/periodic/allowance, native stream/periodic/allowance, and token-approval-revocation. Each takes DeepRequired<…Permission> plus chain enforcer addresses (*Enforcers types) and returns caveats built via @metamask/delegation-core (e.g. periodic/streaming terms, valueLte at zero for ERC-20, exactCalldata 0x for native ETH). DeepRequired is added for builder inputs; builders and enforcer types are re-exported from the package entry.

Vitest suites assert encoded terms match what the decoders already expect. Changelog documents the new APIs.

Reviewed by Cursor Bugbot for commit 488e6ce. Bugbot is set up for automated code reviews on this repo. Configure here.

Base automatically changed from feat/permission-decoders to main June 18, 2026 20:46
@jeffsmale90 jeffsmale90 force-pushed the feat/permission-caveat-builders branch from 16da695 to 05387b5 Compare June 18, 2026 21:45
Comment on lines +151 to +152
// delegation-core accepts bigint for encoding although the type is `number`.
periodDuration: BigInt(UINT256_MAX) as unknown as number,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a temporary measure, until we migrate to the fixed allowance enforcer.

terms: createNativeTokenPeriodTransferTerms({
periodAmount: BigInt(allowanceAmount),
// delegation-core accepts bigint for encoding although the type is `number`.
periodDuration: BigInt(UINT256_MAX) as unknown as number,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a temporary measure, until we migrate to the fixed allowance enforcer.

@jeffsmale90 jeffsmale90 changed the title Feat/permission caveat builders feat: adds utility functions to create caveats array for each permission type Jun 18, 2026
@jeffsmale90 jeffsmale90 marked this pull request as ready for review June 18, 2026 23:00
@jeffsmale90 jeffsmale90 requested a review from a team as a code owner June 18, 2026 23:00

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 488e6ce. Configure here.

@mj-kiwi mj-kiwi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some functions are labeled async yet contain no await calls. Should we turn them sync instead?

* @param options0.contracts - Enforcer addresses used to construct caveats.
* @returns The ERC-20 allowance and zero-value caveats.
*/
export async function createErc20TokenAllowanceCaveats({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can’t see any await inside this function, should we delete the async here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants