@account-kit/wallet-client 0.1.0-alpha.4 → 0.1.0-alpha.6

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 (186) hide show
  1. package/dist/esm/capabilities/eip7702Auth.d.ts +4 -0
  2. package/dist/esm/capabilities/eip7702Auth.js +18 -0
  3. package/dist/esm/capabilities/eip7702Auth.js.map +1 -0
  4. package/dist/esm/capabilities/index.d.ts +4 -0
  5. package/dist/esm/capabilities/index.js +2 -0
  6. package/dist/esm/capabilities/index.js.map +1 -1
  7. package/dist/esm/capabilities/overrides.js +8 -8
  8. package/dist/esm/capabilities/overrides.js.map +1 -1
  9. package/dist/esm/capabilities/permissions/index.d.ts +2 -2
  10. package/dist/esm/capabilities/permissions/index.js +6 -3
  11. package/dist/esm/capabilities/permissions/index.js.map +1 -1
  12. package/dist/esm/capabilities/permissions/mav2.js +1 -0
  13. package/dist/esm/capabilities/permissions/mav2.js.map +1 -1
  14. package/dist/esm/client/actions/getCallsStatus.d.ts +1 -2
  15. package/dist/esm/client/actions/getCallsStatus.js +19 -0
  16. package/dist/esm/client/actions/getCallsStatus.js.map +1 -1
  17. package/dist/esm/client/actions/grantPermissions.d.ts +10 -65
  18. package/dist/esm/client/actions/grantPermissions.js +63 -4
  19. package/dist/esm/client/actions/grantPermissions.js.map +1 -1
  20. package/dist/esm/client/actions/prepareCalls.d.ts +4 -4
  21. package/dist/esm/client/actions/prepareCalls.js +38 -5
  22. package/dist/esm/client/actions/prepareCalls.js.map +1 -1
  23. package/dist/esm/client/actions/requestAccount.d.ts +3 -4
  24. package/dist/esm/client/actions/requestAccount.js +18 -1
  25. package/dist/esm/client/actions/requestAccount.js.map +1 -1
  26. package/dist/esm/client/actions/sendPreparedCalls.d.ts +6 -14
  27. package/dist/esm/client/actions/sendPreparedCalls.js +11 -12
  28. package/dist/esm/client/actions/sendPreparedCalls.js.map +1 -1
  29. package/dist/esm/client/actions/signMessage.d.ts +3 -3
  30. package/dist/esm/client/actions/signMessage.js +18 -0
  31. package/dist/esm/client/actions/signMessage.js.map +1 -1
  32. package/dist/esm/client/actions/signPreparedCalls.d.ts +14 -0
  33. package/dist/esm/client/actions/signPreparedCalls.js +53 -0
  34. package/dist/esm/client/actions/signPreparedCalls.js.map +1 -0
  35. package/dist/esm/client/actions/signSignatureRequest.d.ts +9 -8
  36. package/dist/esm/client/actions/signSignatureRequest.js +69 -31
  37. package/dist/esm/client/actions/signSignatureRequest.js.map +1 -1
  38. package/dist/esm/client/actions/signTypedData.d.ts +2 -2
  39. package/dist/esm/client/actions/signTypedData.js +31 -0
  40. package/dist/esm/client/actions/signTypedData.js.map +1 -1
  41. package/dist/esm/client/client.e2e-test.js +47 -44
  42. package/dist/esm/client/client.e2e-test.js.map +1 -1
  43. package/dist/esm/client/decorator.d.ts +7 -5
  44. package/dist/esm/client/decorator.js +3 -1
  45. package/dist/esm/client/decorator.js.map +1 -1
  46. package/dist/esm/client/index.d.ts +35 -10
  47. package/dist/esm/client/index.js +0 -29
  48. package/dist/esm/client/index.js.map +1 -1
  49. package/dist/esm/exports/index.d.ts +2 -1
  50. package/dist/esm/exports/index.js +2 -1
  51. package/dist/esm/exports/index.js.map +1 -1
  52. package/dist/esm/isomorphic/actions/createSession.js +15 -18
  53. package/dist/esm/isomorphic/actions/createSession.js.map +1 -1
  54. package/dist/esm/isomorphic/actions/getCallsStatus.js +62 -9
  55. package/dist/esm/isomorphic/actions/getCallsStatus.js.map +1 -1
  56. package/dist/esm/isomorphic/actions/prepareCalls.js +39 -26
  57. package/dist/esm/isomorphic/actions/prepareCalls.js.map +1 -1
  58. package/dist/esm/isomorphic/actions/sendPreparedCalls.d.ts +3 -3
  59. package/dist/esm/isomorphic/actions/sendPreparedCalls.js +77 -37
  60. package/dist/esm/isomorphic/actions/sendPreparedCalls.js.map +1 -1
  61. package/dist/esm/isomorphic/client.d.ts +139 -13
  62. package/dist/esm/isomorphic/utils/7702.d.ts +13 -6
  63. package/dist/esm/isomorphic/utils/7702.js +48 -13
  64. package/dist/esm/isomorphic/utils/7702.js.map +1 -1
  65. package/dist/esm/isomorphic/utils/createAccount.d.ts +2 -2
  66. package/dist/esm/isomorphic/utils/createAccount.js +4 -3
  67. package/dist/esm/isomorphic/utils/createAccount.js.map +1 -1
  68. package/dist/esm/isomorphic/utils/decodeSignature.d.ts +3 -0
  69. package/dist/esm/isomorphic/utils/decodeSignature.js +13 -0
  70. package/dist/esm/isomorphic/utils/decodeSignature.js.map +1 -0
  71. package/dist/esm/isomorphic/utils/parsePermissionsContext.d.ts +2 -2
  72. package/dist/esm/isomorphic/utils/parsePermissionsContext.js +8 -7
  73. package/dist/esm/isomorphic/utils/parsePermissionsContext.js.map +1 -1
  74. package/dist/esm/local/client.d.ts +2 -2
  75. package/dist/esm/local/client.js +2 -3
  76. package/dist/esm/local/client.js.map +1 -1
  77. package/dist/esm/remote/client.d.ts +8 -2
  78. package/dist/esm/remote/client.js +3 -13
  79. package/dist/esm/remote/client.js.map +1 -1
  80. package/dist/esm/rpc/examples.d.ts +3 -3
  81. package/dist/esm/rpc/examples.js +3 -3
  82. package/dist/esm/rpc/examples.js.map +1 -1
  83. package/dist/esm/rpc/request.d.ts +362 -44
  84. package/dist/esm/rpc/request.js +26 -56
  85. package/dist/esm/rpc/request.js.map +1 -1
  86. package/dist/esm/rpc/schema.d.ts +325 -49
  87. package/dist/esm/rpc/schema.js.map +1 -1
  88. package/dist/esm/schemas.d.ts +454 -14
  89. package/dist/esm/schemas.js +168 -53
  90. package/dist/esm/schemas.js.map +1 -1
  91. package/dist/esm/types.d.ts +10 -10
  92. package/dist/esm/types.js.map +1 -1
  93. package/dist/types/capabilities/eip7702Auth.d.ts +5 -0
  94. package/dist/types/capabilities/eip7702Auth.d.ts.map +1 -0
  95. package/dist/types/capabilities/index.d.ts +4 -0
  96. package/dist/types/capabilities/index.d.ts.map +1 -1
  97. package/dist/types/capabilities/permissions/index.d.ts +2 -2
  98. package/dist/types/capabilities/permissions/index.d.ts.map +1 -1
  99. package/dist/types/capabilities/permissions/mav2.d.ts.map +1 -1
  100. package/dist/types/client/actions/getCallsStatus.d.ts +1 -2
  101. package/dist/types/client/actions/getCallsStatus.d.ts.map +1 -1
  102. package/dist/types/client/actions/grantPermissions.d.ts +10 -65
  103. package/dist/types/client/actions/grantPermissions.d.ts.map +1 -1
  104. package/dist/types/client/actions/prepareCalls.d.ts +4 -4
  105. package/dist/types/client/actions/prepareCalls.d.ts.map +1 -1
  106. package/dist/types/client/actions/requestAccount.d.ts +3 -4
  107. package/dist/types/client/actions/requestAccount.d.ts.map +1 -1
  108. package/dist/types/client/actions/sendPreparedCalls.d.ts +6 -14
  109. package/dist/types/client/actions/sendPreparedCalls.d.ts.map +1 -1
  110. package/dist/types/client/actions/signMessage.d.ts +3 -3
  111. package/dist/types/client/actions/signMessage.d.ts.map +1 -1
  112. package/dist/types/client/actions/signPreparedCalls.d.ts +15 -0
  113. package/dist/types/client/actions/signPreparedCalls.d.ts.map +1 -0
  114. package/dist/types/client/actions/signSignatureRequest.d.ts +9 -8
  115. package/dist/types/client/actions/signSignatureRequest.d.ts.map +1 -1
  116. package/dist/types/client/actions/signTypedData.d.ts +2 -2
  117. package/dist/types/client/actions/signTypedData.d.ts.map +1 -1
  118. package/dist/types/client/decorator.d.ts +7 -5
  119. package/dist/types/client/decorator.d.ts.map +1 -1
  120. package/dist/types/client/index.d.ts +35 -10
  121. package/dist/types/client/index.d.ts.map +1 -1
  122. package/dist/types/exports/index.d.ts +2 -1
  123. package/dist/types/exports/index.d.ts.map +1 -1
  124. package/dist/types/isomorphic/actions/createSession.d.ts.map +1 -1
  125. package/dist/types/isomorphic/actions/getCallsStatus.d.ts.map +1 -1
  126. package/dist/types/isomorphic/actions/prepareCalls.d.ts.map +1 -1
  127. package/dist/types/isomorphic/actions/sendPreparedCalls.d.ts +3 -3
  128. package/dist/types/isomorphic/actions/sendPreparedCalls.d.ts.map +1 -1
  129. package/dist/types/isomorphic/client.d.ts +139 -13
  130. package/dist/types/isomorphic/client.d.ts.map +1 -1
  131. package/dist/types/isomorphic/utils/7702.d.ts +13 -6
  132. package/dist/types/isomorphic/utils/7702.d.ts.map +1 -1
  133. package/dist/types/isomorphic/utils/createAccount.d.ts +2 -2
  134. package/dist/types/isomorphic/utils/createAccount.d.ts.map +1 -1
  135. package/dist/types/isomorphic/utils/decodeSignature.d.ts +4 -0
  136. package/dist/types/isomorphic/utils/decodeSignature.d.ts.map +1 -0
  137. package/dist/types/isomorphic/utils/parsePermissionsContext.d.ts +2 -2
  138. package/dist/types/isomorphic/utils/parsePermissionsContext.d.ts.map +1 -1
  139. package/dist/types/local/client.d.ts +2 -2
  140. package/dist/types/local/client.d.ts.map +1 -1
  141. package/dist/types/remote/client.d.ts +8 -2
  142. package/dist/types/remote/client.d.ts.map +1 -1
  143. package/dist/types/rpc/examples.d.ts +3 -3
  144. package/dist/types/rpc/examples.d.ts.map +1 -1
  145. package/dist/types/rpc/request.d.ts +362 -44
  146. package/dist/types/rpc/request.d.ts.map +1 -1
  147. package/dist/types/rpc/schema.d.ts +325 -49
  148. package/dist/types/rpc/schema.d.ts.map +1 -1
  149. package/dist/types/schemas.d.ts +454 -14
  150. package/dist/types/schemas.d.ts.map +1 -1
  151. package/dist/types/types.d.ts +10 -10
  152. package/dist/types/types.d.ts.map +1 -1
  153. package/package.json +2 -2
  154. package/src/capabilities/eip7702Auth.ts +26 -0
  155. package/src/capabilities/index.ts +2 -0
  156. package/src/capabilities/overrides.ts +8 -8
  157. package/src/capabilities/permissions/index.ts +8 -3
  158. package/src/capabilities/permissions/mav2.ts +1 -0
  159. package/src/client/actions/getCallsStatus.ts +0 -10
  160. package/src/client/actions/grantPermissions.ts +16 -84
  161. package/src/client/actions/prepareCalls.ts +18 -23
  162. package/src/client/actions/requestAccount.ts +9 -26
  163. package/src/client/actions/sendPreparedCalls.ts +17 -17
  164. package/src/client/actions/signMessage.ts +2 -17
  165. package/src/client/actions/signPreparedCalls.ts +71 -0
  166. package/src/client/actions/signSignatureRequest.ts +51 -47
  167. package/src/client/actions/signTypedData.ts +1 -16
  168. package/src/client/client.e2e-test.ts +54 -57
  169. package/src/client/decorator.ts +19 -15
  170. package/src/client/index.ts +16 -39
  171. package/src/exports/index.ts +2 -1
  172. package/src/isomorphic/actions/createSession.ts +17 -20
  173. package/src/isomorphic/actions/getCallsStatus.ts +82 -10
  174. package/src/isomorphic/actions/prepareCalls.ts +43 -27
  175. package/src/isomorphic/actions/sendPreparedCalls.ts +105 -55
  176. package/src/isomorphic/utils/7702.ts +79 -21
  177. package/src/isomorphic/utils/createAccount.ts +5 -5
  178. package/src/isomorphic/utils/decodeSignature.ts +18 -0
  179. package/src/isomorphic/utils/parsePermissionsContext.ts +9 -9
  180. package/src/local/client.ts +5 -11
  181. package/src/remote/client.ts +7 -22
  182. package/src/rpc/examples.ts +3 -4
  183. package/src/rpc/request.ts +41 -64
  184. package/src/rpc/schema.ts +2 -2
  185. package/src/schemas.ts +232 -54
  186. package/src/types.ts +9 -21
