@account-kit/wallet-client 0.1.0-alpha.7 → 0.1.0-alpha.9

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 (91) hide show
  1. package/dist/esm/capabilities/index.d.ts +3 -0
  2. package/dist/esm/capabilities/index.js +2 -0
  3. package/dist/esm/capabilities/index.js.map +1 -1
  4. package/dist/esm/capabilities/multiDimensionalNonce.d.ts +3 -0
  5. package/dist/esm/capabilities/multiDimensionalNonce.js +7 -0
  6. package/dist/esm/capabilities/multiDimensionalNonce.js.map +1 -0
  7. package/dist/esm/client/actions/prepareCalls.d.ts +1 -1
  8. package/dist/esm/client/actions/prepareCalls.js +1 -1
  9. package/dist/esm/client/actions/prepareCalls.js.map +1 -1
  10. package/dist/esm/client/actions/signPreparedCalls.js +26 -37
  11. package/dist/esm/client/actions/signPreparedCalls.js.map +1 -1
  12. package/dist/esm/client/actions/signSignatureRequest.d.ts +3 -2
  13. package/dist/esm/client/actions/signSignatureRequest.js.map +1 -1
  14. package/dist/esm/exports/internal.d.ts +1 -0
  15. package/dist/esm/exports/internal.js +1 -0
  16. package/dist/esm/exports/internal.js.map +1 -1
  17. package/dist/esm/isomorphic/actions/createSession.js +20 -5
  18. package/dist/esm/isomorphic/actions/createSession.js.map +1 -1
  19. package/dist/esm/isomorphic/actions/prepareCalls.js +39 -17
  20. package/dist/esm/isomorphic/actions/prepareCalls.js.map +1 -1
  21. package/dist/esm/isomorphic/actions/sendPreparedCalls.js +62 -8
  22. package/dist/esm/isomorphic/actions/sendPreparedCalls.js.map +1 -1
  23. package/dist/esm/isomorphic/client.d.ts +9 -0
  24. package/dist/esm/isomorphic/utils/7702.d.ts +6 -1
  25. package/dist/esm/isomorphic/utils/7702.js +26 -12
  26. package/dist/esm/isomorphic/utils/7702.js.map +1 -1
  27. package/dist/esm/isomorphic/utils/createAccount.d.ts +1 -0
  28. package/dist/esm/isomorphic/utils/createAccount.js +96 -34
  29. package/dist/esm/isomorphic/utils/createAccount.js.map +1 -1
  30. package/dist/esm/isomorphic/utils/supportsFeature.d.ts +4 -0
  31. package/dist/esm/isomorphic/utils/supportsFeature.js +21 -0
  32. package/dist/esm/isomorphic/utils/supportsFeature.js.map +1 -0
  33. package/dist/esm/rpc/request.d.ts +54 -0
  34. package/dist/esm/rpc/request.js +1 -0
  35. package/dist/esm/rpc/request.js.map +1 -1
  36. package/dist/esm/rpc/schema.d.ts +54 -0
  37. package/dist/esm/schemas.d.ts +35 -1
  38. package/dist/esm/schemas.js +56 -1
  39. package/dist/esm/schemas.js.map +1 -1
  40. package/dist/esm/types.d.ts +3 -0
  41. package/dist/esm/types.js.map +1 -1
  42. package/dist/esm/utils.d.ts +1 -0
  43. package/dist/esm/utils.js.map +1 -1
  44. package/dist/types/capabilities/index.d.ts +3 -0
  45. package/dist/types/capabilities/index.d.ts.map +1 -1
  46. package/dist/types/capabilities/multiDimensionalNonce.d.ts +4 -0
  47. package/dist/types/capabilities/multiDimensionalNonce.d.ts.map +1 -0
  48. package/dist/types/client/actions/prepareCalls.d.ts +1 -1
  49. package/dist/types/client/actions/signPreparedCalls.d.ts.map +1 -1
  50. package/dist/types/client/actions/signSignatureRequest.d.ts +3 -2
  51. package/dist/types/client/actions/signSignatureRequest.d.ts.map +1 -1
  52. package/dist/types/exports/internal.d.ts +1 -0
  53. package/dist/types/exports/internal.d.ts.map +1 -1
  54. package/dist/types/isomorphic/actions/createSession.d.ts.map +1 -1
  55. package/dist/types/isomorphic/actions/prepareCalls.d.ts.map +1 -1
  56. package/dist/types/isomorphic/actions/sendPreparedCalls.d.ts.map +1 -1
  57. package/dist/types/isomorphic/client.d.ts +9 -0
  58. package/dist/types/isomorphic/client.d.ts.map +1 -1
  59. package/dist/types/isomorphic/utils/7702.d.ts +6 -1
  60. package/dist/types/isomorphic/utils/7702.d.ts.map +1 -1
  61. package/dist/types/isomorphic/utils/createAccount.d.ts +1 -0
  62. package/dist/types/isomorphic/utils/createAccount.d.ts.map +1 -1
  63. package/dist/types/isomorphic/utils/supportsFeature.d.ts +5 -0
  64. package/dist/types/isomorphic/utils/supportsFeature.d.ts.map +1 -0
  65. package/dist/types/rpc/request.d.ts +54 -0
  66. package/dist/types/rpc/request.d.ts.map +1 -1
  67. package/dist/types/rpc/schema.d.ts +54 -0
  68. package/dist/types/rpc/schema.d.ts.map +1 -1
  69. package/dist/types/schemas.d.ts +35 -1
  70. package/dist/types/schemas.d.ts.map +1 -1
  71. package/dist/types/types.d.ts +3 -0
  72. package/dist/types/types.d.ts.map +1 -1
  73. package/dist/types/utils.d.ts +1 -0
  74. package/dist/types/utils.d.ts.map +1 -1
  75. package/package.json +5 -5
  76. package/src/capabilities/index.ts +2 -0
  77. package/src/capabilities/multiDimensionalNonce.ts +7 -0
  78. package/src/client/actions/prepareCalls.ts +1 -1
  79. package/src/client/actions/signPreparedCalls.ts +42 -43
  80. package/src/client/actions/signSignatureRequest.ts +4 -2
  81. package/src/exports/internal.ts +1 -0
  82. package/src/isomorphic/actions/createSession.ts +25 -4
  83. package/src/isomorphic/actions/prepareCalls.ts +48 -21
  84. package/src/isomorphic/actions/sendPreparedCalls.ts +69 -9
  85. package/src/isomorphic/utils/7702.ts +41 -14
  86. package/src/isomorphic/utils/createAccount.ts +115 -35
  87. package/src/isomorphic/utils/supportsFeature.ts +34 -0
  88. package/src/rpc/request.ts +1 -0
  89. package/src/schemas.ts +94 -3
  90. package/src/types.ts +4 -0
  91. package/src/utils.ts +2 -0
