@alchemy/wallet-apis 0.0.0-alpha.14 → 0.0.0-alpha.16

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 (92) hide show
  1. package/dist/esm/actions/grantPermissions.js +9 -2
  2. package/dist/esm/actions/grantPermissions.js.map +1 -1
  3. package/dist/esm/actions/listAccounts.d.ts +10 -2
  4. package/dist/esm/actions/listAccounts.js +23 -2
  5. package/dist/esm/actions/listAccounts.js.map +1 -1
  6. package/dist/esm/actions/requestAccount.d.ts +10 -3
  7. package/dist/esm/actions/requestAccount.js +43 -15
  8. package/dist/esm/actions/requestAccount.js.map +1 -1
  9. package/dist/esm/actions/sendCalls.d.ts +4 -0
  10. package/dist/esm/actions/sendCalls.js +26 -4
  11. package/dist/esm/actions/sendCalls.js.map +1 -1
  12. package/dist/esm/actions/sendPreparedCalls.js +2 -0
  13. package/dist/esm/actions/sendPreparedCalls.js.map +1 -1
  14. package/dist/esm/actions/signMessage.js +5 -1
  15. package/dist/esm/actions/signMessage.js.map +1 -1
  16. package/dist/esm/actions/signPreparedCalls.js +6 -1
  17. package/dist/esm/actions/signPreparedCalls.js.map +1 -1
  18. package/dist/esm/actions/signSignatureRequest.d.ts +10 -3
  19. package/dist/esm/actions/signSignatureRequest.js +93 -42
  20. package/dist/esm/actions/signSignatureRequest.js.map +1 -1
  21. package/dist/esm/actions/signTypedData.js +5 -1
  22. package/dist/esm/actions/signTypedData.js.map +1 -1
  23. package/dist/esm/client.d.ts +4 -4
  24. package/dist/esm/client.js +3 -13
  25. package/dist/esm/client.js.map +1 -1
  26. package/dist/esm/types.d.ts +4 -7
  27. package/dist/esm/types.js.map +1 -1
  28. package/dist/esm/utils/assertions.d.ts +6 -2
  29. package/dist/esm/utils/assertions.js +9 -0
  30. package/dist/esm/utils/assertions.js.map +1 -1
  31. package/dist/esm/utils/capabilities.d.ts +13 -4
  32. package/dist/esm/utils/capabilities.js +37 -11
  33. package/dist/esm/utils/capabilities.js.map +1 -1
  34. package/dist/esm/utils/format.d.ts +3 -1
  35. package/dist/esm/utils/format.js +11 -1
  36. package/dist/esm/utils/format.js.map +1 -1
  37. package/dist/esm/utils/signer.d.ts +10 -0
  38. package/dist/esm/utils/signer.js +28 -0
  39. package/dist/esm/utils/signer.js.map +1 -0
  40. package/dist/esm/utils/viemDecode.d.ts +1 -1
  41. package/dist/esm/utils/viemDecode.js.map +1 -1
  42. package/dist/esm/utils/viemEncode.js.map +1 -1
  43. package/dist/esm/version.d.ts +1 -1
  44. package/dist/esm/version.js +1 -1
  45. package/dist/esm/version.js.map +1 -1
  46. package/dist/types/actions/grantPermissions.d.ts.map +1 -1
  47. package/dist/types/actions/listAccounts.d.ts +10 -2
  48. package/dist/types/actions/listAccounts.d.ts.map +1 -1
  49. package/dist/types/actions/requestAccount.d.ts +10 -3
  50. package/dist/types/actions/requestAccount.d.ts.map +1 -1
  51. package/dist/types/actions/sendCalls.d.ts +4 -0
  52. package/dist/types/actions/sendCalls.d.ts.map +1 -1
  53. package/dist/types/actions/sendPreparedCalls.d.ts.map +1 -1
  54. package/dist/types/actions/signMessage.d.ts.map +1 -1
  55. package/dist/types/actions/signPreparedCalls.d.ts.map +1 -1
  56. package/dist/types/actions/signSignatureRequest.d.ts +10 -3
  57. package/dist/types/actions/signSignatureRequest.d.ts.map +1 -1
  58. package/dist/types/actions/signTypedData.d.ts.map +1 -1
  59. package/dist/types/client.d.ts +4 -4
  60. package/dist/types/client.d.ts.map +1 -1
  61. package/dist/types/types.d.ts +4 -7
  62. package/dist/types/types.d.ts.map +1 -1
  63. package/dist/types/utils/assertions.d.ts +6 -2
  64. package/dist/types/utils/assertions.d.ts.map +1 -1
  65. package/dist/types/utils/capabilities.d.ts +13 -4
  66. package/dist/types/utils/capabilities.d.ts.map +1 -1
  67. package/dist/types/utils/format.d.ts +3 -1
  68. package/dist/types/utils/format.d.ts.map +1 -1
  69. package/dist/types/utils/signer.d.ts +11 -0
  70. package/dist/types/utils/signer.d.ts.map +1 -0
  71. package/dist/types/utils/viemDecode.d.ts +1 -1
  72. package/dist/types/utils/viemDecode.d.ts.map +1 -1
  73. package/dist/types/version.d.ts +1 -1
  74. package/package.json +7 -6
  75. package/src/actions/grantPermissions.ts +13 -2
  76. package/src/actions/listAccounts.ts +39 -5
  77. package/src/actions/requestAccount.ts +67 -22
  78. package/src/actions/sendCalls.ts +40 -4
  79. package/src/actions/sendPreparedCalls.ts +3 -0
  80. package/src/actions/signMessage.ts +8 -0
  81. package/src/actions/signPreparedCalls.ts +14 -1
  82. package/src/actions/signSignatureRequest.ts +165 -54
  83. package/src/actions/signTypedData.ts +8 -0
  84. package/src/client.ts +5 -23
  85. package/src/types.ts +5 -5
  86. package/src/utils/assertions.ts +21 -2
  87. package/src/utils/capabilities.ts +56 -15
  88. package/src/utils/format.ts +20 -1
  89. package/src/utils/signer.ts +36 -0
  90. package/src/utils/viemDecode.ts +1 -1
  91. package/src/utils/viemEncode.ts +1 -1
  92. package/src/version.ts +1 -1
