Skip to content

Commit 37e110f

Browse files
committed
x402 Payload now returns the root delegator, instead of the leaf delegator
1 parent 327672d commit 37e110f

4 files changed

Lines changed: 48 additions & 6 deletions

File tree

packages/smart-accounts-kit/src/experimental/x402DelegationProvider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ export function createx402DelegationProvider(
4242
): Promise<x402DelegationProviderPaymentPayload> => {
4343
const {
4444
account,
45+
createDelegationConfig,
4546
delegationManager,
4647
existingDelegations,
47-
createDelegationConfig,
48+
rootDelegator,
4849
} = await resolveDelegationCreationContext(config, requirements);
4950

5051
const delegation = createOpenDelegation(createDelegationConfig);
@@ -76,7 +77,7 @@ export function createx402DelegationProvider(
7677
return {
7778
delegationManager,
7879
permissionContext,
79-
delegator: delegation.delegator,
80+
delegator: rootDelegator,
8081
};
8182
};
8283
}

packages/smart-accounts-kit/src/experimental/x402DelegationProviderUtils.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ type EnsureExpirySufficientlyConstrainedParams = {
6363
*/
6464
export type DelegationCreationContext = {
6565
account: Account;
66+
createDelegationConfig: Parameters<typeof createOpenDelegation>[0];
6667
delegationManager: Address;
6768
existingDelegations: Delegation[];
68-
createDelegationConfig: Parameters<typeof createOpenDelegation>[0];
69+
rootDelegator: Address;
6970
};
7071

7172
/**
@@ -552,10 +553,18 @@ export const resolveDelegationCreationContext = async (
552553
};
553554
}
554555

556+
const rootDelegator =
557+
existingDelegations[existingDelegations.length - 1]?.delegator;
558+
559+
if (!rootDelegator) {
560+
throw new Error('Root delegator not found');
561+
}
562+
555563
return {
556564
account,
565+
createDelegationConfig,
557566
delegationManager,
558567
existingDelegations,
559-
createDelegationConfig,
568+
rootDelegator,
560569
};
561570
};

packages/smart-accounts-kit/test/experimental/x402DelegationProvider.test.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ const mockPayeeEnforcer = '0x2000000000000000000000000000000000000004' as Hex;
4848
const mockTimestampEnforcer =
4949
'0x2000000000000000000000000000000000000005' as Hex;
5050
const mockDelegator = '0x3000000000000000000000000000000000000003' as Hex;
51+
const mockRootDelegator = '0x3100000000000000000000000000000000000003' as Hex;
5152
const mockSignature = '0xabc123' as Hex;
5253
const mockTypedData = { domain: {}, message: {} };
5354
const mockPermissionContext = '0xfeed' as Hex;
55+
const mockParentPermissionContext = '0xbeef' as Hex;
5456
const mockAllowedCalldataTerms = '0x3333' as Hex;
5557
const mockGeneratedSalt =
5658
'0x1111111111111111111111111111111111111111111111111111111111111111' as Hex;
@@ -141,7 +143,16 @@ describe('createx402DelegationProvider', () => {
141143
mockTypedData,
142144
);
143145
delegationMocks.encodeDelegations.mockReturnValue(mockPermissionContext);
144-
delegationMocks.decodeDelegations.mockReturnValue([]);
146+
delegationMocks.decodeDelegations.mockReturnValue([
147+
{
148+
delegate: '0xb00000000000000000000000000000000000000b',
149+
delegator: mockRootDelegator,
150+
authority: mockAuthority,
151+
caveats: [],
152+
salt: '0x44',
153+
signature: '0x55',
154+
},
155+
]);
145156
});
146157

147158
it('creates and signs a delegation using default from/salt values', async () => {
@@ -151,6 +162,7 @@ describe('createx402DelegationProvider', () => {
151162
account,
152163
environment,
153164
caveats: [],
165+
parentPermissionContext: mockParentPermissionContext,
154166
});
155167

156168
const result = await provider(mockRequirements);
@@ -182,16 +194,19 @@ describe('createx402DelegationProvider', () => {
182194
},
183195
);
184196
expect(account.signTypedData).toHaveBeenCalledWith(mockTypedData);
197+
const decodedDelegations =
198+
delegationMocks.decodeDelegations.mock.results[0]?.value ?? [];
185199
expect(delegationMocks.encodeDelegations).toHaveBeenCalledWith([
186200
{
187201
...delegationMocks.createOpenDelegation.mock.results[0]?.value,
188202
signature: mockSignature,
189203
},
204+
...decodedDelegations,
190205
]);
191206
expect(result).toStrictEqual({
192207
delegationManager: mockDelegationManager,
193208
permissionContext: mockPermissionContext,
194-
delegator: mockDelegator,
209+
delegator: mockRootDelegator,
195210
});
196211
});
197212

@@ -202,6 +217,7 @@ describe('createx402DelegationProvider', () => {
202217
account,
203218
environment,
204219
caveats: [],
220+
parentPermissionContext: mockParentPermissionContext,
205221
});
206222

207223
await provider({
@@ -223,6 +239,7 @@ describe('createx402DelegationProvider', () => {
223239
account,
224240
environment,
225241
caveats: [],
242+
parentPermissionContext: mockParentPermissionContext,
226243
});
227244

228245
await expect(
@@ -240,6 +257,7 @@ describe('createx402DelegationProvider', () => {
240257
const provider = createx402DelegationProvider({
241258
account,
242259
environment: createMockEnvironment(),
260+
parentPermissionContext: mockParentPermissionContext,
243261
} as x402DelegationProviderConfig);
244262

245263
await expect(provider(mockRequirements)).rejects.toThrow(

packages/smart-accounts-kit/test/experimental/x402DelegationProviderUtils.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,15 @@ describe('x402DelegationProviderUtils', () => {
481481
const getEnvironmentSpy = vi
482482
.spyOn(smartAccountsEnvironmentModule, 'getSmartAccountsEnvironment')
483483
.mockReturnValue(baseEnvironment);
484+
const parentDelegation = makeDelegation([]);
484485

485486
try {
486487
const result = await resolveDelegationCreationContext(
487488
{
488489
account: mockAccount,
489490
caveats: [],
490491
salt: `0x${'77'.repeat(32)}`,
492+
parentPermissionContext: [parentDelegation],
491493
},
492494
{
493495
scheme: 'exact',
@@ -515,6 +517,7 @@ describe('x402DelegationProviderUtils', () => {
515517
});
516518

517519
it('resolves deferred account, environment, from, and salt', async () => {
520+
const parentDelegation = makeDelegation([]);
518521
const deferredAccount = vi.fn(async () => mockAccount);
519522
const deferredEnvironment = vi.fn(async () => baseEnvironment);
520523
const deferredFrom = vi.fn(
@@ -531,6 +534,7 @@ describe('x402DelegationProviderUtils', () => {
531534
from: deferredFrom,
532535
salt: deferredSalt,
533536
caveats: [],
537+
parentPermissionContext: [parentDelegation],
534538
},
535539
{
536540
scheme: 'exact',
@@ -652,12 +656,14 @@ describe('x402DelegationProviderUtils', () => {
652656
});
653657

654658
it('does not throw when facilitators are missing and redeemers are optional', async () => {
659+
const parentDelegation = makeDelegation([]);
655660
await expect(
656661
resolveDelegationCreationContext(
657662
{
658663
account: mockAccount,
659664
environment: baseEnvironment,
660665
salt: `0x${'33'.repeat(32)}`,
666+
parentPermissionContext: [parentDelegation],
661667
},
662668
{
663669
scheme: 'exact',
@@ -697,11 +703,13 @@ describe('x402DelegationProviderUtils', () => {
697703
});
698704

699705
it('adds redeemer caveat from redeemers config addresses when facilitators are missing', async () => {
706+
const parentDelegation = makeDelegation([]);
700707
const result = await resolveDelegationCreationContext(
701708
{
702709
account: mockAccount,
703710
environment: baseEnvironment,
704711
salt: `0x${'33'.repeat(32)}`,
712+
parentPermissionContext: [parentDelegation],
705713
redeemers: {
706714
requireRedeemers: true,
707715
addresses: [facilitatorB],
@@ -732,6 +740,7 @@ describe('x402DelegationProviderUtils', () => {
732740
});
733741

734742
it('resolves deferred redeemers configuration and addresses', async () => {
743+
const parentDelegation = makeDelegation([]);
735744
const deferredRedeemerAddresses = vi.fn(async () => [facilitatorB]);
736745
const deferredRedeemersConfig = vi.fn(async () => ({
737746
requireRedeemers: true,
@@ -743,6 +752,7 @@ describe('x402DelegationProviderUtils', () => {
743752
account: mockAccount,
744753
environment: baseEnvironment,
745754
salt: `0x${'33'.repeat(32)}`,
755+
parentPermissionContext: [parentDelegation],
746756
redeemers: deferredRedeemersConfig,
747757
},
748758
{
@@ -775,6 +785,7 @@ describe('x402DelegationProviderUtils', () => {
775785
it('resolves deferred expirySeconds and applies timestamp caveat', async () => {
776786
vi.useFakeTimers();
777787
vi.setSystemTime(new Date('2024-01-01T00:00:00Z'));
788+
const parentDelegation = makeDelegation([]);
778789

779790
const deferredExpirySeconds = vi.fn(async () => 120);
780791
const result = await resolveDelegationCreationContext(
@@ -784,6 +795,7 @@ describe('x402DelegationProviderUtils', () => {
784795
caveats: [],
785796
salt: `0x${'66'.repeat(32)}`,
786797
expirySeconds: deferredExpirySeconds,
798+
parentPermissionContext: [parentDelegation],
787799
},
788800
{
789801
scheme: 'exact',
@@ -816,6 +828,7 @@ describe('x402DelegationProviderUtils', () => {
816828
it('resolves synchronous deferred expirySeconds and applies timestamp caveat', async () => {
817829
vi.useFakeTimers();
818830
vi.setSystemTime(new Date('2024-01-01T00:00:00Z'));
831+
const parentDelegation = makeDelegation([]);
819832

820833
const deferredExpirySeconds = vi.fn(() => 90);
821834
const result = await resolveDelegationCreationContext(
@@ -825,6 +838,7 @@ describe('x402DelegationProviderUtils', () => {
825838
caveats: [],
826839
salt: `0x${'66'.repeat(32)}`,
827840
expirySeconds: deferredExpirySeconds,
841+
parentPermissionContext: [parentDelegation],
828842
},
829843
{
830844
scheme: 'exact',

0 commit comments

Comments
 (0)