@alchemy/smart-accounts 0.0.0-alpha.9 → 5.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +36 -0
  3. package/dist/esm/index.d.ts +2 -4
  4. package/dist/esm/index.js +2 -4
  5. package/dist/esm/index.js.map +1 -1
  6. package/dist/esm/light-account/accounts/account.d.ts +7 -3
  7. package/dist/esm/light-account/accounts/account.js +20 -10
  8. package/dist/esm/light-account/accounts/account.js.map +1 -1
  9. package/dist/esm/light-account/accounts/base.js +50 -23
  10. package/dist/esm/light-account/accounts/base.js.map +1 -1
  11. package/dist/esm/light-account/accounts/calldataCodec.js +3 -2
  12. package/dist/esm/light-account/accounts/calldataCodec.js.map +1 -1
  13. package/dist/esm/light-account/accounts/multi-owner-account.d.ts +6 -2
  14. package/dist/esm/light-account/accounts/multi-owner-account.js +14 -6
  15. package/dist/esm/light-account/accounts/multi-owner-account.js.map +1 -1
  16. package/dist/esm/light-account/lightAccountStaticImpl.d.ts +3 -1
  17. package/dist/esm/light-account/lightAccountStaticImpl.js +57 -7
  18. package/dist/esm/light-account/lightAccountStaticImpl.js.map +1 -1
  19. package/dist/esm/light-account/predictAddress.d.ts +40 -2
  20. package/dist/esm/light-account/predictAddress.js +83 -3
  21. package/dist/esm/light-account/predictAddress.js.map +1 -1
  22. package/dist/esm/light-account/registry.d.ts +3410 -0
  23. package/dist/esm/light-account/registry.js +33 -1
  24. package/dist/esm/light-account/registry.js.map +1 -1
  25. package/dist/esm/logger.d.ts +1 -1
  26. package/dist/esm/logger.js +1 -1
  27. package/dist/esm/logger.js.map +1 -1
  28. package/dist/esm/ma-v1/accounts/multi-owner-account.d.ts +6 -2
  29. package/dist/esm/ma-v1/accounts/multi-owner-account.js +18 -7
  30. package/dist/esm/ma-v1/accounts/multi-owner-account.js.map +1 -1
  31. package/dist/esm/ma-v1/predictAddress.d.ts +20 -1
  32. package/dist/esm/ma-v1/predictAddress.js +38 -2
  33. package/dist/esm/ma-v1/predictAddress.js.map +1 -1
  34. package/dist/esm/ma-v2/accounts/account.d.ts +8 -5
  35. package/dist/esm/ma-v2/accounts/account.js +23 -42
  36. package/dist/esm/ma-v2/accounts/account.js.map +1 -1
  37. package/dist/esm/ma-v2/accounts/base.d.ts +2 -2
  38. package/dist/esm/ma-v2/accounts/base.js +12 -59
  39. package/dist/esm/ma-v2/accounts/base.js.map +1 -1
  40. package/dist/esm/ma-v2/mav2StaticImpl.d.ts +1 -15
  41. package/dist/esm/ma-v2/mav2StaticImpl.js +0 -33
  42. package/dist/esm/ma-v2/mav2StaticImpl.js.map +1 -1
  43. package/dist/esm/ma-v2/modules/time-range-module/module.js +3 -2
  44. package/dist/esm/ma-v2/modules/time-range-module/module.js.map +1 -1
  45. package/dist/esm/ma-v2/predictAddress.d.ts +22 -6
  46. package/dist/esm/ma-v2/predictAddress.js +46 -12
  47. package/dist/esm/ma-v2/predictAddress.js.map +1 -1
  48. package/dist/esm/ma-v2/utils/account.d.ts +0 -3
  49. package/dist/esm/ma-v2/utils/account.js +0 -3
  50. package/dist/esm/ma-v2/utils/account.js.map +1 -1
  51. package/dist/esm/ma-v2/utils/signature.d.ts +1 -16
  52. package/dist/esm/ma-v2/utils/signature.js +1 -38
  53. package/dist/esm/ma-v2/utils/signature.js.map +1 -1
  54. package/dist/esm/utils.d.ts +24 -11
  55. package/dist/esm/utils.js +67 -21
  56. package/dist/esm/utils.js.map +1 -1
  57. package/dist/esm/version.d.ts +1 -1
  58. package/dist/esm/version.js +1 -1
  59. package/dist/esm/version.js.map +1 -1
  60. package/dist/types/index.d.ts +2 -4
  61. package/dist/types/index.d.ts.map +1 -1
  62. package/dist/types/light-account/accounts/account.d.ts +7 -3
  63. package/dist/types/light-account/accounts/account.d.ts.map +1 -1
  64. package/dist/types/light-account/accounts/base.d.ts.map +1 -1
  65. package/dist/types/light-account/accounts/calldataCodec.d.ts.map +1 -1
  66. package/dist/types/light-account/accounts/multi-owner-account.d.ts +6 -2
  67. package/dist/types/light-account/accounts/multi-owner-account.d.ts.map +1 -1
  68. package/dist/types/light-account/lightAccountStaticImpl.d.ts +3 -1
  69. package/dist/types/light-account/lightAccountStaticImpl.d.ts.map +1 -1
  70. package/dist/types/light-account/predictAddress.d.ts +40 -2
  71. package/dist/types/light-account/predictAddress.d.ts.map +1 -1
  72. package/dist/types/light-account/registry.d.ts +3410 -0
  73. package/dist/types/light-account/registry.d.ts.map +1 -1
  74. package/dist/types/logger.d.ts +1 -1
  75. package/dist/types/logger.d.ts.map +1 -1
  76. package/dist/types/ma-v1/accounts/multi-owner-account.d.ts +6 -2
  77. package/dist/types/ma-v1/accounts/multi-owner-account.d.ts.map +1 -1
  78. package/dist/types/ma-v1/predictAddress.d.ts +20 -1
  79. package/dist/types/ma-v1/predictAddress.d.ts.map +1 -1
  80. package/dist/types/ma-v2/accounts/account.d.ts +8 -5
  81. package/dist/types/ma-v2/accounts/account.d.ts.map +1 -1
  82. package/dist/types/ma-v2/accounts/base.d.ts +2 -2
  83. package/dist/types/ma-v2/accounts/base.d.ts.map +1 -1
  84. package/dist/types/ma-v2/mav2StaticImpl.d.ts +1 -15
  85. package/dist/types/ma-v2/mav2StaticImpl.d.ts.map +1 -1
  86. package/dist/types/ma-v2/modules/time-range-module/module.d.ts.map +1 -1
  87. package/dist/types/ma-v2/predictAddress.d.ts +22 -6
  88. package/dist/types/ma-v2/predictAddress.d.ts.map +1 -1
  89. package/dist/types/ma-v2/utils/account.d.ts +0 -3
  90. package/dist/types/ma-v2/utils/account.d.ts.map +1 -1
  91. package/dist/types/ma-v2/utils/signature.d.ts +1 -16
  92. package/dist/types/ma-v2/utils/signature.d.ts.map +1 -1
  93. package/dist/types/utils.d.ts +24 -11
  94. package/dist/types/utils.d.ts.map +1 -1
  95. package/dist/types/version.d.ts +1 -1
  96. package/dist/types/version.d.ts.map +1 -1
  97. package/package.json +9 -8
  98. package/src/index.ts +0 -6
  99. package/src/light-account/accounts/account.ts +30 -16
  100. package/src/light-account/accounts/base.ts +62 -23
  101. package/src/light-account/accounts/calldataCodec.ts +3 -2
  102. package/src/light-account/accounts/multi-owner-account.ts +22 -9
  103. package/src/light-account/lightAccountStaticImpl.ts +84 -11
  104. package/src/light-account/predictAddress.ts +124 -3
  105. package/src/light-account/registry.ts +44 -0
  106. package/src/logger.ts +2 -2
  107. package/src/ma-v1/accounts/multi-owner-account.ts +26 -11
  108. package/src/ma-v1/predictAddress.ts +60 -3
  109. package/src/ma-v2/accounts/account.ts +39 -52
  110. package/src/ma-v2/accounts/base.ts +11 -84
  111. package/src/ma-v2/mav2StaticImpl.ts +1 -52
  112. package/src/ma-v2/modules/time-range-module/module.ts +3 -2
  113. package/src/ma-v2/predictAddress.ts +68 -30
  114. package/src/ma-v2/utils/account.ts +0 -3
  115. package/src/ma-v2/utils/signature.ts +2 -57
  116. package/src/utils.ts +111 -27
  117. package/src/version.ts +1 -1
  118. package/dist/esm/ma-v2/abis/webAuthnFactoryAbi.d.ts +0 -330
  119. package/dist/esm/ma-v2/abis/webAuthnFactoryAbi.js +0 -260
  120. package/dist/esm/ma-v2/abis/webAuthnFactoryAbi.js.map +0 -1
  121. package/dist/esm/ma-v2/modules/webauthn-validation/abis/webauthnValidationAbi.d.ts +0 -287
  122. package/dist/esm/ma-v2/modules/webauthn-validation/abis/webauthnValidationAbi.js +0 -374
  123. package/dist/esm/ma-v2/modules/webauthn-validation/abis/webauthnValidationAbi.js.map +0 -1
  124. package/dist/esm/ma-v2/modules/webauthn-validation/module.d.ts +0 -11
  125. package/dist/esm/ma-v2/modules/webauthn-validation/module.js +0 -16
  126. package/dist/esm/ma-v2/modules/webauthn-validation/module.js.map +0 -1
  127. package/dist/types/ma-v2/abis/webAuthnFactoryAbi.d.ts +0 -331
  128. package/dist/types/ma-v2/abis/webAuthnFactoryAbi.d.ts.map +0 -1
  129. package/dist/types/ma-v2/modules/webauthn-validation/abis/webauthnValidationAbi.d.ts +0 -288
  130. package/dist/types/ma-v2/modules/webauthn-validation/abis/webauthnValidationAbi.d.ts.map +0 -1
  131. package/dist/types/ma-v2/modules/webauthn-validation/module.d.ts +0 -12
  132. package/dist/types/ma-v2/modules/webauthn-validation/module.d.ts.map +0 -1
  133. package/src/ma-v2/abis/webAuthnFactoryAbi.ts +0 -259
  134. package/src/ma-v2/modules/webauthn-validation/abis/webauthnValidationAbi.ts +0 -373
  135. package/src/ma-v2/modules/webauthn-validation/module.ts +0 -28