@@ -6,11 +6,21 @@ import type {
6
6
  Eip7702UnsignedAuth,
7
7
  } from "@alchemy/wallet-api-types";
8
8
  import { vToYParity } from "ox/Signature";
9
- import type { InnerWalletApiClient, WithoutRawPayload } from "../types";
10
- import { assertNever } from "@alchemy/common";
9
+ import type {
10
+ InnerWalletApiClient,
11
+ SignerClient,
12
+ WithoutRawPayload,
13
+ } from "../types";
14
+ import { assertNever, BaseError } from "@alchemy/common";
15
+ import { LOGGER } from "../logger.js";
16
+ import { isLocalAccount, isWebAuthnAccount } from "../utils/assertions.js";
11
17
  import { getAction } from "viem/utils";
12
18
  import { signAuthorization, signMessage, signTypedData } from "viem/actions";
13
- import { LOGGER } from "../logger.js";
19
+ import type {
20
+ WebAuthnSignReturnType,
21
+ WebAuthnAccount,
22
+ } from "viem/account-abstraction";
23
+ import type { LocalAccount } from "viem";
14
24
 
15
25
  export type SignSignatureRequestParams = Prettify<
16
26
  WithoutRawPayload<
@@ -22,16 +32,27 @@ export type SignSignatureRequestParams = Prettify<
22
32
  >
23
33
  >;
24
34
 
25
- export type SignSignatureRequestResult = Prettify<{
26
- type: "secp256k1";
27
- data: Hex;
28
- }>;
35
+ export type SignSignatureRequestResult =
36
+ | {
37
+ type: "secp256k1";
38
+ data: Hex;
39
+ }
40
+ | {
41
+ type: "webauthn-p256";
42
+ data: {
43
+ signature: Hex;
44
+ metadata: Pick<
45
+ WebAuthnSignReturnType["webauthn"],
46
+ "clientDataJSON" | "authenticatorData"
47
+ >;
48
+ };
49
+ };
29
50
 
