Skip to content

Commit 337d8e4

Browse files
committed
Refine redelegatePermissionContext function
1 parent 884d4a6 commit 337d8e4

2 files changed

Lines changed: 39 additions & 81 deletions

File tree

packages/smart-accounts-kit/src/actions/redelegatePermissionContext.ts

Lines changed: 29 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import {
1818
createOpenDelegation,
1919
decodeDelegations,
2020
encodeDelegations,
21-
type CreateDelegationOptions,
22-
type CreateOpenDelegationOptions,
2321
} from '../delegation';
2422
import type {
2523
Delegation,
@@ -33,10 +31,8 @@ export type RedelegatePermissionContextParameters = {
3331
account?: Account | Address;
3432
/** Environment configuration */
3533
environment: SmartAccountsEnvironment;
36-
/** The permission context to redelegate from (from ERC-7715 response) */
34+
/** The permission context to redelegate from (i.e., from ERC-7715 response) */
3735
permissionContext: PermissionContext;
38-
/** The address of the delegation manager contract */
39-
delegationManager: Address;
4036
/** The chain ID for the signature */
4137
chainId: number;
4238
/** Optional scope - if not provided, inherits from parent */
@@ -45,16 +41,9 @@ export type RedelegatePermissionContextParameters = {
4541
caveats?: Caveats;
4642
/** Optional salt for uniqueness */
4743
salt?: Hex;
48-
/** Name of the DelegationManager contract */
49-
name?: string;
50-
/** Version of the DelegationManager contract */
51-
version?: string;
52-
/** Whether to allow insecure unrestricted delegation */
53-
allowInsecureUnrestrictedDelegation?: boolean;
54-
} & (
55-
| { delegate: Address } // Specific delegate
56-
| { delegate?: never } // Open delegation
57-
);
44+
/** The address of the delegate to redelegate to */
45+
to?: Address;
46+
};
5847

5948
export type RedelegatePermissionContextReturnType = {
6049
/** The signed delegation that was created */
@@ -127,14 +116,11 @@ export async function redelegatePermissionContext<
127116
account: accountParam = client.account,
128117
environment,
129118
permissionContext,
130-
delegationManager,
131119
chainId,
132120
scope,
133121
caveats,
134122
salt,
135-
name = 'DelegationManager',
136-
version = '1',
137-
allowInsecureUnrestrictedDelegation = false,
123+
to,
138124
} = parameters;
139125

140126
if (!accountParam) {
@@ -145,72 +131,57 @@ export async function redelegatePermissionContext<
145131

146132
trackSmartAccountsKitFunctionCall('redelegatePermissionContext', {
147133
chainId,
148-
hasDelegate: 'delegate' in parameters && parameters.delegate !== undefined,
134+
hasDelegate: Boolean(parameters.to),
149135
hasScope: scope !== undefined,
150136
hasCaveats: caveats !== undefined,
151137
});
152138

153-
// Decode the permission context to get the delegation chain
154139
const delegations = decodeDelegations(permissionContext);
155140

156-
if (delegations.length === 0) {
141+
const parentDelegation = delegations[0];
142+
143+
if (!parentDelegation) {
157144
throw new BaseError(
158145
'Permission context must contain at least one delegation',
159146
);
160147
}
161148

162-
// The leaf delegation is the first element (chain ordered leaf to root)
163-
const leafDelegation = delegations[0];
164-
165-
// Create the unsigned delegation
166-
// We always pass parentDelegation as the leaf delegation
167-
// TypeScript struggles with the discriminated union, so we build the object explicitly
168-
let unsignedDelegation: Omit<Delegation, 'signature'>;
169-
170-
const commonOptions = {
149+
const createDelegationOptions = {
171150
environment,
172151
from: account.address,
173-
parentDelegation: leafDelegation as Delegation | Hex,
174-
...(scope !== undefined && { scope }),
175-
...(caveats !== undefined && { caveats }),
176-
...(salt !== undefined && { salt }),
152+
scope,
153+
caveats,
154+
parentDelegation,
155+
salt,
177156
};
178157

179-
if ('delegate' in parameters && parameters.delegate) {
180-
unsignedDelegation = createDelegation({
181-
...commonOptions,
182-
to: parameters.delegate,
183-
} as CreateDelegationOptions);
184-
} else {
185-
unsignedDelegation = createOpenDelegation(
186-
commonOptions as CreateOpenDelegationOptions,
187-
);
188-
}
158+
const unsignedDelegation = to
159+
? createDelegation({
160+
...createDelegationOptions,
161+
to,
162+
})
163+
: createOpenDelegation(createDelegationOptions);
189164

190-
// Sign the delegation
191165
const signature = await signDelegation(client, {
192-
account: accountParam,
166+
account,
193167
delegation: unsignedDelegation,
194-
delegationManager,
168+
delegationManager: environment.DelegationManager,
195169
chainId,
196-
name,
197-
version,
198-
allowInsecureUnrestrictedDelegation,
199170
});
200171

201-
// Create the signed delegation
202172
const signedDelegation: Delegation = {
203173
...unsignedDelegation,
204174
signature,
205175
};
206176

207-
// Prepend the new delegation to create the new chain
208-
const newDelegationChain = [signedDelegation, ...delegations];
177+
const newPermissionContext = encodeDelegations([
178+
signedDelegation,
179+
...delegations,
180+
]);
209181

210-
// Return both the delegation and the encoded permission context
211182
return {
212183
delegation: signedDelegation,
213-
permissionContext: encodeDelegations(newDelegationChain),
184+
permissionContext: newPermissionContext,
214185
};
215186
}
216187

@@ -227,10 +198,9 @@ export async function redelegatePermissionContext<
227198
*
228199
* // Now you can call it directly on the client
229200
* const result = await walletClient.redelegatePermissionContext({
230-
* permissionContext: erc7715Response.context,
231-
* delegate: charlie.address,
232201
* environment,
233-
* delegationManager: environment.DelegationManager,
202+
* permissionContext: erc7715Response.context,
203+
* to: charlie.address,
234204
* });
235205
* ```
236206
*/

packages/smart-accounts-kit/test/actions/redelegatePermissionContext.test.ts

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ const mockEnvironment: SmartAccountsEnvironment = {
3232
},
3333
};
3434

35-
const mockDelegationManager: Address =
36-
'0x1234567890123456789012345678901234567890';
3735
const mockChainId = sepolia.id;
3836

3937
describe('redelegatePermissionContext', () => {
@@ -72,9 +70,8 @@ describe('redelegatePermissionContext', () => {
7270
const result = await redelegatePermissionContext(client, {
7371
environment: mockEnvironment,
7472
permissionContext,
75-
delegationManager: mockDelegationManager,
7673
chainId: mockChainId,
77-
delegate: newDelegate,
74+
to: newDelegate,
7875
caveats: [timestampCaveat],
7976
});
8077

@@ -113,9 +110,8 @@ describe('redelegatePermissionContext', () => {
113110
const result = await redelegatePermissionContext(client, {
114111
environment: mockEnvironment,
115112
permissionContext,
116-
delegationManager: mockDelegationManager,
117113
chainId: mockChainId,
118-
// No delegate specified
114+
// No `to` specified - creates an open delegation
119115
caveats: [timestampCaveat],
120116
});
121117

@@ -151,9 +147,8 @@ describe('redelegatePermissionContext', () => {
151147
const result = await redelegatePermissionContext(client, {
152148
environment: mockEnvironment,
153149
permissionContext,
154-
delegationManager: mockDelegationManager,
155150
chainId: mockChainId,
156-
delegate: newDelegate,
151+
to: newDelegate,
157152
caveats: [timestampCaveat],
158153
});
159154

@@ -185,9 +180,8 @@ describe('redelegatePermissionContext', () => {
185180
const result = await redelegatePermissionContext(client, {
186181
environment: mockEnvironment,
187182
permissionContext,
188-
delegationManager: mockDelegationManager,
189183
chainId: mockChainId,
190-
delegate: newDelegate,
184+
to: newDelegate,
191185
// No scope provided - should inherit from parent
192186
caveats: [timestampCaveat], // Add a caveat so signature doesn't fail
193187
});
@@ -215,9 +209,8 @@ describe('redelegatePermissionContext', () => {
215209
const result = await redelegatePermissionContext(client, {
216210
environment: mockEnvironment,
217211
permissionContext,
218-
delegationManager: mockDelegationManager,
219212
chainId: mockChainId,
220-
delegate: newDelegate,
213+
to: newDelegate,
221214
scope: {
222215
type: ScopeType.NativeTokenTransferAmount,
223216
maxAmount: 500n,
@@ -236,9 +229,8 @@ describe('redelegatePermissionContext', () => {
236229
redelegatePermissionContext(client, {
237230
environment: mockEnvironment,
238231
permissionContext: emptyContext,
239-
delegationManager: mockDelegationManager,
240232
chainId: mockChainId,
241-
delegate: '0x2000000000000000000000000000000000000002',
233+
to: '0x2000000000000000000000000000000000000002',
242234
}),
243235
).rejects.toThrow(
244236
'Permission context must contain at least one delegation',
@@ -268,9 +260,8 @@ describe('redelegatePermissionContext', () => {
268260
redelegatePermissionContext(clientWithoutAccount, {
269261
environment: mockEnvironment,
270262
permissionContext,
271-
delegationManager: mockDelegationManager,
272263
chainId: mockChainId,
273-
delegate: '0x2000000000000000000000000000000000000002',
264+
to: '0x2000000000000000000000000000000000000002',
274265
}),
275266
).rejects.toThrow('Account not found');
276267
});
@@ -306,9 +297,8 @@ describe('redelegatePermissionContext', () => {
306297
account,
307298
environment: mockEnvironment,
308299
permissionContext,
309-
delegationManager: mockDelegationManager,
310300
chainId: mockChainId,
311-
delegate: newDelegate,
301+
to: newDelegate,
312302
caveats: [timestampCaveat],
313303
});
314304

@@ -349,8 +339,7 @@ describe('redelegatePermissionContextActions', () => {
349339
const result = await client.redelegatePermissionContext({
350340
environment: mockEnvironment,
351341
permissionContext,
352-
delegationManager: mockDelegationManager,
353-
delegate: newDelegate,
342+
to: newDelegate,
354343
caveats: [timestampCaveat],
355344
// chainId should be inferred from client
356345
});
@@ -382,8 +371,7 @@ describe('redelegatePermissionContextActions', () => {
382371
clientWithoutChain.redelegatePermissionContext({
383372
environment: mockEnvironment,
384373
permissionContext,
385-
delegationManager: mockDelegationManager,
386-
delegate: '0x2000000000000000000000000000000000000002',
374+
to: '0x2000000000000000000000000000000000000002',
387375
}),
388376
).rejects.toThrow('Chain ID is required');
389377
});

0 commit comments

Comments
 (0)