Skip to content

fix: createx402DelegationProvider should resolve redeemer addresses as interesection of facilitatorAddresses and redeemer.addresses#256

Merged
jeffsmale90 merged 7 commits into
mainfrom
fix/redeemer_addresses
Jun 2, 2026
Merged

fix: createx402DelegationProvider should resolve redeemer addresses as interesection of facilitatorAddresses and redeemer.addresses#256
jeffsmale90 merged 7 commits into
mainfrom
fix/redeemer_addresses

Conversation

@jeffsmale90

@jeffsmale90 jeffsmale90 commented May 28, 2026

Copy link
Copy Markdown
Collaborator

📝 Description

Fixes #254

When createx402DelegationProvider, a redeemer caveat is added that contains the union of facilitatorAddresses and redeemer addresses specified in the params.

🔄 What Changed?

With this change, the intersection of facilitatorAddresses and redeemer addresses is used instead. If only one of the two is specified, that value is used.

Note: if both the facilitator specifies facilitatorAddresses and the configuration specifies redeemer.addresses, they should be the same value (as the intersection will be used as the redeemer caveat terms.

🚀 Why?

If a caller specifies redeemer addresses, it would be reasonable to expect that only those addresses can redeem the delegation, whereas if the facilitator specifies facilitatorAddresses, the addresses that can redeem could be expanded to include other addresses.

🧪 How to Test?

Given the following snippet:

const delegationProvider = createx402DelegationProvider({
  account,
  parentPermissionContext: () => '0x...',
  redeemers: {
    requireRedeemers: true,
    addresses: ['0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', '0xb4827a2a066cd2ef88560efdf063dd05c6c41cc7']
  },
  expirySeconds: 15
});

And a facilitator that specifies facilitatorAddresses: ['0xb4827a2a066cd2ef88560efdf063dd05c6c41cc7']

Previously:

  {
    type: 'redeemer',
    redeemers: [
      '0xb4827a2a066cd2ef88560efdf063dd05c6c41cc7',
      '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'
    ]
  },

Now:

  {
    type: 'redeemer',
    redeemers: [ '0xb4827a2a066cd2ef88560efdf063dd05c6c41cc7' ]
  },

⚠️ 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
Breaking change to who can redeem x402 delegations when both facilitator and config redeemer lists are supplied; incorrect overlap assumptions could block redemption or widen trust if callers relied on the old union.

Overview
Experimental createx402DelegationProvider now builds redeemer caveats from the intersection of PaymentRequirements.extra.facilitatorAddresses and configured redeemers.addresses, instead of their union. When only one side is set, that list is used; when both are set, only overlapping addresses are allowed.

ensureRedeemerSufficientlyConstrained takes separate facilitatorAddresses and redeemerAddresses and uses new resolveRedeemerAddresses (normalized comparison). An empty resolved list (e.g. explicit [] or non-overlapping inputs) throws No valid redeemer addresses were resolved rather than skipping constraints. Changelog and unit tests were updated for intersection behavior and the new error path.

Breaking: delegations that previously allowed any address in either list will only allow addresses present in both when both inputs are provided.

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

…section of specified redeemer addresses, and facilitatorAddresses

- if only one of the two is specified, that value is used
@jeffsmale90 jeffsmale90 marked this pull request as ready for review May 28, 2026 04:43
@jeffsmale90 jeffsmale90 requested a review from a team as a code owner May 28, 2026 04:43

if (redeemerAddresses.length === 0) {
if (!redeemerAddresses || redeemerAddresses.length === 0) {
if (!requireRedeemers) {

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.

Could you clarify what this means exactly?

From my understanding, setting requireRedeemers: false just lets us omit the redeemer caveat when no redeemer source is given. If both facilitatorAddresses and redeemerAddresses are specified but have no overlapping addresses, should the process fail, or create a delegation with no redeemer restrictions on purpose?

I’m checking this because the current code handles an empty intersection the same as when no redeemer sources exist.

@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.

Just some questions

};

/**
* Resolves the allowed redeemer addresses from the union of facilitator specified and caller specified redeemer addresses.

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 think it's intersection, not union

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.

it sure is!

facilitatorAddresses,
redeemerAddresses,
}: ResolveRedeemerAddressesParams): Address[] | undefined => {
if (!facilitatorAddresses) {

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.

If a payment server sends extra: { facilitatorAddresses: [] }, the code enters intersection logic, produces [], and throws a confusing error — even though the user's redeemerAddresses alone would have been sufficient.

@jeffsmale90 jeffsmale90 Jun 1, 2026

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.

I think the behaviour is correct. I've refactored slightly, added some comments, and clarified the error message to "No valid redeemer addresses were resolved. If both redeemers.addresses and extra.facilitatorAddresses are provided, they must overlap. If only one is provided, it must include at least one address.".

If either extra.facilitatorAddresses or redeemers.addresses is specified it implies a constraint (if undefined, it implies no constraint). If the value is either [] or the intersection of the two values is [] it implies a constraint that cannot be satisfied, hence the error.

If we treat [] as no constraint, it's error prone - ["0xaddress1","0xaddress2"] means either address can redeem, ["oxaddress1"] means only that address can redeem, [] means anyone can

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.

@throws only describes the old scenario, misses the new empty-intersection throw

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.

fixed

@jeffsmale90 jeffsmale90 force-pushed the fix/redeemer_addresses branch from 675f4f8 to 9c3a2a0 Compare June 1, 2026 23:22

@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 9c3a2a0. Configure here.

Comment thread packages/smart-accounts-kit/src/experimental/x402DelegationProviderUtils.ts Outdated
@jeffsmale90 jeffsmale90 requested a review from mj-kiwi June 1, 2026 23:36

@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.

LGTM

@jeffsmale90 jeffsmale90 merged commit 461140a into main Jun 2, 2026
18 checks passed
@jeffsmale90 jeffsmale90 deleted the fix/redeemer_addresses branch June 2, 2026 03:39
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.

Experimental x402 redeemers.addresses are concatenated to facilitatorAddresses published by facilitator

2 participants