@@ -1,13 +1,19 @@
1
1
  import {
2
2
  type Address,
3
- getContractAddress,
3
+ type Client,
4
+ concatHex,
5
+ decodeFunctionData,
4
6
  encodeAbiParameters,
7
+ getContractAddress,
8
+ isAddressEqual,
5
9
  keccak256,
6
- concatHex,
7
10
  type Hex,
8
11
  } from "viem";
12
+ import type { EntryPointVersion } from "viem/account-abstraction";
9
13
  import { DefaultMaV1Address } from "./account.js";
14
+ import { MultiOwnerModularAccountFactoryAbi } from "./abis/MultiOwnerModularAccountFactory.js";
10
15
  import { BaseError } from "@alchemy/common";
16
+ import { getSenderFromFactoryData } from "../utils.js";
11
17
 
12
18
  export type PredictMultiOwnerModularAccountV1AddressParams = {
13
19
  salt: bigint;
@@ -46,7 +52,7 @@ export const predictMultiOwnerModularAccountV1Address = ({
46
52
  throw new BaseError("Owners array cannot be empty");
47
53
  }
48
54
  if (ownerAddresses.length > 100) {
49
- throw new Error("Maximum 100 owners on creation");
55
+ throw new BaseError("Maximum 100 owners on creation");
50
56
  }
51
57
 
52
58
  const combinedSalt = getCombinedSalt(salt, ownerAddresses);
@@ -83,3 +89,54 @@ function getERC1967ProxyInitCodeHash(implementationAddress: Address): Hex {
83
89
 
84
90
  return keccak256(concatHex([ERC1967_PROXY_BYTECODE, constructorArgs]));
85
91
  }
92
+
93
+ export type GetMultiOwnerModularAccountV1AddressFromFactoryDataParams = {
94
+ client: Client;
95
+ factoryAddress: Address;
96
+ factoryData: Hex;
97
+ entryPoint: {
98
+ version: EntryPointVersion;
99
+ address: Address;
100
+ };
101
+ };
102
+
103
+ /**
104
+ * Gets the multi-owner modular account v1 address from factory data.
105
+ * If the factory is a known default, decodes the args and predicts without RPC.
106
+ * Otherwise falls back to calling the entry point's getSenderAddress.
107
+ *
108
+ * @param {GetMultiOwnerModularAccountV1AddressFromFactoryDataParams} params - The parameters
109
+ * @returns {Promise<Address>} The account address
110
+ */
111
+ export async function getMultiOwnerModularAccountV1AddressFromFactoryData({
112
+ client,
113
+ factoryAddress,
114
+ factoryData,
115
+ entryPoint,
116
+ }: GetMultiOwnerModularAccountV1AddressFromFactoryDataParams): Promise<Address> {
117
+ if (
118
+ isAddressEqual(factoryAddress, DefaultMaV1Address.MULTI_OWNER_MAV1_FACTORY)
119
+ ) {
120
+ try {
121
+ const decoded = decodeFunctionData({
122
+ abi: MultiOwnerModularAccountFactoryAbi,
123
+ data: factoryData,
124
+ });
125
+ if (decoded.functionName === "createAccount") {
126
+ const [decodedSalt, decodedOwners] = decoded.args;
127
+ return predictMultiOwnerModularAccountV1Address({
128
+ factoryAddress,
129
+ salt: decodedSalt,
130
+ ownerAddresses: [...decodedOwners],
131
+ });
132
+ }
133
+ } catch {
134
+ // Decode failed, fall through to RPC
135
+ }
136
+ }
137
+ return getSenderFromFactoryData(client, {
138
+ factory: factoryAddress,
139
+ factoryData,
140
+ entryPoint,
141
+ });
142
+ }
@@ -9,16 +9,17 @@ import {
9
9
  type PrivateKeyAccount,
10
10
  type Transport,
11
11
  } from "viem";
12
- import type {
13
- WebAuthnAccount,
14
- ToSmartAccountParameters,
12
+ import {
13
+ type ToSmartAccountParameters,
14
+ entryPoint07Address,
15
15
  } from "viem/account-abstraction";
16
16
  import { toModularAccountV2Base, type ModularAccountV2Base } from "./base.js";
17
17
  import type { SignerEntity } from "../types.js";
18
- import { predictModularAccountV2Address } from "../predictAddress.js";
19
- import { parsePublicKey } from "webauthn-p256";
18
+ import {
19
+ getModularAccountV2AddressFromFactoryData,
20
+ predictModularAccountV2Address,
21
+ } from "../predictAddress.js";
20
22
  import { accountFactoryAbi } from "../abis/accountFactoryAbi.js";
21
- import { webAuthnFactoryAbi } from "../abis/webAuthnFactoryAbi.js";
22
23
  import { EntityIdOverrideError } from "../../errors/EntityIdOverrideError.js";
23
24
  import { InvalidOwnerError } from "../../errors/InvalidOwnerError.js";
24
25
  import { DEFAULT_OWNER_ENTITY_ID, DefaultAddress } from "../utils/account.js";
@@ -33,7 +34,7 @@ export type ToModularAccountV2Params<
33
34
  TMode extends Mode | undefined = Mode | undefined,
34
35
  > = {
35
36
  client: Client<Transport, Chain, JsonRpcAccount | LocalAccount | undefined>;
36
- owner: JsonRpcAccount | LocalAccount | WebAuthnAccount;
37
+ owner: JsonRpcAccount | LocalAccount;
37
38
  deferredAction?: Hex;
38
39
  signerEntity?: SignerEntity;
39
40
  accountAddress?: Address;
@@ -46,11 +47,18 @@ export type ToModularAccountV2Params<
46
47
  implementationAddress?: never;
47
48
  }
48
49
  : {
49
- salt?: bigint;
50
50
  factory?: Address;
51
- factoryData?: Hex;
52
51
  implementationAddress?: Address;
53
- });
52
+ } & (
53
+ | {
54
+ salt?: bigint;
55
+ factoryData?: never;
56
+ }
57
+ | {
58
+ salt?: never;
59
+ factoryData?: Hex;
60
+ }
61
+ ));
54
62
 
