Skip to content

Commit ba5345d

Browse files
committed
Allow insecure unrestricted delegation when signing a redelegation
1 parent 157251b commit ba5345d

2 files changed

Lines changed: 48 additions & 0 deletions

File tree

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ async function signAndPrependRedelegation(
9898
delegation: unsignedDelegation,
9999
delegationManager: environment.DelegationManager,
100100
chainId,
101+
// Redelegations always inherit from a parent delegation (enforced by
102+
// `resolveRedelegationInputs`), so the parent's caveats provide the
103+
// restriction even when the redelegation itself adds no extra caveats.
104+
// This mirrors `resolveCaveats`, which also allows empty caveats in this
105+
// case.
106+
allowInsecureUnrestrictedDelegation: true,
101107
});
102108

103109
const signedDelegation: Delegation = {

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,29 @@ describe('redelegatePermissionContext', () => {
125125
expect(result.delegation.caveats).to.deep.include(timestampCaveat);
126126
});
127127

128+
it('should sign successfully when inheriting from parent without scope or caveats', async () => {
129+
const permissionContext = buildRootPermissionContext();
130+
const newDelegate: Address = '0x2000000000000000000000000000000000000002';
131+
132+
const result = await redelegatePermissionContext(client, {
133+
environment: mockEnvironment,
134+
permissionContext,
135+
chainId: mockChainId,
136+
to: newDelegate,
137+
// No scope and no caveats - should inherit entirely from parent
138+
// and still produce a valid signature.
139+
});
140+
141+
expect(result.delegation.delegate).to.equal(newDelegate);
142+
expect(result.delegation.delegator).to.equal(account.address);
143+
expect(result.delegation.caveats).to.deep.equal([]);
144+
expect(result.delegation.signature).to.match(/^0x[a-fA-F0-9]+$/u);
145+
expect(result.permissionContext).to.match(/^0x[a-fA-F0-9]+$/u);
146+
expect(result.permissionContext.length).to.be.greaterThan(
147+
permissionContext.length,
148+
);
149+
});
150+
128151
it('should allow scope override even with parent', async () => {
129152
const permissionContext = buildRootPermissionContext();
130153
const newDelegate: Address = '0x2000000000000000000000000000000000000002';
@@ -256,6 +279,25 @@ describe('redelegatePermissionContextOpen', () => {
256279
expect(result.delegation.caveats).to.deep.include(timestampCaveat);
257280
});
258281

282+
it('should sign successfully when inheriting from parent without scope or caveats', async () => {
283+
const permissionContext = buildRootPermissionContext();
284+
285+
const result = await redelegatePermissionContextOpen(client, {
286+
environment: mockEnvironment,
287+
permissionContext,
288+
chainId: mockChainId,
289+
// No scope and no caveats - should inherit entirely from parent
290+
// and still produce a valid signature.
291+
});
292+
293+
expect(result.delegation.delegate).to.equal(
294+
'0x0000000000000000000000000000000000000a11', // ANY_BENEFICIARY
295+
);
296+
expect(result.delegation.delegator).to.equal(account.address);
297+
expect(result.delegation.caveats).to.deep.equal([]);
298+
expect(result.delegation.signature).to.match(/^0x[a-fA-F0-9]+$/u);
299+
});
300+
259301
it('should allow scope override on an open redelegation', async () => {
260302
const permissionContext = buildRootPermissionContext();
261303

0 commit comments

Comments
 (0)