Skip to content

Commit 6ec4bf3

Browse files
committed
WIP: feat: add an EIP-7702 impl of single owner LA
1 parent 87bf632 commit 6ec4bf3

5 files changed

Lines changed: 103 additions & 20 deletions

File tree

packages/smart-accounts/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ export {
3939
lightAccountStaticImplV1_0_2,
4040
lightAccountStaticImplV1_1_0,
4141
lightAccountStaticImplV2_0_0,
42+
lightAccountStaticImplV2_1_0,
43+
lightAccountStaticImplV2_2_0,
44+
lightAccountStaticImpl7702V2_1_0,
4245
multiOwnerLightAccountStaticImplV2_0_0,
4346
} from "./light-account/lightAccountStaticImpl.js";
47+
export type { LightAccountStaticImpl7702V2_1_0 } from "./light-account/lightAccountStaticImpl.js";
4448

4549
// ModularAccountV1
4650
export type * from "./ma-v1/accounts/base.js";

packages/smart-accounts/src/light-account/accounts/account.ts

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import {
66
type Hex,
77
type JsonRpcAccount,
88
type LocalAccount,
9+
type PrivateKeyAccount,
910
type Transport,
1011
} from "viem";
1112
import { readContract } from "viem/actions";
13+
import type { ToSmartAccountParameters } from "viem/account-abstraction";
1214
import { LightAccountAbi_v1 } from "../abis/LightAccountAbi_v1.js";
1315
import { LightAccountAbi_v2 } from "../abis/LightAccountAbi_v2.js";
1416
import { LightAccountFactoryAbi_v1 } from "../abis/LightAccountFactoryAbi_v1.js";
@@ -27,6 +29,10 @@ import { toLightAccountBase, type LightAccountBase } from "./base.js";
2729
import { BaseError, lowerAddress } from "@alchemy/common";
2830
import { getAction } from "viem/utils";
2931
import { LOGGER } from "../../logger.js";
32+
import { InvalidOwnerError } from "../../errors/InvalidOwnerError.js";
33+
import { lightAccountStaticImpl7702V2_1_0 } from "../lightAccountStaticImpl.js";
34+
35+
type LightAccountMode = "default" | "7702";
3036

3137
export type LightAccount<
3238
TLightAccountVersion extends
@@ -39,15 +45,24 @@ export type LightAccount<
3945
export type ToLightAccountParams<
4046
TLightAccountVersion extends
4147
LightAccountVersion<"LightAccount"> = LightAccountVersion<"LightAccount">,
48+
TMode extends LightAccountMode | undefined = LightAccountMode | undefined,
4249
> = {
4350
client: Client<Transport, Chain, JsonRpcAccount | LocalAccount | undefined>;
4451
owner: JsonRpcAccount | LocalAccount;
45-
salt?: bigint;
4652
accountAddress?: Address;
47-
factory?: Address;
48-
factoryData?: Hex;
4953
version?: TLightAccountVersion;
50-
};
54+
mode?: TMode;
55+
} & (TMode extends "7702"
56+
? {
57+
salt?: never;
58+
factory?: never;
59+
factoryData?: never;
60+
}
61+
: {
62+
salt?: bigint;
63+
factory?: Address;
64+
factoryData?: Hex;
65+
});
5166