30
51
  /**
31
52
  * Signs a signature request using the provided signer.
32
53
  * This method handles different types of signature requests including personal_sign, eth_signTypedData_v4, and authorization.
33
54
  *
34
- * @param {SmartAccountSigner} signer - The signer to use for signing the request
55
+ * @param {InnerWalletApiClient} client - The wallet client to use for signing
35
56
  * @param {SignSignatureRequestParams} params - The signature request parameters
36
57
  * @param {string} params.type - The type of signature request ('personal_sign', 'eth_signTypedData_v4', or 'signature_with_authorization')
37
58
  * @param {SignSignatureRequestParams["data"]} params.data - The data to sign, format depends on the signature type
@@ -63,73 +84,163 @@ export async function signSignatureRequest(
63
84
  params: SignSignatureRequestParams,
64
85
  ): Promise<SignSignatureRequestResult> {
65
86
  LOGGER.debug("signSignatureRequest:start", { type: params.type });
66
- const actions = {
67
- signMessage: getAction(client.owner, signMessage, "signMessage"),
68
- signTypedData: getAction(client.owner, signTypedData, "signTypedData"),
69
- signAuthorization: getAction(
70
- client.owner,
71
- signAuthorization,
72
- "signAuthorization",
73
- ),
74
- };
75
87
 
88
+ if (isWebAuthnAccount(client.owner)) {
89
+ return signWithWebAuthn(client.owner, params);
90
+ }
91
+
92
+ if (isLocalAccount(client.owner)) {
93
+ return signWithLocalAccount(client.owner, params);
94
+ }
95
+
96
+ return signWithSignerClient(client.owner, params);
97
+ }
98
+
99
+ // ─────────────────────────────────────────────────────────────────────────────
100
+ // WebAuthn signer
101
+ // ─────────────────────────────────────────────────────────────────────────────
102
+
103
+ type WebAuthnResult = Extract<
104
+ SignSignatureRequestResult,
105
+ { type: "webauthn-p256" }
106
+ >;
107
+
108
+ async function signWithWebAuthn(
109
+ signer: WebAuthnAccount,
110
+ params: SignSignatureRequestParams,
111
+ ): Promise<WebAuthnResult> {
76
112
  switch (params.type) {
77
113
  case "personal_sign": {
78
- const res = {
79
- type: "secp256k1",
80
- data: await actions.signMessage({
81
- message: params.data,
82
- account: client.owner.account,
83
- }),
84
- } as const;
85
- LOGGER.debug("signSignatureRequest:personal_sign:ok");
86
- return res;
114
+ const { signature, webauthn: metadata } = await signer.signMessage({
115
+ message: params.data,
116
+ });
117
+ LOGGER.debug("signSignatureRequest:webauthn:personal_sign:ok");
118
+ return { type: "webauthn-p256", data: { signature, metadata } };
87
119
  }
88
120
  case "eth_signTypedData_v4": {
89
- const res = {
90
- type: "secp256k1",
91
- data: await actions.signTypedData({
92
- ...params.data,
93
- account: client.owner.account,
94
- }),
95
- } as const;
96
- LOGGER.debug("signSignatureRequest:typedData:ok");
97
- return res;
121
+ const { signature, webauthn: metadata } = await signer.signTypedData(
122
+ params.data,
123
+ );
124
+ LOGGER.debug("signSignatureRequest:webauthn:eth_signTypedData_v4:ok");
125
+ return { type: "webauthn-p256", data: { signature, metadata } };
126
+ }
127
+ case "eip7702Auth":
128
+ throw new BaseError(
129
+ "WebAuthn account cannot sign EIP-7702 authorization requests",
130
+ );
131
+ default:
132
+ LOGGER.warn("signSignatureRequest:unknown-type", {
133
+ type: (params as { type?: unknown }).type,
134
+ });
135
+ return assertNever(params, "Unexpected signature request type.");
136
+ }
137
+ }
138
+
139
+ // ─────────────────────────────────────────────────────────────────────────────
140
+ // LocalAccount signer
141
+ // ─────────────────────────────────────────────────────────────────────────────
142
+
143
+ type Secp256k1Result = Extract<
144
+ SignSignatureRequestResult,
145
+ { type: "secp256k1" }
146
+ >;
147
+
148
+ async function signWithLocalAccount(
149
+ signer: LocalAccount,
150
+ params: SignSignatureRequestParams,
151
+ ): Promise<Secp256k1Result> {
152
+ switch (params.type) {
153
+ case "personal_sign": {
154
+ const data = await signer.signMessage({ message: params.data });
155
+ LOGGER.debug("signSignatureRequest:localAccount:personal_sign:ok");
156
+ return { type: "secp256k1", data };
157
+ }
158
+ case "eth_signTypedData_v4": {
159
+ const data = await signer.signTypedData(params.data);
160
+ LOGGER.debug("signSignatureRequest:localAccount:eth_signTypedData_v4:ok");
161
+ return { type: "secp256k1", data };
98
162
  }
99
163
  case "eip7702Auth": {
164
+ if (!signer.signAuthorization) {
165
+ throw new BaseError(
166
+ "Current signer does not support signing authorization requests",
167
+ );
168
+ }
100
169
  const {
101
170
  r,
102
171
  s,
103
172
  v,
104
173
  yParity: _yParity,
105
- } = await actions.signAuthorization({
106
- ...{
107
- ...params.data,
108
- chainId: hexToNumber(params.data.chainId),
109
- nonce: hexToNumber(params.data.nonce),
110
- },
111
- account: client.owner.account,
174
+ } = await signer.signAuthorization({
175
+ address: params.data.address,
176
+ chainId: hexToNumber(params.data.chainId),
177
+ nonce: hexToNumber(params.data.nonce),
112
178
  });
113
- // yParity *should* already be a number, but some 3rd
114
- // party signers may mistakenly return it as a bigint.
115
179
  const yParity =
116
180
  _yParity != null ? Number(_yParity) : vToYParity(Number(v));
181
+ LOGGER.debug("signSignatureRequest:localAccount:eip7702Auth:ok");
182
+ return {
183
+ type: "secp256k1",
184
+ data: serializeSignature({ r, s, yParity }),
185
+ };
186
+ }
187
+ default:
188
+ LOGGER.warn("signSignatureRequest:unknown-type", {
189
+ type: (params as { type?: unknown }).type,
190
+ });
191
+ return assertNever(params, "Unexpected signature request type.");
192
+ }
193
+ }
117
194
 
118
- const res = {
195
+ // ─────────────────────────────────────────────────────────────────────────────
196
+ // SignerClient (WalletClient)
197
+ // ─────────────────────────────────────────────────────────────────────────────
198
+
199
+ async function signWithSignerClient(
200
+ signer: SignerClient,
201
+ params: SignSignatureRequestParams,
202
+ ): Promise<Secp256k1Result> {
203
+ switch (params.type) {
204
+ case "personal_sign": {
205
+ const action = getAction(signer, signMessage, "signMessage");
206
+ const data = await action({
207
+ message: params.data,
208
+ account: signer.account,
209
+ });
210
+ LOGGER.debug("signSignatureRequest:signerClient:personal_sign:ok");
211
+ return { type: "secp256k1", data };
212
+ }
213
+ case "eth_signTypedData_v4": {
214
+ const action = getAction(signer, signTypedData, "signTypedData");
215
+ const data = await action({ ...params.data, account: signer.account });
216
+ LOGGER.debug("signSignatureRequest:signerClient:eth_signTypedData_v4:ok");
217
+ return { type: "secp256k1", data };
218
+ }
219
+ case "eip7702Auth": {
220
+ const action = getAction(signer, signAuthorization, "signAuthorization");
221
+ const {
222
+ r,
223
+ s,
224
+ v,
225
+ yParity: _yParity,
226
+ } = await action({
227
+ address: params.data.address,
228
+ chainId: hexToNumber(params.data.chainId),
229
+ nonce: hexToNumber(params.data.nonce),
230
+ account: signer.account,
231
+ });
232
+ const yParity =
233
+ _yParity != null ? Number(_yParity) : vToYParity(Number(v));
234
+ LOGGER.debug("signSignatureRequest:signerClient:eip7702Auth:ok");
235
+ return {
119
236
  type: "secp256k1",
120
- data: serializeSignature({
121
- r,
122
- s,
123
- yParity,
124
- }),
125
- } as const;
126
- LOGGER.debug("signSignatureRequest:eip7702Auth:ok");
127
- return res;
237
+ data: serializeSignature({ r, s, yParity }),
238
+ };
128
239
  }
129
240
  default:
130
241
  LOGGER.warn("signSignatureRequest:unknown-type", {
131
242
  type: (params as { type?: unknown }).type,
132
243
  });
133
- return assertNever(params, `Unexpected signature request type.`);
244
+ return assertNever(params, "Unexpected signature request type.");
134
245
  }
135
246
  }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ BaseError,
2
3
  type Address,
3
4
  type Hex,
4
5
  type Prettify,
@@ -78,6 +79,13 @@ export async function signTypedData(
78
79
 
79
80
  const signed = await signSignatureRequest(client, prepared.signatureRequest);
80
81
 
82
+ // TODO: Wallet server needs to be updated to support webauthn here.
83
+ if (signed.type === "webauthn-p256") {
84
+ throw new BaseError(
85
+ "WebAuthn account is currently unsupported by wallet_formatSign",
86
+ );
87
+ }
88
+
81
89
  const formatted = await formatSign(client, {
82
90
  from: account.address,
83
91
  signature: {
package/src/client.ts CHANGED
@@ -1,20 +1,14 @@
1
- import {
2
- createClient,
3
- type Address,
4
- type Chain,
5
- type LocalAccount,
6
- createWalletClient,
7
- } from "viem";
1
+ import { createClient, type Address, type Chain } from "viem";
8
2
  import { smartWalletActions } from "./decorators/smartWalletActions.js";
9
3
  import { type AlchemyTransport } from "@alchemy/common";
10
- import type { SignerClient, SmartWalletClient } from "./types.js";
4
+ import type { SmartWalletClient, SmartWalletSigner } from "./types.js";
11
5
  import { createInternalState } from "./internal.js";
12
6
  import type { CreationOptionsBySignerAddress } from "@alchemy/wallet-api-types";
13
7
 
14
8
  export type CreateSmartWalletClientParams<
15
9
  TAccount extends Address | undefined = Address | undefined,
16
10
  > = {
17
- signer: LocalAccount | SignerClient;
11
+ signer: SmartWalletSigner;
18
12
  transport: AlchemyTransport;
19
13
  chain: Chain;
20
14
  account?: TAccount;
@@ -30,7 +24,7 @@ export type CreateSmartWalletClientParams<
30
24
  * Creates a smart wallet client with wallet API actions.
31
25
  *
32
26
  * @param {CreateSmartWalletClientParams} params - Parameters for creating the smart wallet client.
33
- * @param {LocalAccount | JsonRpcAccount} params.account - The account to use for signing.
27
+ * @param {SmartWalletSigner} params.account - The account to use for signing.
34
28
  * @param {AlchemyTransport} params.transport - The transport to use for RPC calls.
35
29
  * @param {Chain} params.chain - The blockchain network to connect to.
36
30
  * @param {string[]} params.policyIds - Optional policy IDs for paymaster service.
@@ -48,18 +42,6 @@ export const createSmartWalletClient = <
48
42
  }: CreateSmartWalletClientParams<TAccount>): SmartWalletClient<TAccount> => {
49
43
  const _policyIds = [...(policyId ? [policyId] : []), ...(policyIds ?? [])];
50
44
 
51
- // If the signer is a `LocalAccount` wrap it inside of a client now so
52
- // downstream actions can just use `getAction` to get signing actions
53
- // and `signerClient.account.address` to access the address.
54
- const signerClient =
55
- "request" in signer
56
- ? signer
57
- : createWalletClient({
58
- account: signer,
59
- transport,
60
- chain,
61
- });
62
-
63
45
  return createClient({
64
46
  account,
65
47
  transport,
@@ -69,7 +51,7 @@ export const createSmartWalletClient = <
69
51
  .extend(() => ({
70
52
  policyIds: _policyIds,
71
53
  internal: createInternalState(),
72
- owner: signerClient,
54
+ owner: signer,
73
55
  }))
74
56
  .extend(smartWalletActions<TAccount>);
75
57
  };
package/src/types.ts CHANGED
@@ -11,10 +11,12 @@ import type {
11
11
  Prettify,
12
12
  Transport,
13
13
  WalletClient,
14
+ LocalAccount,
14
15
  } from "viem";
15
16
  import type { InternalState } from "./internal";
16
17
  import type { SmartWalletClient1193Methods } from "./provider";
17
18
  import type { SmartWalletActions } from "./decorators/smartWalletActions";
19
+ import type { WebAuthnAccount } from "viem/account-abstraction";
18
20
 
19
21
  export type BaseWalletClient<
20
22
  TExtend extends { [key: string]: unknown } | undefined =
@@ -30,12 +32,14 @@ export type BaseWalletClient<
30
32
 
31
33
  export type InnerWalletApiClient = BaseWalletClient<{
32
34
  internal: InternalState | undefined; // undefined if you want to skip using an internal cache
33
- owner: SignerClient;
35
+ owner: SmartWalletSigner;
34
36
  policyIds?: string[];
35
37
  }>;
36
38
 
37
39
  export type SignerClient = WalletClient<Transport, Chain | undefined, Account>;
38
40
 
41
+ export type SmartWalletSigner = LocalAccount | WebAuthnAccount | SignerClient;
42
+
39
43
  export type SmartWalletClientEip1193Provider = Prettify<
40
44
  EIP1193Events & {
41
45
  request: EIP1193RequestFn<SmartWalletClient1193Methods>;
@@ -50,10 +54,6 @@ export type OptionalChainId<T> = T extends { chainId: Hex }
50
54
  ? Omit<T, "chainId"> & { chainId?: Hex | undefined }
51
55
  : T;
52
56
 
53
- export type OptionalSignerAddress<T> = T extends { signerAddress: Address }
54
- ? Omit<T, "signerAddress"> & { signerAddress?: Address | undefined }
55
- : T;
56
-
57
57
  export type WithoutRawPayload<T> = T extends { rawPayload: Hex }
58
58
  ? Omit<T, "rawPayload">
59
59
  : T;
@@ -1,6 +1,7 @@
1
- import type { Client } from "viem";
2
- import type { InnerWalletApiClient } from "../types.js";
1
+ import type { Client, LocalAccount } from "viem";
2
+ import type { InnerWalletApiClient, SignerClient } from "../types.js";
3
3
  import { BaseError } from "@alchemy/common";
4
+ import type { WebAuthnAccount } from "viem/account-abstraction";
4
5
 
5
6
  /**
6
7
  * Type guard function to check if a client is an Alchemy Smart Wallet Client.
@@ -30,3 +31,21 @@ export function assertSmartWalletClient(
30
31
  throw new BaseError(message);
31
32
  }
32
33
  }
34
+
35
+ export function isLocalAccount(
36
+ signer: LocalAccount | WebAuthnAccount | SignerClient,
37
+ ): signer is LocalAccount {
38
+ return signer.type === "local";
39
+ }
40
+
41
+ export function isWebAuthnAccount(
42
+ signer: LocalAccount | WebAuthnAccount | SignerClient,
43
+ ): signer is WebAuthnAccount {
44
+ return signer.type === "webAuthn";
45
+ }
46
+
47
+ export function isSignerClient(
48
+ signer: LocalAccount | WebAuthnAccount | SignerClient,
49
+ ): signer is SignerClient {
50
+ return "request" in signer;
51
+ }
@@ -1,24 +1,65 @@
1
- import type { Capabilities } from "@alchemy/wallet-api-types/capabilities";
1
+ import type {
2
+ PrepareCallsCapabilities,
3
+ SendPreparedCallsCapabilities,
4
+ } from "@alchemy/wallet-api-types/capabilities";
2
5
  import type { InnerWalletApiClient } from "../types.js";
3
6
 
4
7
  /**
5
8
  * Merges client capabilities with capabilities from the request.
9
+ * Uses policyId (singular) when there's one policy, policyIds (array) when multiple.
6
10
  *
7
11
  * @param {InnerWalletApiClient} client - The inner wallet API client (potentially including global capabilities like policy IDs)
8
- * @param {Capabilities | undefined} capabilities - Request capabilities to merge with, if any
9
- * @returns {Capabilities | undefined} The merged capabilities object, or original capabilities if no capability configuration exists on the client
12
+ * @param {T | undefined} capabilities - Request capabilities to merge with, if any
13
+ * @returns {T | undefined} The merged capabilities object, or original capabilities if no capability configuration exists on the client
10
14
  */