@@ -6,6 +6,7 @@ import type { Static } from "@sinclair/typebox";
6
6
  import { Value } from "@sinclair/typebox/value";
7
7
  import {
8
8
  ChainNotFoundError,
9
+ hexToNumber,
9
10
  isHex,
10
11
  type Chain,
11
12
  type Hex,
@@ -16,6 +17,21 @@ import type { wallet_getCallsStatus } from "../../rpc/request.js";
16
17
  import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
17
18
  import { TypeCallId } from "../../schemas.js";
18
19
  import { castToHex } from "../../utils.js";
20
+ import { InternalError, BaseError } from "ox/RpcResponse";
21
+ import {
22
+ polygon,
23
+ mainnet,
24
+ base,
25
+ worldchain,
26
+ optimism,
27
+ arbitrum,
28
+ sepolia,
29
+ polygonAmoy,
30
+ baseSepolia,
31
+ optimismSepolia,
32
+ worldchainSepolia,
33
+ arbitrumSepolia,
34
+ } from "viem/chains";
19
35
 
20
36
  export type GetCallsStatusParams = Static<
21
37
  (typeof wallet_getCallsStatus)["properties"]["Request"]["properties"]["params"]
@@ -44,6 +60,29 @@ export const CallStatusCode = {
44
60
  PARTIAL_CHAIN_RULES_FAILURE: 600,
45
61
  } as const;
46
62
 
63
+ // https://eips.ethereum.org/EIPS/eip-5792#error-codes
64
+ const ErrorCode = {
65
+ UNKNOWN_BUNDLE_ID: 5730,
66
+ };
67
+
68
+ // "eth_getUserOperationByHash" is limited to the last 150 blocks
69
+ // for all networks except those in this list.
70
+ // https://www.alchemy.com/docs/node/bundler-api/bundler-api-endpoints/eth-get-user-operation-by-hash
71
+ const GET_USER_OP_BY_HASH_UNLIMITED_RANGE_NETWORKS: number[] = [
72
+ mainnet.id,
73
+ sepolia.id,
74
+ polygon.id,
75
+ polygonAmoy.id,
76
+ base.id,
77
+ baseSepolia.id,
78
+ optimism.id,
79
+ optimismSepolia.id,
80
+ worldchain.id,
81
+ worldchainSepolia.id,
82
+ arbitrum.id,
83
+ arbitrumSepolia.id,
84
+ ];
85
+
47
86
  export async function getCallsStatus(
48
87
  client: SmartAccountClient<
49
88
  Transport,
@@ -57,21 +96,54 @@ export async function getCallsStatus(
57
96
  if (!client.chain) {
58
97
  throw new ChainNotFoundError();
59
98
  }
60
-
61
99
  const { chainId, hash } = Value.Decode(TypeCallId, callId);
62
100
 
63
- const result = await client.getUserOperationReceipt(hash);
64
-
65
- return {
101
+ const baseResp = {
66
102
  id: callId,
67
103
  chainId,
68
104
  atomic: true,
69
- status: !result?.receipt
70
- ? CallStatusCode.PENDING
71
- : result.success
72
- ? CallStatusCode.CONFIRMED
73
- : CallStatusCode.CHAIN_RULES_FAILURE,
74
- receipts: !result?.receipt ? undefined : [transformReceipt(result.receipt)],
105
+ };
106
+
107
+ const result = await client.getUserOperationByHash(hash);
108
+ if (
109
+ !result &&
110
+ GET_USER_OP_BY_HASH_UNLIMITED_RANGE_NETWORKS.includes(hexToNumber(chainId))
111
+ ) {
112
+ // This network has unlimited range, so we should always have a result here if the callId is valid.
113
+ throw new BaseError({
114
+ message: `callId ${callId} not found`,
115
+ code: ErrorCode.UNKNOWN_BUNDLE_ID,
116
+ });
117
+ }
118
+ if (result && !result.transactionHash) {
119
+ // A result but no txn hash means it's valid but pending.
120
+ return {
121
+ ...baseResp,
122
+ status: CallStatusCode.PENDING,
123
+ };
124
+ }
125
+
126
+ const receipt = await client.getUserOperationReceipt(hash);
127
+ if (result?.transactionHash && !receipt) {
128
+ // This should never happen.
129
+ throw new InternalError({
130
+ message: `Failed to get receipt for callId ${callId}`,
131
+ });
132
+ }
133
+ if (!receipt) {
134
+ // This covers txns older than 150 blocks which were not retrievable by "eth_getUserOperationByHash".
135
+ throw new BaseError({
136
+ message: `callId ${callId} not found`,
137
+ code: ErrorCode.UNKNOWN_BUNDLE_ID,
138
+ });
139
+ }
140
+
141
+ return {
142
+ ...baseResp,
143
+ status: receipt.success
144
+ ? CallStatusCode.CONFIRMED
145
+ : CallStatusCode.CHAIN_RULES_FAILURE,
146
+ receipts: [transformReceipt(receipt.receipt)],
75
147
  };
76
148
  }
77
149
 
@@ -17,8 +17,10 @@ import type { wallet_prepareCalls } from "../../rpc/request.js";
17
17
  import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
18
18
  import { createAccount } from "../utils/createAccount.js";
19
19
  import { createDummySigner } from "../utils/createDummySigner.js";
20
- import { createAuthorization } from "../utils/7702.js";
20
+ import { createAuthorizationRequest, parseDelegation } from "../utils/7702.js";
21
21
  import { InvalidRequestError } from "ox/RpcResponse";
22
+ import { assertNever } from "../../utils.js";
23
+ import { assertValid7702AccountAddress } from "../utils/7702.js";
22
24
 
23
25
  export type PrepareCallsParams = Omit<
24
26
  Static<
@@ -45,16 +47,23 @@ export async function prepareCalls(
45
47
  throw new ChainNotFoundError();
46
48
  }
47
49
 
50
+ assertValid7702AccountAddress(params.from, params.capabilities?.eip7702Auth);
51
+
48
52
  // in local mode, we probably want some kind of caching for this
49
- const { counterfactualInfo, delegation } = await client.request({
50
- method: "wallet_requestAccount",
51
- params: [
52
- {
53
- accountAddress: params.from,
54
- includeCounterfactualInfo: true,
55
- },
56
- ],
57
- });
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
+ {
62
+ accountAddress: params.from,
63
+ includeCounterfactualInfo: true,
64
+ },
65
+ ],
66
+ });
58
67
 