5267
/**
5368
* Creates a light account.
@@ -58,6 +73,7 @@ export type ToLightAccountParams<
5873
export async function toLightAccount<
5974
TLightAccountVersion extends
6075
LightAccountVersion<"LightAccount"> = LightAccountVersion<"LightAccount">,
76+
TMode extends LightAccountMode = LightAccountMode,
6177
>({
6278
client,
6379
owner,
@@ -66,11 +82,15 @@ export async function toLightAccount<
6682
version = defaultLightAccountVersion() as TLightAccountVersion,
6783
factory = AccountVersionRegistry.LightAccount[version].factoryAddress,
6884
factoryData: factoryData_,
69-
}: ToLightAccountParams<TLightAccountVersion>): Promise<
85+
mode,
86+
}: ToLightAccountParams<TLightAccountVersion, TMode>): Promise<
7087
LightAccount<TLightAccountVersion>
7188
> {
89+
const is7702 = mode === "7702";
90+
7291
LOGGER.debug("toLightAccount:start", {
7392
version,
93+
mode,
7494
hasAccountAddress: !!accountAddress_,
7595
});
7696

@@ -87,16 +107,26 @@ export async function toLightAccount<
87107

88108
const accountAddress =
89109
accountAddress_ ??
90-
predictLightAccountAddress({
91-
factoryAddress: factory,
92-
salt,
93-
ownerAddress: owner.address,
94-
version,
95-
});
110+
(is7702 && owner.type === "local"
111+
? owner.address
112+
: predictLightAccountAddress({
113+
factoryAddress: factory,
114+
salt,
115+
ownerAddress: owner.address,
116+
version,
117+
}));
96118

97-
LOGGER.debug("toLightAccount:address-resolved", { accountAddress });
119+
LOGGER.debug("toLightAccount:address-resolved", { accountAddress, is7702 });
98120

99121
const getFactoryArgs = async () => {
122+
if (is7702) {
123+
// EIP-7702 uses special factory address for EP 0.8
124+
return {
125+
factory: "0x7702000000000000000000000000000000000000" as Address,
126+
factoryData: "0x" as Hex,
127+
} as const;
128+
}
129+
100130
const factoryData =
101131
factoryData_ ??
102132
encodeFunctionData({
@@ -111,6 +141,29 @@ export async function toLightAccount<
111141
};
112142
};
113143

144+
let authorization: ToSmartAccountParameters["authorization"];
145+
if (is7702) {
146+
LOGGER.debug("toLightAccount:7702-mode");
147+
if (owner.type !== "local") {
148+
LOGGER.error("toLightAccount:invalid-owner-type", {
149+
ownerType: owner.type,
150+
});
151+
throw new InvalidOwnerError(
152+
`Owner of type ${owner.type} is unsupported for 7702 mode.`,
153+
);
154+
}
155+
if (owner.signAuthorization == null) {
156+
LOGGER.error("toLightAccount:missing-signAuthorization");
157+
throw new InvalidOwnerError(
158+
"Owner must implement `signAuthorization` to be used with 7702 mode.",
159+
);
160+
}
161+
authorization = {
162+
account: owner as PrivateKeyAccount,
163+
address: lightAccountStaticImpl7702V2_1_0.delegationAddress,
164+
};
165+
}
166+
114167
const baseAccount = await toLightAccountBase({
115168
client,
116169
owner,
@@ -119,6 +172,7 @@ export async function toLightAccount<
119172
type: "LightAccount",
120173
version,
121174
getFactoryArgs,
175+
authorization,
122176
});
123177

124178
return {

packages/smart-accounts/src/light-account/accounts/base.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
getUserOperationTypedData,
2121
toSmartAccount,
2222
type SmartAccountImplementation,
23+
type ToSmartAccountParameters,
2324
} from "viem/account-abstraction";
2425
import { getStorageAt, signMessage, signTypedData } from "viem/actions";
2526
import type {
@@ -67,7 +68,7 @@ export type BaseLightAccountImplementation<
6768
prepareSignature: (request: SignatureRequest) => Promise<SignatureRequest>;
6869
formatSignature: (signature: Hex) => Promise<Hex>;
6970
},
70-
false
71+
boolean
7172
>;
7273

7374
export type LightAccountBase<
@@ -94,6 +95,7 @@ export type ToLightAccountBaseParams<
9495
factory?: Address | undefined;
9596
factoryData?: Hex | undefined;
9697
}>;
98+
authorization?: ToSmartAccountParameters["authorization"];
9799
};
98100

99101
export async function toLightAccountBase<
@@ -109,6 +111,7 @@ export async function toLightAccountBase<
109111
type,
110112
version,
111113
getFactoryArgs,
114+
authorization,
112115
}: ToLightAccountBaseParams<
113116
TLightAccountType,
114117
TLightAccountVersion,
@@ -232,6 +235,7 @@ export async function toLightAccountBase<
232235
getFactoryArgs,
233236
client,
234237
entryPoint,
238+
authorization,
235239

236240
async getAddress() {
237241
return accountAddress;

packages/smart-accounts/src/light-account/lightAccountStaticImpl.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,15 @@ export const multiOwnerLightAccountStaticImplV2_0_0: StaticSmartAccountImplement
174174
},
175175
};
176176

177+
const lightAccountBaseV2_1_0 = {
178+
entryPoint: {
179+
abi: entryPoint08Abi,
180+
address: entryPoint08Address,
181+
version: "0.8",
182+
},
183+
accountAbi: LightAccountAbi_v2,
184+
} as const;
185+
177186
export const lightAccountStaticImplV2_1_0: StaticSmartAccountImplementation<
178187
false,
179188
"0.8",
@@ -182,12 +191,7 @@ export const lightAccountStaticImplV2_1_0: StaticSmartAccountImplementation<
182191
typeof LightAccountAbi_v2,
183192
typeof LightAccountFactoryAbi_v2
184193
> = {
185-
entryPoint: {
186-
abi: entryPoint08Abi,
187-
address: entryPoint08Address,
188-
version: "0.8",
189-
},
190-
accountAbi: LightAccountAbi_v2,
194+
...lightAccountBaseV2_1_0,
191195
accountImplementation: lowerAddress(
192196
"0x2c53D0bD33A60db8881c7b049Df6fd762A1f059C",
193197
),
@@ -209,6 +213,23 @@ export const lightAccountStaticImplV2_1_0: StaticSmartAccountImplementation<
209213
},
210214
};
211215

216+
export type LightAccountStaticImpl7702V2_1_0 = StaticSmartAccountImplementation<
217+
true,
218+
"0.8",
219+
{},
220+
typeof entryPoint08Abi,
221+
typeof LightAccountAbi_v2,
222+
never
223+
>;
224+
225+
export const lightAccountStaticImpl7702V2_1_0: LightAccountStaticImpl7702V2_1_0 =
226+
{
227+
...lightAccountBaseV2_1_0,
228+
delegationAddress: lowerAddress(
229+
"0x82CfFc0f83A66F016f1273CdD5C43f86E78d2478",
230+
),
231+
};
232+
212233
export const lightAccountStaticImplV2_2_0: StaticSmartAccountImplementation<
213234
false,
214235
"0.9",

0 commit comments

Comments
 (0)