11
- export const mergeClientCapabilities = (
15
+ export const mergeClientCapabilities = <
16
+ T extends PrepareCallsCapabilities | SendPreparedCallsCapabilities,
17
+ >(
12
18
  client: InnerWalletApiClient,
13
- capabilities: Capabilities | undefined,
14
- ): Capabilities | undefined => {
15
- return client.policyIds?.length && !capabilities?.paymasterService
16
- ? {
17
- ...capabilities,
18
- paymasterService: {
19
- ...capabilities?.paymasterService,
20
- policyIds: client.policyIds,
21
- },
22
- }
23
- : capabilities;
19
+ capabilities: T | undefined,
20
+ ): T | undefined => {
21
+ if (!client.policyIds?.length || capabilities?.paymasterService) {
22
+ return capabilities;
23
+ }
24
+
25
+ return {
26
+ ...capabilities,
27
+ paymasterService:
28
+ client.policyIds.length === 1
29
+ ? { policyId: client.policyIds[0] }
30
+ : { policyIds: client.policyIds },
31
+ } as T;
32
+ };
33
+
34
+ /**
35
+ * Extracts capabilities from prepareCalls that are usable for sendPreparedCalls.
36
+ * Only permissions and paymasterService (policyId/policyIds & webhookData) are supported.
37
+ *
38
+ * @param {PrepareCallsCapabilities | undefined} capabilities - The prepareCalls capabilities
39
+ * @returns {SendPreparedCallsCapabilities | undefined} The sendPreparedCalls capabilities, or undefined if no relevant capabilities exist
40
+ */
41
+ export const extractCapabilitiesForSending = (
42
+ capabilities: PrepareCallsCapabilities | undefined,
43
+ ): SendPreparedCallsCapabilities | undefined => {
44
+ if (
45
+ capabilities?.permissions == null &&
46
+ capabilities?.paymasterService == null
47
+ ) {
48
+ return undefined;
49
+ }
50
+
51
+ const paymasterService = capabilities.paymasterService;
52
+
53
+ return {
54
+ permissions: capabilities.permissions,
55
+ paymasterService:
56
+ paymasterService != null
57
+ ? {
58
+ ...("policyId" in paymasterService
59
+ ? { policyId: paymasterService.policyId }
60
+ : { policyIds: paymasterService.policyIds }),
61
+ webhookData: paymasterService.webhookData,
62
+ }
63
+ : undefined,
64
+ };
24
65
  };
@@ -6,8 +6,13 @@ import {
6
6
  bytesToHex,
7
7
  type TypedDataDefinition,
8
8
  getTypesForEIP712Domain,
9
+ sliceHex,
9
10
  } from "viem";
10
- import type { TypedDataDefinition as WalletServerTypedDataDefinition } from "@alchemy/wallet-api-types";
11
+ import type {
12
+ TypedDataDefinition as WalletServerTypedDataDefinition,
13
+ WebAuthnPublicKey,
14
+ } from "@alchemy/wallet-api-types";
15
+ import type { ToWebAuthnAccountParameters } from "viem/account-abstraction";
11
16
 
12
17
  export const castToHex = (val: string | number | bigint | Hex): Hex => {
13
18
  if (isHex(val)) {
@@ -59,3 +64,17 @@ export const typedDataToJsonSafe = ({
59
64
  ),
60
65
  };
61
66
  };
67
+
68
+ export function credentialToWebAuthnPublicKey(
69
+ credential: ToWebAuthnAccountParameters["credential"],
70
+ ): WebAuthnPublicKey {
71
+ const { x, y } = {
72
+ x: sliceHex(credential.publicKey, 0, 32, { strict: true }),
73
+ y: sliceHex(credential.publicKey, 32, 64, { strict: true }),
74
+ };
75
+
76
+ return {
77
+ x,
78
+ y,
79
+ };
80
+ }
@@ -0,0 +1,36 @@
1
+ import { toHex, type Address } from "viem";
2
+ import type { SmartWalletSigner } from "../types";
3
+ import type { WebAuthnPublicKey } from "@alchemy/wallet-api-types";
4
+ import { parsePublicKey } from "webauthn-p256";
5
+
6
+ export function getSignerAddressOrPublicKey(
7
+ signer: SmartWalletSigner,
8
+ ):
9
+ | { type: "secp256k1"; address: Address }
10
+ | { type: "webauthn-p256"; publicKey: WebAuthnPublicKey } {
11
+ // SignerClient.
12
+ if ("request" in signer) {
13
+ return {
14
+ type: "secp256k1",
15
+ address: signer.account.address,
16
+ };
17
+ }
18
+
19
+ // LocalAccount.
20
+ if (signer.type === "local") {
21
+ return {
22
+ type: "secp256k1",
23
+ address: signer.address,
24
+ };
25
+ }
26
+
27
+ // WebAuthnAccount.
28
+ const key = parsePublicKey(signer.publicKey);
29
+ return {
30
+ type: "webauthn-p256",
31
+ publicKey: {
32
+ x: toHex(key.x),
33
+ y: toHex(key.y),
34
+ },
35
+ };
36
+ }
@@ -15,7 +15,7 @@ import type {
15
15
  PreparedCall_UserOpV060,
16
16
  PreparedCall_UserOpV070,
17
17
  } from "@alchemy/wallet-api-types";
18
- import type { Capabilities as WalletApiCapabilities } from "@alchemy/wallet-api-types/capabilities";
18
+ import type { PrepareCallsCapabilities as WalletApiCapabilities } from "@alchemy/wallet-api-types/capabilities";
19
19
  import type {
20
20
  ViemEncodedAuthorizationCall,
21
21
  ViemEncodedPaymasterPermitCall,
@@ -19,7 +19,7 @@ import type {
19
19
  PreparedCall_UserOpV060,
20
20
  PreparedCall_UserOpV070,
21
21
  } from "@alchemy/wallet-api-types";
22
- import type { Capabilities as WalletApiCapabilities } from "@alchemy/wallet-api-types/capabilities";
22
+ import type { PrepareCallsCapabilities as WalletApiCapabilities } from "@alchemy/wallet-api-types/capabilities";
23
23
 
24
24
  export type ViemEncodedPreparedCalls =
25
25
  | (ViemEncodedUserOperationCall | ViemEncodedPaymasterPermitCall)
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // This file is autogenerated by inject-version.ts. Any changes will be
2
2
  // overwritten on commit!
3
- export const VERSION = "0.0.0-alpha.14";
3
+ export const VERSION = "0.0.0-alpha.16";