59
68
  if (!counterfactualInfo && !delegation) {
60
69
  throw new InvalidRequestError({
@@ -69,13 +78,13 @@ export async function prepareCalls(
69
78
  signer: createDummySigner(params.from),
70
79
  accountAddress: params.from,
71
80
  counterfactualInfo,
72
- capabilities: params.capabilities,
81
+ permissions: params.capabilities?.permissions,
73
82
  delegation,
74
83
  });
75
84
 
76
85
  // If using 7702, we need an Authorization (unless it's already authorized).
77
86
  const authorizationRequest = delegation
78
- ? await createAuthorization(client, {
87
+ ? await createAuthorizationRequest(client, {
79
88
  address: account.address,
80
89
  delegation,
81
90
  })
@@ -99,29 +108,36 @@ export async function prepareCalls(
99
108
  });
100
109
 
101
110
  // The eip7702Auth field should never be included in the UO sig
102
- // request. It's handled by the separate authorization request.
111
+ // request. It's handled by a separate authorization request.
103
112
  if ("eip7702Auth" in builtUo) {
104
113
  builtUo.eip7702Auth = undefined;
105
114
  }
106
- const uoRequest = deepHexlify(builtUo);
107
115
 
108
- const signatureRequest = {
109
- type: "personal_sign" as const,
110
- data: {
111
- raw: account.getEntryPoint().getUserOperationHash(uoRequest),
112
- },
113
- };
116
+ const hexlifiedUo = deepHexlify(builtUo);
117
+
118
+ const ep = account.getEntryPoint();
114
119
 
115
- return {
120
+ const uoRequest = {
116
121
  type:
117
- account.getEntryPoint().version === "0.7.0"
118
- ? "user-operation-v070"
119
- : "user-operation-v060",
120
- data: uoRequest,
122
+ ep.version === "0.7.0"
123
+ ? ("user-operation-v070" as const)
124
+ : ep.version === "0.6.0"
125
+ ? ("user-operation-v060" as const)
126
+ : assertNever(ep.version, "Unexpected entry point version"),
127
+ data: hexlifiedUo,
121
128
  chainId: toHex(client.chain.id),
122
129
  signatureRequest: {
123
- ...signatureRequest,
124
- ...(authorizationRequest ? { authorizationRequest } : {}),
130
+ type: "personal_sign" as const,
131
+ data: {
132
+ raw: ep.getUserOperationHash(hexlifiedUo),
133
+ },
125
134
  },
126
135
  };
136
+
137
+ return authorizationRequest
138
+ ? {
139
+ type: "array" as const,
140
+ data: [authorizationRequest, uoRequest],
141
+ }
142
+ : uoRequest;
127
143
  }
@@ -3,31 +3,33 @@ import {
3
3
  type SmartAccountClient,
4
4
  type SmartContractAccount,
5
5
  } from "@aa-sdk/core";
6
- import type { Static, StaticDecode } from "@sinclair/typebox";
7
6
  import { Value } from "@sinclair/typebox/value";
8
7
  import {
9
8
  BaseError,
10
9
  ChainNotFoundError,
11
10
  concat,
12
11
  concatHex,
12
+ numberToHex,
13
+ parseSignature,
13
14
  toHex,
15
+ type Address,
14
16
  type Chain,
15
17
  type Hex,
16
18
  type Transport,
17
19
  } from "viem";
18
20
  import { decodePermissionsContext } from "../../capabilities/permissions/mav2.js";
19
- import type { wallet_sendPreparedCalls } from "../../rpc/request.js";
21
+ import { type wallet_sendPreparedCalls } from "../../rpc/request.js";
20
22
  import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
21
23
  import { TypeCallId } from "../../schemas.js";
22
- import { isSupportedImplementationAddress7702 } from "../utils/7702.js";
24
+ import { isSupportedDelegationAddress7702 } from "../utils/7702.js";
23
25
  import { InvalidRequestError } from "ox/RpcResponse";
26
+ import { assertNever } from "../../utils.js";
27
+ import type { Static } from "@sinclair/typebox";
28
+ import { decodeSignature } from "../utils/decodeSignature.js";
24
29
 
25
- export type SendPreparedCallsParams = Omit<
26
- StaticDecode<
27
- (typeof wallet_sendPreparedCalls)["properties"]["Request"]["properties"]["params"]
28
- >[0],
29
- "chainId"
30
- >;
30
+ export type SendPreparedCallsParams = Static<
31
+ (typeof wallet_sendPreparedCalls)["properties"]["Request"]["properties"]["params"]
32
+ >[0];
31
33
 
32
34
  export type SendPreparedCallsResult = Static<
33
35
  (typeof wallet_sendPreparedCalls)["properties"]["ReturnType"]
@@ -48,16 +50,6 @@ export async function sendPreparedCalls(
48
50
  throw new ChainNotFoundError();
49
51
  }
50
52
 
51
- // One last safety check to be sure the UO wasn't modified to include an unsupported 7702 delegation address.
52
- if (
53
- params.signedAuthorization &&
54
- !isSupportedImplementationAddress7702(params.signedAuthorization.address)
55
- ) {
56
- throw new InvalidRequestError({
57
- message: `Unsupported 7702 delegation address: ${params.signedAuthorization.address}`,
58
- });
59
- }
60
-
61
53
  const deferredAction: Hex | undefined = (() => {
62
54
  if (!params.capabilities?.permissions) {
63
55
  return;
@@ -77,46 +69,104 @@ export async function sendPreparedCalls(
77
69
  return decodedContext.deferredAction;
78
70
  })();
79
71
 
80
- const entryPoint =
81
- params.type === "user-operation-v060"
82
- ? getEntryPoint(client.chain, { version: "0.6.0" })
83
- : getEntryPoint(client.chain, { version: "0.7.0" });
72
+ const userOps =
73
+ params.type === "array"
74
+ ? params.data.filter((it) => {
75
+ const isUserOp =
76
+ it.type === "user-operation-v060" ||
77
+ it.type === "user-operation-v070";
78
+ if (isUserOp && it.chainId !== toHex(client.chain.id)) {
79
+ throw new InvalidRequestError({
80
+ message:
81
+ "Multiple chain IDs in a single request are not currently supported.",
82
+ });
83
+ }
84
+ return isUserOp;
85
+ })
86
+ : [params];
87
+
88
+ const authorizations =
89
+ params.type === "array"
90
+ ? params.data.filter((it) => it.type === "authorization")
91
+ : [];
84
92
 
85
- const hash = await client
86
- .sendRawUserOperation(
87
- {
88
- ...params.data,
89
- signature:
90
- deferredAction != null
91
- ? concatHex([
92
- `0x${deferredAction.slice(68)}`, // Cuts off stuff preprended to the digest (nonce, etc. that we had previously).
93
- "0xff",
94
- "0x00",
95
- params.signature.signature,
96
- ])
97
- : concat(["0xFF", "0x00", params.signature.signature]),
98
- eip7702Auth: params.signedAuthorization,
99
- },
100
- entryPoint.address,
101
- )
102
- .catch((err) => {
103
- if (
104
- err instanceof BaseError &&
105
- err.details.endsWith("is not a contract and initCode is empty")
106
- ) {
107
- throw new BaseError(
108
- `${err.details} (If using 7702, be sure you include the 'signedAuthorization' field in the request parameters)`,
109
- );
110
- }
111
- throw err;
93
+ if (authorizations.length > 1) {
94
+ throw new InvalidRequestError({
95
+ message:
96
+ "Multiple authorizations in a single request are not currently supported",
112
97
  });
98
+ }
99
+ const [authorization] = authorizations;
100
+
101
+ // One last safety check to be sure the UO wasn't modified to include an unsupported 7702 delegation address.
102
+ if (
103
+ authorization &&
104
+ !isSupportedDelegationAddress7702(authorization.data.address)
105
+ ) {
106
+ throw new InvalidRequestError({
107
+ message: `Unsupported 7702 delegation address: ${authorization.data.address}`,
108
+ });
109
+ }
113
110
 
114
- const callId = Value.Encode(TypeCallId, {
115
- chainId: toHex(client.chain.id),
116
- hash,
117
- });
111
+ const hashes = await Promise.all(
112
+ userOps.map(async (userOp, idx) => {
113
+ const ep: { address: Address } =
114
+ userOp.type === "user-operation-v060"
115
+ ? getEntryPoint(client.chain, { version: "0.6.0" })
116
+ : userOp.type === "user-operation-v070"
117
+ ? getEntryPoint(client.chain, { version: "0.7.0" })
118
+ : assertNever(userOp, "Unexpected user op type");
119
+ const authSig = authorization
120
+ ? parseSignature(decodeSignature(authorization.signature).data)
121
+ : undefined;
122
+ const uoSigHex = decodeSignature(userOp.signature).data;
123
+ return client
124
+ .sendRawUserOperation(
125
+ {
126
+ ...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]),
136
+ eip7702Auth:
137
+ idx === 0 && authorization && authSig
138
+ ? {
139
+ ...authorization.data,
140
+ chainId: authorization.chainId,
141
+ ...{
142
+ ...authSig,
143
+ yParity: numberToHex(authSig.yParity),
144
+ },
145
+ }
146
+ : undefined,
147
+ },
148
+ ep.address,
149
+ )
150
+ .catch((err) => {
151
+ if (
152
+ err instanceof BaseError &&
153
+ err.details.endsWith("is not a contract and initCode is empty")
154
+ ) {
155
+ throw new BaseError(
156
+ `${err.details} (If using 7702, be sure you include the signed authorization in the request parameters)`,
157
+ );
158
+ }
159
+ throw err;
160
+ });
161
+ }),
162
+ );
118
163
 
119
164
  return {
120
- preparedCallIds: [callId],
165
+ preparedCallIds: hashes.map((hash) =>
166
+ Value.Encode(TypeCallId, {
167
+ chainId: toHex(client.chain.id),
168
+ hash,
169
+ }),
170
+ ),
121
171
  };
122
172
  }
@@ -1,14 +1,19 @@
1
1
  import type { SmartAccountClient, SmartContractAccount } from "@aa-sdk/core";
2
2
  import {
3
3
  concatHex,
4
- type Authorization,
4
+ numberToHex,
5
5
  type Address,
6
6
  type Chain,
7
7
  type Transport,
8
+ isAddress,
8
9
  } from "viem";
9
10
  import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
11
+ import { PreparedCall_Authorization } from "../../schemas.js";
12
+ import type { Eip7702AuthCapability } from "../../capabilities/eip7702Auth.ts";
13
+ import type { Static } from "@sinclair/typebox";
14
+ import { InvalidRequestError } from "ox/RpcResponse";
10
15
 
11
- export const createAuthorization = async (
16
+ export const createAuthorizationRequest = async (
12
17
  client: SmartAccountClient<
13
18
  Transport,
14
19
  Chain,
@@ -17,42 +22,95 @@ export const createAuthorization = async (
17
22
  WalletServerViemRpcSchema
18
23
  >,
19
24
  params: { address: Address; delegation: Address },
20
- ): Promise<Authorization<number, false> | undefined> => {
25
+ ): Promise<Static<typeof PreparedCall_Authorization> | undefined> => {
21
26
  const expectedCode = concatHex(["0xef0100", params.delegation]);
22
27
  const code = (await client.getCode({ address: params.address })) ?? "0x";
23
28
  if (code.toLowerCase() === expectedCode.toLowerCase()) {
24
29
  return undefined; // Already authorized.
25
30
  }
26
- return {
27
- chainId: client.chain.id,
31
+ const data = {
28
32
  address: params.delegation,
29
- nonce: await client.getTransactionCount({
30
- address: params.address,
31
- }),
33
+ nonce: numberToHex(
34
+ await client.getTransactionCount({
35
+ address: params.address,
36
+ }),
37
+ ),
38
+ };
39
+ return {
40
+ type: "authorization" as const,
41
+ data,
42
+ chainId: numberToHex(client.chain.id),
43
+ signatureRequest: {
44
+ type: "eip7702Auth" as const,
45
+ },
32
46
  };
33
47
  };
34
48
 
35
- type Supported7702AccountType = "ModularAccountV2";
49
+ export const EIP_7702_ACCOUNT_TYPE = ["ModularAccountV2"] as const;
50
+
51
+ type Supported7702AccountType = (typeof EIP_7702_ACCOUNT_TYPE)[number];
36
52
 
37
- const IMPLEMENTATION_ADDRESS_TO_ACCOUNT_TYPE: Record<
53
+ const Eip7702AccountTypeToDelegationAddress = {
54
+ ModularAccountV2: "0x69007702764179f14F51cdce752f4f775d74E139",
55
+ } as const satisfies Record<Supported7702AccountType, Address>;
56
+
57
+ const DelegationAddressToAccountType: Record<
38
58
  Address,
39
59
  Supported7702AccountType
40
- > = {
41
- "0x69007702764179f14F51cdce752f4f775d74E139": "ModularAccountV2",
60
+ > = Object.fromEntries(
61
+ Object.entries(Eip7702AccountTypeToDelegationAddress).map(([key, value]) => [
62
+ value,
63
+ key,
64
+ ]),
65
+ ) as Record<Address, Supported7702AccountType>;
66
+
67
+ export const SUPPORTED_DELEGATION_ADDRESSES = Object.values(
68
+ Eip7702AccountTypeToDelegationAddress,
69
+ );
70
+
71
+ export const isSupportedDelegationAddress7702 = (address: Address): boolean => {
72
+ return (SUPPORTED_DELEGATION_ADDRESSES as Address[]).includes(address);
42
73
  };
43
74
 
44
- export const getAccountTypeForImplementationAddress7702 = (
75
+ export const getAccountTypeForDelegationAddress7702 = (
45
76
  address: Address,
46
77
  ): Supported7702AccountType | undefined => {
47
- return IMPLEMENTATION_ADDRESS_TO_ACCOUNT_TYPE[address];
78
+ return DelegationAddressToAccountType[address];
48
79
  };
49
80
 
50
- const SUPPORTED_IMPLEMENTATION_ADDRESSES = Object.keys(
51
- IMPLEMENTATION_ADDRESS_TO_ACCOUNT_TYPE,
52
- );
81
+ const getDelegationAddressForAccountType7702 = (
82
+ accountType: Supported7702AccountType,
83
+ ): (typeof SUPPORTED_DELEGATION_ADDRESSES)[number] => {
84
+ return Eip7702AccountTypeToDelegationAddress[accountType];
85
+ };
86
+
87
+ const DEFAULT_7702_DELEGATION_ADDR =
88
+ Eip7702AccountTypeToDelegationAddress["ModularAccountV2"];
53
89
 
54
- export const isSupportedImplementationAddress7702 = (
55
- address: string,
56
- ): boolean => {
57
- return SUPPORTED_IMPLEMENTATION_ADDRESSES.includes(address);
90
+ export const parseDelegation = (
91
+ eip7702AuthCapability: Static<typeof Eip7702AuthCapability>,
92
+ ) => {
93
+ return eip7702AuthCapability === true
94
+ ? DEFAULT_7702_DELEGATION_ADDR
95
+ : isAddress(eip7702AuthCapability.delegation)
96
+ ? eip7702AuthCapability.delegation
97
+ : getDelegationAddressForAccountType7702(
98
+ eip7702AuthCapability.delegation,
99
+ );
100
+ };
101
+
102
+ export const assertValid7702AccountAddress = (
103
+ fromAddress: Address,
104
+ eip7702AuthCapability: Static<typeof Eip7702AuthCapability> | undefined,
105
+ ) => {
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
+ });
115
+ }
58
116
  };
@@ -6,12 +6,12 @@ import {
6
6
  import type { StaticDecode } from "@sinclair/typebox";
7
7
  import type { Address, Chain, Transport } from "viem";
8
8
  import { concatHex, hexToNumber } from "viem";
9
- import type { Capabilities } from "../../capabilities/index.js";
10
9
  import type { TypeSerializedInitcode } from "../../schemas.js";
11
10
  import { parsePermissionsContext } from "./parsePermissionsContext.js";
12
11
  import { assertNever } from "../../utils.js";
13
- import { getAccountTypeForImplementationAddress7702 } from "./7702.js";
12
+ import { getAccountTypeForDelegationAddress7702 } from "./7702.js";
14
13
  import { InternalError } from "ox/RpcResponse";
14
+ import { PermissionsCapability } from "../../capabilities/permissions/index.js";
15
15
 
16
16
  type CreateAccountParams = {
17
17
  chain: Chain;
@@ -19,8 +19,8 @@ type CreateAccountParams = {
19
19
  signer: SmartAccountSigner;
20
20
  accountAddress: Address;
21
21
  counterfactualInfo?: StaticDecode<typeof TypeSerializedInitcode>; // undefined for 7702 accounts
22
+ permissions?: StaticDecode<typeof PermissionsCapability>;
22
23
  delegation?: Address;
23
- capabilities?: StaticDecode<typeof Capabilities>;
24
24
  };
25
25
 
26
26
  /**
@@ -47,7 +47,7 @@ export async function createAccount(
47
47
  });
48
48
  }
49
49
  } else if (mode === "7702") {
50
- const accountType = getAccountTypeForImplementationAddress7702(
50
+ const accountType = getAccountTypeForDelegationAddress7702(
51
51
  params.delegation!,
52
52
  );
53
53
  if (accountType !== "ModularAccountV2") {
@@ -60,7 +60,7 @@ export async function createAccount(
60
60
  }
61
61
 
62
62
  const parsedContext = parsePermissionsContext(
63
- params.capabilities,
63
+ params.permissions,
64
64
  ci,
65
65
  params.delegation,
66
66
  );
@@ -0,0 +1,18 @@
1
+ import { Value } from "@sinclair/typebox/value";
2
+ import type { Static, StaticDecode } from "@sinclair/typebox";
3
+ import { TypeEcdsaSig } from "../../schemas.js";
4
+ import { assertNever } from "../../utils.js";
5
+
6
+ export const decodeSignature = (
7
+ signature: Static<typeof TypeEcdsaSig>["signature"],
8
+ ): StaticDecode<typeof TypeEcdsaSig>["signature"] => {
9
+ switch (signature.type) {
10
+ case "ecdsa":
11
+ case "secp256k1":
12
+ return Value.Decode(TypeEcdsaSig, { signature } satisfies Static<
13
+ typeof TypeEcdsaSig
14
+ >).signature;
15
+ default:
16
+ return assertNever(signature, "Unexpected signature type");
17
+ }
18
+ };
@@ -2,33 +2,33 @@ import type { StaticDecode } from "@sinclair/typebox";
2
2
  import { InvalidRequestError } from "ox/RpcResponse";
3
3
  import { decodePermissionsContext } from "../../capabilities/permissions/mav2.js";
4
4
  import type { TypeSerializedInitcode } from "../../schemas.js";
5
- import type { PrepareCallsParams } from "../actions/prepareCalls.js";
6
5
  import type { Address } from "viem";
7
- import { getAccountTypeForImplementationAddress7702 } from "./7702.js";
6
+ import { getAccountTypeForDelegationAddress7702 } from "./7702.js";
7
+ import { PermissionsCapability } from "../../capabilities/permissions/index.js";
8
8
 
9
9
  export function parsePermissionsContext(
10
- capabilities: PrepareCallsParams["capabilities"],
11
- parsedCi: StaticDecode<typeof TypeSerializedInitcode> | undefined,
10
+ permissions?: StaticDecode<typeof PermissionsCapability>,
11
+ parsedCi?: StaticDecode<typeof TypeSerializedInitcode> | undefined,
12
12
  delegation7702?: Address,
13
13
  ) {
14
- if (!capabilities?.permissions) {
14
+ if (!permissions) {
15
15
  return undefined;
16
16
  }
17
17
 
18
- if ("sessionId" in capabilities.permissions) {
18
+ if ("sessionId" in permissions) {
19
19
  throw new InvalidRequestError({
20
20
  message: "Remote permissions are not supported in isomorphic client",
21
21
  });
22
22
  }
23
23
 
24
- if (!("context" in capabilities.permissions)) {
24
+ if (!("context" in permissions)) {
25
25
  return undefined;
26
26
  }
27
27
 
28
28
  const isMAV2 =
29
29
  (parsedCi && parsedCi.factoryType === "MAv2.0.0-sma-b") ||
30
30
  (delegation7702 &&
31
- getAccountTypeForImplementationAddress7702(delegation7702) ===
31
+ getAccountTypeForDelegationAddress7702(delegation7702) ===
32
32
  "ModularAccountV2");
33
33
 
34
34
  if (!isMAV2) {
@@ -37,7 +37,7 @@ export function parsePermissionsContext(
37
37
  });
38
38
  }
39
39
 
40
- const context = decodePermissionsContext(capabilities.permissions);
40
+ const context = decodePermissionsContext(permissions);
41
41
 
42
42
  if (context?.contextVersion === "REMOTE_MODE_DEFERRED_ACTION") {
43
43
  throw new InvalidRequestError({