55
63
  /**
56
64
  * Creates a MAv2 account.
@@ -81,19 +89,11 @@ export async function toModularAccountV2<TMode extends Mode = Mode>({
81
89
 
82
90
  const entityId = signerEntity?.entityId ?? DEFAULT_OWNER_ENTITY_ID;
83
91
 
84
- const factoryAddress =
85
- factory ??
86
- (owner.type === "webAuthn"
87
- ? DefaultAddress.MAV2_FACTORY_WEBAUTHN
88
- : DefaultAddress.MAV2_FACTORY);
92
+ const factoryAddress = factory ?? DefaultAddress.MAV2_FACTORY;
89
93
 
90
94
  const implementationAddress =
91
95
  implementationAddress_ ??
92
- (is7702
93
- ? DefaultAddress.SMAV2_7702
94
- : owner.type === "webAuthn"
95
- ? DefaultAddress.MAV2
96
- : DefaultAddress.SMAV2_BYTECODE);
96
+ (is7702 ? DefaultAddress.SMAV2_7702 : DefaultAddress.SMAV2_BYTECODE);
97
97
 
98
98
  const getFactoryArgs = async () => {
99
99
  if (is7702) {
@@ -108,20 +108,6 @@ export async function toModularAccountV2<TMode extends Mode = Mode>({
108
108
  } as const;
109
109
  }
110
110
 
111
- if (owner.type === "webAuthn") {
112
- const { x, y } = parsePublicKey(owner.publicKey);
113
- return {
114
- factory: factoryAddress,
115
- factoryData:
116
- factoryData_ ??
117
- encodeFunctionData({
118
- abi: webAuthnFactoryAbi,
119
- functionName: "createWebAuthnAccount",
120
- args: [x, y, salt, entityId],
121
- }),
122
- };
123
- }
124
-
125
111
  return {
126
112
  factory: factoryAddress,
127
113
  factoryData:
@@ -136,24 +122,26 @@ export async function toModularAccountV2<TMode extends Mode = Mode>({
136
122
 
137
123
  const accountAddress =
138
124
  accountAddress_ ??
139
- (mode === "7702" && owner.type === "local"
125
+ (is7702
140
126
  ? owner.address
141
- : predictModularAccountV2Address({
142
- factoryAddress,
143
- implementationAddress,
144
- salt,
145
- ...(owner.type === "webAuthn"
146
- ? {
147
- type: "WebAuthn",
148
- ownerPublicKey: owner.publicKey,
149
- entityId,
150
- }
151
- : {
152
- type: "SMA", // `MA` is never used here since we only support deploying SMA & WebAuthn accounts.
153
- ownerAddress: owner.address,
154
- entityId,
155
- }),
156
- }));
127
+ : factoryData_
128
+ ? await getModularAccountV2AddressFromFactoryData({
129
+ client,
130
+ factoryAddress,
131
+ factoryData: factoryData_,
132
+ implementationAddress,
133
+ entryPoint: {
134
+ version: "0.7",
135
+ address: entryPoint07Address,
136
+ },
137
+ })
138
+ : predictModularAccountV2Address({
139
+ factoryAddress,
140
+ implementationAddress,
141
+ salt,
142
+ type: "SMA",
143
+ ownerAddress: owner.address,
144
+ }));
157
145
 
158
146
  LOGGER.debug("toModularAccountV2:address-resolved", {
159
147
  accountAddress,
@@ -163,7 +151,6 @@ export async function toModularAccountV2<TMode extends Mode = Mode>({
163
151
  let authorization: ToSmartAccountParameters["authorization"];
164
152
  if (is7702) {
165
153
  LOGGER.debug("toModularAccountV2:7702-mode");
166
- // TODO(v5): Ensure this works w/ our signer types.
167
154
  if (owner.type !== "local") {
168
155
  LOGGER.error("toModularAccountV2:invalid-owner-type", {
169
156
  ownerType: owner.type,
@@ -22,10 +22,7 @@ import {
22
22
  entryPoint07Address,
23
23
  getUserOperationHash,
24
24
  toSmartAccount,
25
- type WebAuthnAccount,
26
25
  type ToSmartAccountParameters,
27
- estimateUserOperationGas,
28
- type UserOperation,
29
26
  } from "viem/account-abstraction";
30
27
  import {
31
28
  getCode,
@@ -60,15 +57,13 @@ import {
60
57
  import { parseDeferredAction } from "../utils/deferredActions.js";
61
58
  import {
62
59
  pack1271Signature,
63
- toWebAuthnSignature,
64
60
  toReplaySafeTypedData,
65
61
  packUOSignature,
66
- WEBAUTHN_DUMMY_SIGNATURE,
67
62
  } from "../utils/signature.js";
68
- import { chainHas7212 } from "../../utils.js";
69
63
  import { InvalidDeferredActionNonceError } from "../../errors/InvalidDeferredActionNonceError.js";
70
64
  import { InvalidNonceKeyError } from "../../errors/InvalidNonceKeyError.js";
71
65
  import { InvalidEntityIdError } from "../../errors/InvalidEntityIdError.js";
66
+ import { is7702Delegated } from "../../utils.js";
72
67
 
73
68
  export type ValidationDataParams =
74
69
  | {
@@ -104,7 +99,7 @@ export type ToModularAccountV2BaseParams<
104
99
  TTransport extends Transport = Transport,
105
100
  > = {
106
101
  client: Client<TTransport, Chain, JsonRpcAccount | LocalAccount | undefined>;
107
- owner: JsonRpcAccount | LocalAccount | WebAuthnAccount;
102
+ owner: JsonRpcAccount | LocalAccount;
108
103
  accountAddress: Address;
109
104
  getFactoryArgs: () => Promise<{
110
105
  factory?: Address | undefined;
@@ -155,7 +150,9 @@ export async function toModularAccountV2Base<
155
150
  }
156
151
  const action = getAction(client, getCode, "getCode");
157
152
  const code = await action({ address: accountAddress });
158
- isDeployed = !!code;
153
+ isDeployed = authorization
154
+ ? is7702Delegated(authorization.address, code)
155
+ : !!code;
159
156
  return isDeployed;
160
157
  };
161
158
 
@@ -303,17 +300,12 @@ export async function toModularAccountV2Base<
303
300
  data: toReplaySafeTypedData({
304
301
  chainId: client.chain.id,
305
302
  hash,
306
- ...(owner.type === "webAuthn"
307
- ? {
308
- address: DefaultModuleAddress.WEBAUTHN_VALIDATION,
303
+ ...(entityId === DEFAULT_OWNER_ENTITY_ID
304
+ ? { address: accountAddress }
305
+ : {
306
+ address: DefaultModuleAddress.SINGLE_SIGNER_VALIDATION,
309
307
  salt: concatHex([`0x${"00".repeat(12)}`, accountAddress]),
310
- }
311
- : entityId === DEFAULT_OWNER_ENTITY_ID
312
- ? { address: accountAddress }
313
- : {
314
- address: DefaultModuleAddress.SINGLE_SIGNER_VALIDATION,
315
- salt: concatHex([`0x${"00".repeat(12)}`, accountAddress]),
316
- }),
308
+ }),
317
309
  }),
318
310
  };
319
311
  };
@@ -321,8 +313,7 @@ export async function toModularAccountV2Base<
321
313
  const formatSignature = async (signature: Hex): Promise<Hex> => {
322
314
  return pack1271Signature({
323
315
  entityId,
324
- validationSignaturePrefix:
325
- owner.type === "webAuthn" ? null : SignaturePrefix.EOA,
316
+ validationSignaturePrefix: SignaturePrefix.EOA,
326
317
  validationSignature: signature,
327
318
  });
328
319
  };
@@ -418,10 +409,6 @@ export async function toModularAccountV2Base<
418
409
  },
419
410
 
420
411
  async getStubSignature() {
421
- if (owner.type === "webAuthn") {
422
- return WEBAUTHN_DUMMY_SIGNATURE;
423
- }
424
-
425
412
  const sig = packUOSignature({
426
413
  validationSignature:
427
414
  "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c",
@@ -435,13 +422,6 @@ export async function toModularAccountV2Base<
435
422
  data: message,
436
423
  });
437
424
 
438
- if (owner.type === "webAuthn") {
439
- const validationSignature = toWebAuthnSignature(
440
- await owner.sign({ hash: hashTypedData(data) }),
441
- );
442
- return formatSignature(validationSignature);
443
- }
444
-
445
425
  const action = getAction(client, signTypedData, "signTypedData");
446
426
 
447
427
  const signature = await action({
@@ -465,15 +445,6 @@ export async function toModularAccountV2Base<
465
445
  data: td as TypedDataDefinition, // TODO(v5): Try harder to satisfy this w/o casting.
466
446
  });
467
447
 
468
- if (owner.type === "webAuthn") {
469
- const validationSignature = toWebAuthnSignature(
470
- await owner.sign({ hash: hashTypedData(data) }),
471
- );
472
- return isDeferredAction
473
- ? validationSignature
474
- : formatSignature(validationSignature);
475
- }
476
-
477
448
  const action = getAction(client, signTypedData, "signTypedData");
478
449
 
479
450
  const signature = await action({
@@ -497,21 +468,6 @@ export async function toModularAccountV2Base<
497
468
  },
498
469
  });
499
470
 
500
- if (owner.type === "webAuthn") {
501
- const validationSignature = toWebAuthnSignature(
502
- await owner.sign({
503
- hash: hashMessage({ raw: hash }),
504
- }),
505
- );
506
-
507
- const signature = deferredActionData
508
- ? concatHex([deferredActionData, validationSignature])
509
- : validationSignature;
510
- deferredActionData = undefined; // clear once used
511
- hasAssociatedExecHooks = false; // set to falsy value once used
512
- return concatHex(["0xff", signature]);
513
- }
514
-
515
471
  const signMessageAction = getAction(client, signMessage, "signMessage");
516
472
 
517
473
  const validationSignature = await signMessageAction({
@@ -533,35 +489,6 @@ export async function toModularAccountV2Base<
533
489
  return signature;
534
490
  },
535
491
 
536
- userOperation: {
537
- estimateGas: async (uo) => {
538
- if (owner.type !== "webAuthn") {
539
- // Uses the default gas estimator.
540
- // Note that we get 7702 support automatically from Viem.
541
- return undefined;
542
- }
543
-
544
- const estimateGasAction = getAction(
545
- client,
546
- estimateUserOperationGas,
547
- "estimateUserOperationGas",
548
- );
549
-
550
- const estimate = await estimateGasAction({
551
- ...(uo as UserOperation<typeof entryPoint.version>),
552
- entryPointAddress: entryPoint.address,
553
- });
554
-
555
- const buffer = (await chainHas7212(client)) ? 10000n : 300000n;
556
-
557
- // TODO(v4): iterate numbers. Aim to have ~1000 gas buffer to account for longer authenticatorDatas and clientDataJSONs.
558
- return {
559
- ...estimate,
560
- verificationGasLimit: estimate.verificationGasLimit + buffer,
561
- };
562
- },
563
- },
564
-
565
492
  extend: {
566
493
  smartAccountType: "ModularAccountV2" as const,
567
494
  signerEntity: {
@@ -1,14 +1,11 @@
1
- import { encodeFunctionData, type Address, type Hex } from "viem";
1
+ import { encodeFunctionData, type Address } from "viem";
2
2
  import { entryPoint07Abi, entryPoint07Address } from "viem/account-abstraction";
3
3
  import { lowerAddress } from "@alchemy/common";
4
4
  import type { StaticSmartAccountImplementation } from "../types.js";
5
5
  import { semiModularAccountBytecodeAbi } from "./abis/semiModularAccountBytecodeAbi.js";
6
6
  import { accountFactoryAbi } from "./abis/accountFactoryAbi.js";
7
- import { webAuthnFactoryAbi } from "./abis/webAuthnFactoryAbi.js";
8
7
  import { DefaultAddress as DefaultMAV2Address } from "./utils/account.js";
9
8
  import { predictModularAccountV2Address } from "./predictAddress.js";
10
- import { modularAccountAbi } from "./abis/modularAccountAbi.js";
11
- import { parsePublicKey } from "webauthn-p256";
12
9
 
13
10
  export type SemiModularAccountV2FactoryArgs = {
14
11
  owner: Address;
@@ -84,51 +81,3 @@ export const semiModularAccount7702StaticImpl: SemiModularAccount7702StaticImpl
84
81
  ...semiModularAccountBase,
85
82
  delegationAddress: lowerAddress(DefaultMAV2Address.SMAV2_7702),
86
83
  };
87
-
88
- export type WebAuthnModularAccountV2FactoryArgs = {
89
- ownerPublicKey: Hex;
90
- salt: bigint;
91
- entityId: number;
92
- };
93
-
94
- export type WebAuthnModularAccountV2StaticImpl =
95
- StaticSmartAccountImplementation<
96
- false,
97
- "0.7",
98
- WebAuthnModularAccountV2FactoryArgs,
99
- typeof entryPoint07Abi,
100
- typeof modularAccountAbi,
101
- typeof webAuthnFactoryAbi
102
- >;
103
-
104
- /**
105
- * Static implementation logic for WebAuthnModularAccountV2.
106
- *
107
- * TODO(v5): update JSDoc format when doc-gen supports structs or records.
108
- */
109
- export const webAuthnModularAccountV2StaticImpl: WebAuthnModularAccountV2StaticImpl =
110
- {
111
- entryPoint,
112
- accountAbi: modularAccountAbi,
113
- accountImplementation: lowerAddress(DefaultMAV2Address.MAV2),
114
- factoryAddress: lowerAddress(DefaultMAV2Address.MAV2_FACTORY_WEBAUTHN),
115
- factoryAbi: webAuthnFactoryAbi,
116
- getFactoryData: (args: WebAuthnModularAccountV2FactoryArgs) => {
117
- const { x, y } = parsePublicKey(args.ownerPublicKey);
118
- return encodeFunctionData({
119
- abi: webAuthnFactoryAbi,
120
- functionName: "createWebAuthnAccount",
121
- args: [x, y, args.salt, args.entityId],
122
- });
123
- },
124
- predictAccountAddress: (args: WebAuthnModularAccountV2FactoryArgs) => {
125
- return predictModularAccountV2Address({
126
- factoryAddress: DefaultMAV2Address.MAV2_FACTORY_WEBAUTHN,
127
- implementationAddress: DefaultMAV2Address.MAV2,
128
- type: "WebAuthn",
129
- salt: args.salt,
130
- ownerPublicKey: args.ownerPublicKey,
131
- entityId: args.entityId,
132
- });
133
- },
134
- };
@@ -2,6 +2,7 @@ import { encodeAbiParameters, type Address, type Hex } from "viem";
2
2
 