@@ -9,6 +9,7 @@ import {
9
9
  ChainNotFoundError,
10
10
  custom,
11
11
  fromHex,
12
+ hashMessage,
12
13
  toHex,
13
14
  type Chain,
14
15
  type Transport,
@@ -17,7 +18,7 @@ import type { wallet_prepareCalls } from "../../rpc/request.js";
17
18
  import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
18
19
  import { createAccount } from "../utils/createAccount.js";
19
20
  import { createDummySigner } from "../utils/createDummySigner.js";
20
- import { createAuthorizationRequest, parseDelegation } from "../utils/7702.js";
21
+ import { createAuthorizationRequest, isDelegated } from "../utils/7702.js";
21
22
  import { InvalidRequestError } from "ox/RpcResponse";
22
23
  import { assertNever } from "../../utils.js";
23
24
  import { assertValid7702AccountAddress } from "../utils/7702.js";
@@ -50,20 +51,23 @@ export async function prepareCalls(
50
51
  assertValid7702AccountAddress(params.from, params.capabilities?.eip7702Auth);
51
52
 
52
53
  // in local mode, we probably want some kind of caching for this
53
- const { counterfactualInfo, delegation } = params.capabilities?.eip7702Auth
54
- ? {
55
- counterfactualInfo: undefined,
56
- delegation: parseDelegation(params.capabilities.eip7702Auth),
57
- }
58
- : await client.request({
59
- method: "wallet_requestAccount",
60
- params: [
61
- {
54
+ const { counterfactualInfo, delegation } = await client.request({
55
+ method: "wallet_requestAccount",
56
+ params: [
57
+ params.capabilities?.eip7702Auth
58
+ ? {
59
+ signerAddress: params.from,
60
+ creationHint: {
61
+ accountType: "7702",
62
+ },
63
+ includeCounterfactualInfo: true,
64
+ }
65
+ : {
62
66
  accountAddress: params.from,
63
67
  includeCounterfactualInfo: true,
64
68
  },
65
- ],
66
- });
69
+ ],
70
+ });
67
71
 
68
72
  if (!counterfactualInfo && !delegation) {
69
73
  throw new InvalidRequestError({
@@ -82,13 +86,26 @@ export async function prepareCalls(
82
86
  delegation,
83
87
  });
84
88
 
85
- // If using 7702, we need an Authorization (unless it's already authorized).
86
- const authorizationRequest = delegation
87
- ? await createAuthorizationRequest(client, {
88
- address: account.address,
89
- delegation,
90
- })
91
- : undefined;
89
+ const authorizationRequest =
90
+ delegation &&
91
+ !(await isDelegated(client, {
92
+ address: account.address,
93
+ delegation,
94
+ }))
95
+ ? await createAuthorizationRequest(client, {
96
+ address: account.address,
97
+ delegation,
98
+ })
99
+ : undefined;
100
+
101
+ if (params.capabilities?.permissions && authorizationRequest) {
102
+ // The user shouldn't see this in most cases since we require
103
+ // the account to be delegated before creating the session.
104
+ throw new InvalidRequestError({
105
+ message:
106
+ "When using a 7702 account with a session key, the account must be delegated before preparing calls.",
107
+ });
108
+ }
92
109
 
93
110
  if (authorizationRequest) {
94
111
  // @ts-expect-error - this is available but not typed as public
@@ -104,7 +121,12 @@ export async function prepareCalls(
104
121
  value: x.value ? fromHex(x.value, "bigint") : undefined,
105
122
  })),
106
123
  account,
107
- overrides: params.capabilities?.gasParamsOverride,
124
+ overrides: {
125
+ ...params.capabilities?.gasParamsOverride,
126
+ nonceKey: params.capabilities?.nonceOverride?.nonceKey
127
+ ? fromHex(params.capabilities.nonceOverride.nonceKey, "bigint")
128
+ : undefined,
129
+ },
108
130
  });
109
131
 
110
132
  // The eip7702Auth field should never be included in the UO sig
@@ -117,6 +139,8 @@ export async function prepareCalls(
117
139
 
118
140
  const ep = account.getEntryPoint();
119
141
 
142
+ const uoHash = ep.getUserOperationHash(hexlifiedUo);
143
+
120
144
  const uoRequest = {
121
145
  type:
122
146
  ep.version === "0.7.0"
@@ -129,8 +153,11 @@ export async function prepareCalls(
129
153
  signatureRequest: {
130
154
  type: "personal_sign" as const,
131
155
  data: {
132
- raw: ep.getUserOperationHash(hexlifiedUo),
156
+ raw: uoHash,
133
157
  },
158
+ rawPayload: hashMessage({
159
+ raw: uoHash,
160
+ }),
134
161
  },
135
162
  };
136
163
 
@@ -85,6 +85,12 @@ export async function sendPreparedCalls(
85
85
  })
86
86
  : [params];
87
87
 
88
+ if (!userOps.length) {
89
+ throw new InvalidRequestError({
90
+ message: "Calls must include at least one user operation",
91
+ });
92
+ }
93
+
88
94
  const authorizations =
89
95
  params.type === "array"
90
96
  ? params.data.filter((it) => it.type === "authorization")
@@ -120,19 +126,73 @@ export async function sendPreparedCalls(
120
126
  ? parseSignature(decodeSignature(authorization.signature).data)
121
127
  : undefined;
122
128
  const uoSigHex = decodeSignature(userOp.signature).data;
129
+
130
+ const { counterfactualInfo, delegation } = await client.request({
131
+ method: "wallet_requestAccount",
132
+ params: [
133
+ {
134
+ accountAddress: userOp.data.sender,
135
+ includeCounterfactualInfo: true,
136
+ },
137
+ ],
138
+ });
139
+
140
+ if (!counterfactualInfo && !delegation) {
141
+ throw new InvalidRequestError({
142
+ message:
143
+ "No counterfactual info or delegated implementation address found.",
144
+ });
145
+ }
146
+
147
+ const factoryType = counterfactualInfo?.factoryType;
148
+
149
+ // build signature based on account type
150
+ const signature = (() => {
151
+ switch (factoryType) {
152
+ // light accounts
153
+ case "LightAccountV1.0.1":
154
+ case "LightAccountV1.0.2":
155
+ case "LightAccountV1.1.0":
156
+ case "MAv1.0.0-MultiOwner":
157
+ // For LAv1 and MAv1-MultiOwner, we always just pass the signature.
158
+ return uoSigHex;
159
+ case "LightAccountV2.0.0":
160
+ // for LAv2, we need to prepend the "SignatureType.EOA" byte.
161
+ // TODO: Once we support nested smart accounts, switch this byte depending on the signature type.
162
+ return concat(["0x00", uoSigHex]);
163
+ case undefined: // undefined defaults to sma-b
164
+ case "MAv2.0.0-sma-b":
165
+ // For sma-b, we need to handle deferred actions if needed and prepend the "Reserved
166
+ // Signature Segment" and "SignatureType.EOA" bytes
167
+ return deferredAction != null
168
+ ? concatHex([
169
+ `0x${deferredAction.slice(68)}`, // Cuts off stuff prepended to the digest (nonce, etc.).
170
+ "0xFF",
171
+ "0x00",
172
+ uoSigHex,
173
+ ])
174
+ : concat(["0xFF", "0x00", uoSigHex]);
175
+ case "LightAccountV2.0.0-MultiOwner":
176
+ // for LAv2-MultiOwner, we need to prepend the "SignatureType.EOA" byte
177
+ // TODO: Once we support nested smart accounts, switch this byte depending on the signature type, and add the smart account signer's address.
178
+ return concat(["0x00", uoSigHex]);
179
+ case "MAv2.0.0-ma-ssv":
180
+ case "MAv2.0.0-ma-webauthn":
181
+ case "MAv1.0.0-MultiSig":
182
+ case "unknown":
183
+ throw new InvalidRequestError({
184
+ message: `Unsupported factory type: ${factoryType}`,
185
+ });
186
+ default:
187
+ return assertNever(factoryType, "Unsupported factory type");
188
+ }
189
+ })();
190
+
123
191
  return client
124
192
  .sendRawUserOperation(
125
193
  {
126
194
  ...userOp.data,
127
- signature:
128
- deferredAction != null
129
- ? concatHex([
130
- `0x${deferredAction.slice(68)}`, // Cuts off stuff prepended to the digest (nonce, etc. that we had previously).
131
- "0xff",
132
- "0x00",
133
- uoSigHex,
134
- ])
135
- : concat(["0xFF", "0x00", uoSigHex]),
195
+ signature,
136
196
  eip7702Auth:
137
197
  idx === 0 && authorization && authSig
138
198
  ? {
@@ -6,14 +6,17 @@ import {
6
6
  type Chain,
7
7
  type Transport,
8
8
  isAddress,
9
+ hexToNumber,
9
10
  } from "viem";
10
11
  import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
11
12
  import { PreparedCall_Authorization } from "../../schemas.js";
12
13
  import type { Eip7702AuthCapability } from "../../capabilities/eip7702Auth.ts";
13
14
  import type { Static } from "@sinclair/typebox";
14
15
  import { InvalidRequestError } from "ox/RpcResponse";
16
+ import { hashAuthorization } from "viem/utils";
15
17
 
16
- export const createAuthorizationRequest = async (
18
+ /** Checks if an address is actively delegated on-chain. */
19
+ export const isDelegated = async (
17
20
  client: SmartAccountClient<
18
21
  Transport,
19
22
  Chain,
@@ -22,12 +25,22 @@ export const createAuthorizationRequest = async (
22
25
  WalletServerViemRpcSchema
23
26
  >,
24
27
  params: { address: Address; delegation: Address },
25
- ): Promise<Static<typeof PreparedCall_Authorization> | undefined> => {
28
+ ): Promise<boolean> => {
26
29
  const expectedCode = concatHex(["0xef0100", params.delegation]);
27
30
  const code = (await client.getCode({ address: params.address })) ?? "0x";
28
- if (code.toLowerCase() === expectedCode.toLowerCase()) {
29
- return undefined; // Already authorized.
30
- }
31
+ return code.toLowerCase() === expectedCode.toLowerCase();
32
+ };
33
+
34
+ export const createAuthorizationRequest = async (
35
+ client: SmartAccountClient<
36
+ Transport,
37
+ Chain,
38
+ SmartContractAccount | undefined,
39
+ Record<string, unknown>,
40
+ WalletServerViemRpcSchema
41
+ >,
42
+ params: { address: Address; delegation: Address },
43
+ ): Promise<Static<typeof PreparedCall_Authorization>> => {
31
44
  const data = {
32
45
  address: params.delegation,
33
46
  nonce: numberToHex(
@@ -42,6 +55,11 @@ export const createAuthorizationRequest = async (
42
55
  chainId: numberToHex(client.chain.id),
43
56
  signatureRequest: {
44
57
  type: "eip7702Auth" as const,
58
+ rawPayload: hashAuthorization({
59
+ chainId: client.chain.id,
60
+ nonce: hexToNumber(data.nonce),
61
+ address: params.delegation,
62
+ }),
45
63
  },
46
64
  };
47
65
  };
@@ -103,14 +121,23 @@ export const assertValid7702AccountAddress = (
103
121
  fromAddress: Address,
104
122
  eip7702AuthCapability: Static<typeof Eip7702AuthCapability> | undefined,
105
123
  ) => {
106
- if (
107
- eip7702AuthCapability &&
108
- typeof eip7702AuthCapability === "object" &&
109
- "account" in eip7702AuthCapability &&
110
- eip7702AuthCapability?.account !== fromAddress
111
- ) {
112
- throw new InvalidRequestError({
113
- message: `EIP-7702 delegation account ${eip7702AuthCapability.account} must match 'from' address ${fromAddress}.`,
114
- });
124
+ if (eip7702AuthCapability) {
125
+ if (
126
+ typeof eip7702AuthCapability === "object" &&
127
+ "account" in eip7702AuthCapability &&
128
+ eip7702AuthCapability?.account !== fromAddress
129
+ ) {
130
+ throw new InvalidRequestError({
131
+ message: `EIP-7702 delegation account ${eip7702AuthCapability.account} must match 'from' address ${fromAddress}.`,
132
+ });
133
+ }
134
+
135
+ const delegation = parseDelegation(eip7702AuthCapability);
136
+
137
+ if (!isSupportedDelegationAddress7702(delegation)) {
138
+ throw new InvalidRequestError({
139
+ message: `Unsupported 7702 delegation address: ${delegation}`,
140
+ });
141
+ }
115
142
  }
116
143
  };
@@ -1,17 +1,20 @@
1
1
  import type { SmartAccountSigner, SmartContractAccount } from "@aa-sdk/core";
2
2
  import {
3
+ createLightAccount,
3
4
  createModularAccountV2,
5
+ createMultiOwnerLightAccount,
6
+ createMultiOwnerModularAccount,
4
7
  type ModularAccountV2,
5
8
  } from "@account-kit/smart-contracts";
6
9
  import type { StaticDecode } from "@sinclair/typebox";
7
10
  import type { Address, Chain, Transport } from "viem";
8
- import { concatHex, hexToNumber } from "viem";
11
+ import { concatHex, hexToBigInt, hexToNumber, zeroAddress } from "viem";
9
12
  import type { TypeSerializedInitcode } from "../../schemas.js";
10
13
  import { parsePermissionsContext } from "./parsePermissionsContext.js";
11
14
  import { assertNever } from "../../utils.js";
12
15
  import { getAccountTypeForDelegationAddress7702 } from "./7702.js";
13
- import { InternalError } from "ox/RpcResponse";
14
16
  import { PermissionsCapability } from "../../capabilities/permissions/index.js";
17
+ import { InternalError, InvalidRequestError } from "ox/RpcResponse";
15
18
 
16
19
  type CreateAccountParams = {
17
20
  chain: Chain;
@@ -33,32 +36,8 @@ export async function createAccount(
33
36
  ): Promise<SmartContractAccount> {
34
37
  const { counterfactualInfo: ci, ...accountParams } = params;
35
38
 
36
- const mode = params.delegation ? "7702" : "default";
37
-
38
- if (mode === "default") {
39
- if (!ci) {
40
- throw new InternalError({
41
- message: "Counterfactual info not found",
42
- });
43
- }
44
- if (ci.factoryType !== "MAv2.0.0-sma-b") {
45
- throw new InternalError({
46
- message: `Factory type ${ci.factoryType} is not currently supported.`,
47
- });
48
- }
49
- } else if (mode === "7702") {
50
- const accountType = getAccountTypeForDelegationAddress7702(
51
- params.delegation!,
52
- );
53
- if (accountType !== "ModularAccountV2") {
54
- throw new InternalError({
55
- message: "7702 mode currently only supports ModularAccountV2",
56
- });
57
- }
58
- } else {
59
- assertNever(mode, "Unexpected mode in createAccount");
60
- }
61
-
39
+ // This throws if we pass a permission context and the account is not MA-v2
40
+ // TODO: test that this edge case is handled correctly
62
41
  const parsedContext = parsePermissionsContext(
63
42
  params.permissions,
64
43
  ci,
@@ -73,14 +52,91 @@ export async function createAccount(
73
52
  }
74
53
  : undefined;
75
54
 
76
- // TODO: clean this up to support different account types.
77
- return createModularAccountV2({
55
+ const mode = params.delegation ? "7702" : "default";
56
+
57
+ if (mode === "7702") {
58
+ const accountType = getAccountTypeForDelegationAddress7702(
59
+ params.delegation!,
60
+ );
61
+ if (accountType !== "ModularAccountV2") {
62
+ throw new Error("7702 mode currently only supports ModularAccountV2");
63
+ }
64
+ return createModularAccountV2({
65
+ ...accountParams,
66
+ signerEntity,
67
+ deferredAction: parsedContext?.deferredAction,
68
+ mode,
69
+ });
70
+ }
71
+
72
+ if (mode !== "default") {
73
+ return assertNever(mode, "Unexpected mode in createAccount");
74
+ }
75
+
76
+ // At this point, we are guaranteed to be in default mode, where ci
77
+ // (counterfactualInfo) must be defined
78
+
79
+ if (!ci) {
80
+ throw new InternalError({
81
+ message: "Counterfactual info not found",
82
+ });
83
+ }
84
+
85
+ const factoryType = ci.factoryType;
86
+ const commonParams = {
78
87
  ...accountParams,
79
- signerEntity,
80
- deferredAction: parsedContext?.deferredAction,
81
- initCode: ci ? concatHex([ci.factoryAddress, ci.factoryData]) : undefined,
82
- mode,
83
- });
88
+ initCode: concatHex([ci.factoryAddress, ci.factoryData]),
89
+ };
90
+
91
+ // Return the account created based on the factory type
92
+ switch (factoryType) {
93
+ case "MAv2.0.0-sma-b":
94
+ return createModularAccountV2({
95
+ ...commonParams,
96
+ signerEntity,
97
+ deferredAction: parsedContext?.deferredAction,
98
+ mode,
99
+ });
100
+ case "LightAccountV2.0.0":
101
+ return createLightAccount({
102
+ ...commonParams,
103
+ version: "v2.0.0",
104
+ });
105
+ case "LightAccountV1.0.1":
106
+ return createLightAccount({
107
+ ...commonParams,
108
+ version: "v1.0.1",
109
+ });
110
+ case "LightAccountV1.0.2":
111
+ return createLightAccount({
112
+ ...commonParams,
113
+ version: "v1.0.2",
114
+ });
115
+ case "LightAccountV1.1.0":
116
+ return createLightAccount({
117
+ ...commonParams,
118
+ version: "v1.1.0",
119
+ });
120
+ case "MAv1.0.0-MultiOwner":
121
+ return createMultiOwnerModularAccount({
122
+ ...commonParams,
123
+ });
124
+ case "LightAccountV2.0.0-MultiOwner":
125
+ return createMultiOwnerLightAccount({
126
+ ...commonParams,
127
+ version: "v2.0.0",
128
+ });
129
+ case "MAv1.0.0-MultiSig":
130
+ case "MAv2.0.0-ma-ssv":
131
+ case "MAv2.0.0-ma-webauthn":
132
+ case "unknown":
133
+ case undefined:
134
+ throw new InvalidRequestError({
135
+ message: `Account type currently unsupported: ${factoryType}`,
136
+ });
137
+ default:
138
+ return assertNever(factoryType, "Unsupported factory type");
139
+ }
84
140
  }
85
141
 
86
142
  export function isModularAccountV2(
@@ -88,3 +144,27 @@ export function isModularAccountV2(
88
144
  ): account is ModularAccountV2 {
89
145
  return account.source === "ModularAccountV2";
90
146
  }
147
+
148
+ // Performs basic checks on the initialOwners array and returns a new array with the signer address added if not present.
149
+ // Pulled from MAv1 support in Account Kit.
150
+ export function prepareInitialOwners(
151
+ initialOwners: Address[],
152
+ signerAddress: Address,
153
+ ): Address[] {
154
+ const preparedOwners = Array.from(
155
+ new Set([...initialOwners, signerAddress]),
156
+ ).sort((a, b) => {
157
+ const bigintA = hexToBigInt(a);
158
+ const bigintB = hexToBigInt(b);
159
+
160
+ return bigintA < bigintB ? -1 : bigintA > bigintB ? 1 : 0;
161
+ });
162
+
163
+ if (preparedOwners.some((x) => x === zeroAddress)) {
164
+ throw new InvalidRequestError({
165
+ message: "Initial owners cannot contain the zero address",
166
+ });
167
+ }
168
+
169
+ return preparedOwners;
170
+ }
@@ -0,0 +1,34 @@
1
+ import type { StaticDecode } from "@sinclair/typebox";
2
+ import type { TypeSerializedInitcode } from "../../schemas.ts";
3
+
4
+ export type Feature = "permissions";
5
+
6
+ type FactoryType = StaticDecode<typeof TypeSerializedInitcode>["factoryType"];
7
+
8
+ const supportedFeatures: Record<FactoryType, Feature[]> = {
9
+ "LightAccountV1.0.1": [],
10
+ "LightAccountV1.0.2": [],
11
+ "LightAccountV1.1.0": [],
12
+ "LightAccountV2.0.0": [],
13
+ "LightAccountV2.0.0-MultiOwner": [],
14
+ "MAv1.0.0-MultiOwner": [],
15
+ "MAv1.0.0-MultiSig": [],
16
+ "MAv2.0.0-sma-b": ["permissions"],
17
+ "MAv2.0.0-ma-ssv": ["permissions"],
18
+ "MAv2.0.0-ma-webauthn": [],
19
+ unknown: [],
20
+ };
21
+
22
+ export function supportsFeature(
23
+ counterfactualInfo: StaticDecode<typeof TypeSerializedInitcode>,
24
+ feature: Feature,
25
+ ): boolean {
26
+ const factorySupportedFeatures =
27
+ supportedFeatures[counterfactualInfo.factoryType];
28
+ if (factorySupportedFeatures === undefined) {
29
+ throw new Error(
30
+ "Unsupported FactoryType: " + counterfactualInfo.factoryType,
31
+ );
32
+ }
33
+ return factorySupportedFeatures.includes(feature);
34
+ }
@@ -218,6 +218,7 @@ export const wallet_createSession = Type.Object(
218
218
  }),
219
219
  ReturnType: Type.Object({
220
220
  sessionId: TypeHex(),
221
+ chainId: TypeHex(),
221
222
  signatureRequest: TypeTypedDataSignatureRequest,
222
223
  }),
223
224
  },
package/src/schemas.ts CHANGED
@@ -16,6 +16,7 @@ import {
16
16
  parseSignature,
17
17
  numberToHex,
18
18
  } from "viem";
19
+ import type { Expect } from "./utils.ts";
19
20
 
20
21
  const UUID_V4_REGEX =
21
22
  /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
@@ -24,6 +25,22 @@ FormatRegistry.Set("uuid", (value) => UUID_V4_REGEX.test(value));
24
25
  const BASE_64_URL_REGEX = /^[A-Za-z0-9_-]+$/; // Matches base64url encoded strings (without padding)
25
26
  FormatRegistry.Set("base64url", (value) => BASE_64_URL_REGEX.test(value));
26
27
 
28
+ export const baseAccountTypes = [
29
+ "sma-b",
30
+ "la-v2",
31
+ "la-v2-multi-owner",
32
+ "la-v1.0.1",
33
+ "la-v1.0.2",
34
+ "la-v1.1.0",
35
+ "ma-v1-multi-owner",
36
+ ] as const;
37
+
38
+ export type BaseAccountType = (typeof baseAccountTypes)[number];
39
+
40
+ export const accountTypes = [...baseAccountTypes, "7702"] as const;
41
+
42
+ export type AccountType = (typeof accountTypes)[number];
43
+
27
44
  export const TypeHex = (options?: SchemaOptions) =>
28
45
  Type.TemplateLiteral("0x${string}", {
29
46
  ...options,
@@ -275,7 +292,73 @@ export const TypeCreationOptions = Type.Optional(
275
292
  salt: Type.Optional(TypeHex()),
276
293
  },
277
294
  {
278
- description: "SMA-B account type",
295
+ description: "Modular Account V2 SMA-B account type",
296
+ },
297
+ ),
298
+ Type.Object(
299
+ {
300
+ accountType: Type.Literal("la-v2"),
301
+ salt: Type.Optional(TypeHex()),
302
+ },
303
+ {
304
+ description: "Light Account V2 account type",
305
+ },
306
+ ),
307
+ Type.Object(
308
+ {
309
+ accountType: Type.Literal("la-v2-multi-owner"),
310
+ salt: Type.Optional(TypeHex()),
311
+ initialOwners: Type.Optional(
312
+ Type.Array(TypeAddress, {
313
+ description:
314
+ "The initial owners of the account. The signer address will be implicitly added if not specified in this list.",
315
+ }),
316
+ ),
317
+ },
318
+ {
319
+ description: "Light Account V2 Multi-Owner account type",
320
+ },
321
+ ),
322
+ Type.Object(
323
+ {
324
+ accountType: Type.Literal("la-v1.0.1"),
325
+ salt: Type.Optional(TypeHex()),
326
+ },
327
+ {
328
+ description: "Light Account V1.0.1 account type",
329
+ },
330
+ ),
331
+ Type.Object(
332
+ {
333
+ accountType: Type.Literal("la-v1.0.2"),
334
+ salt: Type.Optional(TypeHex()),
335
+ },
336
+ {
337
+ description: "Light Account V1.0.2 account type",
338
+ },
339
+ ),
340
+ Type.Object(
341
+ {
342
+ accountType: Type.Literal("la-v1.1.0"),
343
+ salt: Type.Optional(TypeHex()),
344
+ },
345
+ {
346
+ description: "Light Account V1.1.0 account type",
347
+ },
348
+ ),
349
+ Type.Object(
350
+ {
351
+ accountType: Type.Literal("ma-v1-multi-owner"),
352
+ salt: Type.Optional(TypeHex()),
353
+ initialOwners: Type.Optional(
354
+ Type.Array(TypeAddress, {
355
+ description:
356
+ "The initial owners of the account. The signer address will be implicitly added if not specified in this list.",
357
+ }),
358
+ ),
359
+ },
360
+ {
361
+ description: "Modular Account V1 Multi-Owner account type",
279
362
  },
280
363
  ),
281
364
  Type.Object(
@@ -295,10 +378,15 @@ export const TypeCreationOptions = Type.Optional(
295
378
  );
296
379
  export type TypeCreationOptions = Static<typeof TypeCreationOptions>;
297
380
 
298
- export type TypeAccountType = Exclude<
381
+ type BaseAccountTypeExhaustive = BaseAccountType extends Exclude<
299
382
  Static<typeof TypeCreationOptions>,
300
383
  undefined
301
- >["accountType"];
384
+ >["accountType"]
385
+ ? true
386
+ : "BaseAccountType values not fully covered in TypeCreationOptions";
387
+
388
+ // Compile-time assertion that TypeCreationOptions covers all BaseAccountType values.
389
+ type _AssertBaseAccountTypeExhaustive = Expect<BaseAccountTypeExhaustive>;
302
390
 
303
391
  export const TypeSignatureType = Type.Union([
304
392
  Type.Literal("secp256k1", { description: "Secp256k1" }),
@@ -371,6 +459,7 @@ export const TypePersonalSignSignatureRequest = Type.Object(
371
459
  { description: "Raw message" },
372
460
  ),
373
461
  ]),
462
+ rawPayload: TypeHex(),
374
463
  },
375
464
  { description: "Personal sign" },
376
465
  );
@@ -379,6 +468,7 @@ export const TypeTypedDataSignatureRequest = Type.Object(
379
468
  {
380
469
  type: Type.Literal("eth_signTypedData_v4"),
381
470
  data: TTypedDataDefinition,
471
+ rawPayload: TypeHex(),
382
472
  },
383
473
  {
384
474
  description: "Typed data",
@@ -387,6 +477,7 @@ export const TypeTypedDataSignatureRequest = Type.Object(
387
477
 
388
478
  export const TypeAuthorizationSignatureRequest = Type.Object({
389
479
  type: Type.Literal("eip7702Auth"),
480
+ rawPayload: TypeHex(),
390
481
  });
391
482
 
392
483
  export const TypeSignatureRequest = Type.Union([
package/src/types.ts CHANGED
@@ -60,3 +60,7 @@ export type InnerWalletApiClient = InnerWalletApiClientBase<
60
60
  export type WithoutChainId<T> = T extends { chainId: Hex }
61
61
  ? Omit<T, "chainId">
62
62
  : T;
63
+
64
+ export type WithoutRawPayload<T> = T extends { rawPayload: Hex }
65
+ ? Omit<T, "rawPayload">
66
+ : T;