Add createx402DelegationProvider to @metamask/smart-accounts-kit/experimental#248
Conversation
- if no facilitatorAddresses are specified, at least one redeemer caveat must be either in the parentPermissionContext or specified caveats - if facilitatorAddresses are specified, only add a redeemer caveat if the redeemers are not already constrained to the facilitator addresses
- only if there isn't an existing caveat constraining the payee - also minor refactor to put various x402 utilities into x402DelegationProviderUtils.ts
- also refactor types into x402DelegationProviderTypes.ts to simplify internal type dependencies
4611795 to
22f61b9
Compare
- also add parseEip155ChainId function
resolve using getMetaMaskSmartAccountEnvironment if not specified
createDelegationProvider to @metamask/smart-accounts-kit/experimentalcreatex402DelegationProvider to @metamask/smart-accounts-kit/experimental
| throw new Error('Unsupported chain namespace'); | ||
| } | ||
|
|
||
| return parseInt(reference, 10); |
There was a problem hiding this comment.
parseInt can return NaN for non-numeric references (e.g. "eip155:testnet"). consider adding a Number.isFinite check and throwing if invalid.
There was a problem hiding this comment.
good call.
I've changed this to use Number(reference) and added an isNaN check.
| existingDelegations, | ||
| expirySeconds, | ||
| }: EnsureExpirySufficientlyConstrainedParams): Caveat[] => { | ||
| const beforeThreshold = Math.floor(Date.now() / 1000) + expirySeconds; |
There was a problem hiding this comment.
Should we add validation here to enforce expirySeconds > 0? Even though it’s caller-provided config and 0/negative values are unlikely in practice, it might still be safer to guard against them.
| }: EnsurePayeeSufficientlyConstrainedParams): Caveat[] => { | ||
| const allowedCalldataTerms = createAllowedCalldataTerms({ | ||
| startIndex: TRANSFER_PAYEE_INDEX, | ||
| value: payee, |
There was a problem hiding this comment.
I think the payee here is a 20 byte address. ThecreateAllowedCalldataTerms does not ABI-pad the value, so for transfer(address,uint256) we either need to match the 20-byte address at offset 16, or pass a padded address slot at offset 4.
There was a problem hiding this comment.
oof yeah, good catch!
…traint is required, and which addresses should be constrained
- pad payee address to 32 bytes for allowedCalldataTerms - require expiry to be positive number - reject invalid chainId in network string
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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 ce66c3e. Configure here.

📝 Description
Adds
createx402DelegationProviderand related utils and types to@metamask/smart-accounts-kit/experimental.The resulting
DelegationProvidercan be used with thex402Erc7710Client.Examples
Minimal provider (quick start)
Use this when you just want the specified account to create a root delegation to cover the
PaymentRequirements.Re-delegate from a static
permissionContextUse this when you already have a parent delegation and want to redelegate it.
Add a short expiration
Use this for safer, short-lived delegations (for example, 60 seconds).
Or use a dynamic expiration, specifying a shorter expiration for larger amounts.
Dynamic caveats per payment requirements
Use this when caveats should depend on
network,asset,amount, etc.5) Use a dynamic parent
permissionContextUse this when parent delegations are stored by chain/user/merchant and loaded at runtime.
6) Deterministic
fromandsaltfor reproducibilityUse this when you want stable delegation derivation, or if delegating from an account other than the specified
account(i.e., aMultiSigaccount whereaccountis an authorized signer).🚀 Why?
The
x402Erc7710Clientmust be instantiated with aDelegationProvider. Presently the caller must implement the logic for creating theDelegationPayload.With this new
x402DelegationProvider, the caller can model most use cases without having to implement complex delegation creation and signing. The intention is to cover the vast majority of use cases, while also allowing the caller to implement theDelegationProviderthemselves if needed.List any breaking changes:
📋 Checklist
Check off completed items:
🔗 Related Issues
Link to related issues:
Closes #
Related to #
📚 Additional Notes
Any additional information, concerns, or context:
Note
Medium Risk
New delegation creation and signing paths with automatic caveat enforcement affect payment authorization scope; logic is security-sensitive but isolated to experimental exports and covered by extensive tests.
Overview
Adds an experimental
createx402DelegationProviderunder@metamask/smart-accounts-kit/experimentalsox402Erc7710Clientcallers can supply a ready-made delegation provider instead of building signed delegation payloads themselves.For each x402
PaymentRequirementschallenge, the provider resolves static or deferred config (account, environment, caveats, parentpermissionContext,from/salt, redeemer rules, optionalexpirySeconds), builds an open delegation scoped to the payment (ERC-20 transfer amount, payee, network), auto-appends redeemer, payee (AllowedCalldataEnforcer), and optional timestamp caveats when existing caveats or parent delegations are not strict enough, signs viasignTypedData, and returnsdelegationManager, encodedpermissionContext, anddelegator.Also exports
generateSaltfrom@metamask/smart-accounts-kit/utils(32-bytecrypto.getRandomValues), adds@metamask/utilsfor CAIPeip155chain parsing (parseEip155ChainId), and documents both in the changelog. Broad unit tests cover the provider and caveat/context helpers.Reviewed by Cursor Bugbot for commit ce66c3e. Bugbot is set up for automated code reviews on this repo. Configure here.