3
3
  import { timeRangeModuleAbi } from "./abis/timeRangeModuleAbi.js";
4
4
  import { HookType, type HookConfig } from "../../types.js";
5
+ import { BaseError } from "@alchemy/common";
5
6
 
6
7
  export const TimeRangeModule = {
7
8
  abi: timeRangeModuleAbi,
@@ -14,13 +15,13 @@ export const TimeRangeModule = {
14
15
  address: Address,
15
16
  ): { hookConfig: HookConfig; initData: Hex } => {
16
17
  if (installArgs.validUntil > 2 ** 48 - 1) {
17
- throw new Error(
18
+ throw new BaseError(
18
19
  "TimeRangeModule.buildHook: validUntil > type(uint48).max",
19
20
  );
20
21
  }
21
22
 
22
23
  if (installArgs.validAfter > 2 ** 48 - 1) {
23
- throw new Error(
24
+ throw new BaseError(
24
25
  "TimeRangeModule.buildHook: validAfter > type(uint48).max",
25
26
  );
26
27
  }
@@ -1,13 +1,22 @@
1
1
  import { assertNever } from "@alchemy/common";
2
2
  import {
3
3
  concatHex,
4
+ decodeFunctionData,
4
5
  encodePacked,
5
6
  getContractAddress,
7
+ isAddressEqual,
6
8
  keccak256,
7
9
  type Address,
10
+ type Client,
8
11
  type Hex,
9
12
  } from "viem";
10
- import { parsePublicKey } from "webauthn-p256";
13
+ import {
14
+ entryPoint07Address,
15
+ type EntryPointVersion,
16
+ } from "viem/account-abstraction";
17
+ import { accountFactoryAbi } from "./abis/accountFactoryAbi.js";
18
+ import { DefaultAddress } from "./utils/account.js";
19
+ import { getSenderFromFactoryData } from "../utils.js";
11
20
 
12
21
  export type PredictModularAccountV2AddressParams = {
13
22
  factoryAddress: Address;
@@ -23,15 +32,10 @@ export type PredictModularAccountV2AddressParams = {
23
32
  type: "SMA";
24
33
  ownerAddress: Address;
25
34
  }
26
- | {
27
- type: "WebAuthn";
28
- ownerPublicKey: Hex;
29
- entityId: number;
30
- }
31
35
  );
32
36
 
33
37
  /**
34
- * Predicts the address of a modular account V2 based on the provided parameters, which include factory address, salt, and implementation address. This function supports different types of accounts including "SMA", "MA", and "WebAuthn".
38
+ * Predicts the address of a modular account V2 based on the provided parameters, which include factory address, salt, and implementation address. This function supports different types of accounts including "SMA" and "MA".
35
39
  *
36
40
  * @example
37
41
  * ```ts
@@ -80,16 +84,6 @@ export function predictModularAccountV2Address(
80
84
  ),
81
85
  initcode: getProxyBytecode(implementationAddress),
82
86
  };
83
- case "WebAuthn":
84
- const { x, y } = parsePublicKey(params.ownerPublicKey);
85
- return {
86
- combinedSalt: getCombinedSaltWebAuthn(
87
- { x, y },
88
- salt,
89
- params.entityId,
90
- ),
91
- initcode: getProxyBytecode(implementationAddress),
92
- };
93
87
  default:
94
88
  return assertNever(params, "Unexpected MAv2 type");
95
89
  }
@@ -116,19 +110,6 @@ function getCombinedSaltK1(
116
110
  );
117
111
  }
118
112
 
119
- function getCombinedSaltWebAuthn(
120
- ownerPublicKey: { x: bigint; y: bigint },
121
- salt: bigint,
122
- entityId: number,
123
- ): Hex {
124
- return keccak256(
125
- encodePacked(
126
- ["uint256", "uint256", "uint256", "uint32"],
127
- [ownerPublicKey.x, ownerPublicKey.y, salt, entityId],
128
- ),
129
- );
130
- }
131
-
132
113
  function getProxyBytecode(implementationAddress: Address): Hex {
133
114
  return concatHex([
134
115
  "0x603d3d8160223d3973",
@@ -147,3 +128,60 @@ function getProxyBytecodeWithImmutableArgs(
147
128
  2,
148
129
  )}`;
149
130
  }
131
+
132
+ export type GetModularAccountV2AddressFromFactoryDataParams = {
133
+ client: Client;
134
+ factoryAddress: Address;
135
+ factoryData: Hex;
136
+ implementationAddress: Address;
137
+ entryPoint?: {
138
+ version: EntryPointVersion;
139
+ address: Address;
140
+ };
141
+ };
142
+
143
+ /**
144
+ * Gets the modular account v2 address from factory data.
145
+ * If the factory is a known default (SMA), decodes the args and predicts without RPC.
146
+ * Otherwise falls back to calling the entry point's getSenderAddress.
147
+ *
148
+ * @param {GetModularAccountV2AddressFromFactoryDataParams} params - The parameters
149
+ * @returns {Promise<Address>} The account address
150
+ */
151
+ export async function getModularAccountV2AddressFromFactoryData({
152
+ client,
153
+ factoryAddress,
154
+ factoryData,
155
+ implementationAddress,
156
+ entryPoint = {
157
+ version: "0.7",
158
+ address: entryPoint07Address,
159
+ },
160
+ }: GetModularAccountV2AddressFromFactoryDataParams): Promise<Address> {
161
+ // Try SMA factory
162
+ if (isAddressEqual(factoryAddress, DefaultAddress.MAV2_FACTORY)) {
163
+ try {
164
+ const decoded = decodeFunctionData({
165
+ abi: accountFactoryAbi,
166
+ data: factoryData,
167
+ });
168
+ if (decoded.functionName === "createSemiModularAccount") {
169
+ const [decodedOwner, decodedSalt] = decoded.args;
170
+ return predictModularAccountV2Address({
171
+ factoryAddress,
172
+ implementationAddress,
173
+ salt: decodedSalt,
174
+ type: "SMA",
175
+ ownerAddress: decodedOwner,
176
+ });
177
+ }
178
+ } catch {
179
+ // Decode failed, fall through to RPC
180
+ }
181
+ }
182
+ return getSenderFromFactoryData(client, {
183
+ factory: factoryAddress,
184
+ factoryData,
185
+ entryPoint,
186
+ });
187
+ }
@@ -16,11 +16,9 @@ import type { ModularAccountV2Base } from "../accounts/base.js";
16
16
  */
17
17
  export const DefaultAddress = {
18
18
  MAV2_FACTORY: "0x00000000000017c61b5bEe81050EC8eFc9c6fecd",
19
- MAV2_FACTORY_WEBAUTHN: "0x55010E571dCf07e254994bfc88b9C1C8FAe31960",
20
19
  SMAV2_BYTECODE: "0x000000000000c5A9089039570Dd36455b5C07383",
21
20
  SMAV2_STORAGE: "0x0000000000006E2f9d80CaEc0Da6500f005EB25A",
22
21
  SMAV2_7702: "0x69007702764179f14F51cdce752f4f775d74E139",
23
- MAV2: "0x00000000000002377B26b1EdA7b0BC371C60DD4f",
24
22
  } satisfies Record<string, Address>;
25
23
 
26
24
  /**
@@ -28,7 +26,6 @@ export const DefaultAddress = {
28
26
  */
29
27
  export const DefaultModuleAddress = {
30
28
  SINGLE_SIGNER_VALIDATION: "0x00000000000099DE0BF6fA90dEB851E2A2df7d83",
31
- WEBAUTHN_VALIDATION: "0x0000000000001D9d34E07D9834274dF9ae575217",
32
29
  TIME_RANGE: "0x00000000000082B8e2012be914dFA4f62A0573eA",
33
30
  PAYMASTER_GUARD: "0x0000000000001aA7A7F7E29abe0be06c72FD42A1",
34
31
  NATIVE_TOKEN_LIMIT: "0x00000000000001e541f0D090868FBe24b59Fbe06",