@alchemy/wallet-apis 0.0.0-alpha.12

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 (182) hide show
  1. package/LICENSE +21 -0
  2. package/dist/esm/actions/formatSign.d.ts +35 -0
  3. package/dist/esm/actions/formatSign.js +38 -0
  4. package/dist/esm/actions/formatSign.js.map +1 -0
  5. package/dist/esm/actions/grantPermissions.d.ts +73 -0
  6. package/dist/esm/actions/grantPermissions.js +87 -0
  7. package/dist/esm/actions/grantPermissions.js.map +1 -0
  8. package/dist/esm/actions/listAccounts.d.ts +40 -0
  9. package/dist/esm/actions/listAccounts.js +43 -0
  10. package/dist/esm/actions/listAccounts.js.map +1 -0
  11. package/dist/esm/actions/prepareCalls.d.ts +44 -0
  12. package/dist/esm/actions/prepareCalls.js +58 -0
  13. package/dist/esm/actions/prepareCalls.js.map +1 -0
  14. package/dist/esm/actions/prepareSign.d.ts +33 -0
  15. package/dist/esm/actions/prepareSign.js +41 -0
  16. package/dist/esm/actions/prepareSign.js.map +1 -0
  17. package/dist/esm/actions/requestAccount.d.ts +33 -0
  18. package/dist/esm/actions/requestAccount.js +67 -0
  19. package/dist/esm/actions/requestAccount.js.map +1 -0
  20. package/dist/esm/actions/sendCalls.d.ts +34 -0
  21. package/dist/esm/actions/sendCalls.js +49 -0
  22. package/dist/esm/actions/sendCalls.js.map +1 -0
  23. package/dist/esm/actions/sendPreparedCalls.d.ts +43 -0
  24. package/dist/esm/actions/sendPreparedCalls.js +50 -0
  25. package/dist/esm/actions/sendPreparedCalls.js.map +1 -0
  26. package/dist/esm/actions/signMessage.d.ts +27 -0
  27. package/dist/esm/actions/signMessage.js +51 -0
  28. package/dist/esm/actions/signMessage.js.map +1 -0
  29. package/dist/esm/actions/signPreparedCalls.d.ts +32 -0
  30. package/dist/esm/actions/signPreparedCalls.js +88 -0
  31. package/dist/esm/actions/signPreparedCalls.js.map +1 -0
  32. package/dist/esm/actions/signSignatureRequest.d.ts +41 -0
  33. package/dist/esm/actions/signSignatureRequest.js +97 -0
  34. package/dist/esm/actions/signSignatureRequest.js.map +1 -0
  35. package/dist/esm/actions/signTypedData.d.ts +40 -0
  36. package/dist/esm/actions/signTypedData.js +66 -0
  37. package/dist/esm/actions/signTypedData.js.map +1 -0
  38. package/dist/esm/client.d.ts +34 -0
  39. package/dist/esm/client.js +62 -0
  40. package/dist/esm/client.js.map +1 -0
  41. package/dist/esm/decorators/smartWalletActions.d.ts +36 -0
  42. package/dist/esm/decorators/smartWalletActions.js +37 -0
  43. package/dist/esm/decorators/smartWalletActions.js.map +1 -0
  44. package/dist/esm/experimental/actions/requestQuoteV0.d.ts +54 -0
  45. package/dist/esm/experimental/actions/requestQuoteV0.js +62 -0
  46. package/dist/esm/experimental/actions/requestQuoteV0.js.map +1 -0
  47. package/dist/esm/experimental/swapActionsDecorator.d.ts +13 -0
  48. package/dist/esm/experimental/swapActionsDecorator.js +16 -0
  49. package/dist/esm/experimental/swapActionsDecorator.js.map +1 -0
  50. package/dist/esm/exports/experimental.d.ts +4 -0
  51. package/dist/esm/exports/experimental.js +3 -0
  52. package/dist/esm/exports/experimental.js.map +1 -0
  53. package/dist/esm/exports/index.d.ts +31 -0
  54. package/dist/esm/exports/index.js +16 -0
  55. package/dist/esm/exports/index.js.map +1 -0
  56. package/dist/esm/exports/internal.d.ts +6 -0
  57. package/dist/esm/exports/internal.js +4 -0
  58. package/dist/esm/exports/internal.js.map +1 -0
  59. package/dist/esm/internal.d.ts +11 -0
  60. package/dist/esm/internal.js +12 -0
  61. package/dist/esm/internal.js.map +1 -0
  62. package/dist/esm/logger.d.ts +2 -0
  63. package/dist/esm/logger.js +8 -0
  64. package/dist/esm/logger.js.map +1 -0
  65. package/dist/esm/provider.d.ts +26 -0
  66. package/dist/esm/provider.js +191 -0
  67. package/dist/esm/provider.js.map +1 -0
  68. package/dist/esm/testSetup.d.ts +3 -0
  69. package/dist/esm/testSetup.js +18 -0
  70. package/dist/esm/testSetup.js.map +1 -0
  71. package/dist/esm/types.d.ts +34 -0
  72. package/dist/esm/types.js +2 -0
  73. package/dist/esm/types.js.map +1 -0
  74. package/dist/esm/utils/assertions.d.ts +18 -0
  75. package/dist/esm/utils/assertions.js +24 -0
  76. package/dist/esm/utils/assertions.js.map +1 -0
  77. package/dist/esm/utils/capabilities.d.ts +10 -0
  78. package/dist/esm/utils/capabilities.js +19 -0
  79. package/dist/esm/utils/capabilities.js.map +1 -0
  80. package/dist/esm/utils/format.d.ts +7 -0
  81. package/dist/esm/utils/format.js +37 -0
  82. package/dist/esm/utils/format.js.map +1 -0
  83. package/dist/esm/utils/viemDecode.d.ts +8 -0
  84. package/dist/esm/utils/viemDecode.js +231 -0
  85. package/dist/esm/utils/viemDecode.js.map +1 -0
  86. package/dist/esm/utils/viemEncode.d.ts +40 -0
  87. package/dist/esm/utils/viemEncode.js +216 -0
  88. package/dist/esm/utils/viemEncode.js.map +1 -0
  89. package/dist/esm/version.d.ts +1 -0
  90. package/dist/esm/version.js +4 -0
  91. package/dist/esm/version.js.map +1 -0
  92. package/dist/types/actions/formatSign.d.ts +36 -0
  93. package/dist/types/actions/formatSign.d.ts.map +1 -0
  94. package/dist/types/actions/grantPermissions.d.ts +74 -0
  95. package/dist/types/actions/grantPermissions.d.ts.map +1 -0
  96. package/dist/types/actions/listAccounts.d.ts +41 -0
  97. package/dist/types/actions/listAccounts.d.ts.map +1 -0
  98. package/dist/types/actions/prepareCalls.d.ts +45 -0
  99. package/dist/types/actions/prepareCalls.d.ts.map +1 -0
  100. package/dist/types/actions/prepareSign.d.ts +34 -0
  101. package/dist/types/actions/prepareSign.d.ts.map +1 -0
  102. package/dist/types/actions/requestAccount.d.ts +34 -0
  103. package/dist/types/actions/requestAccount.d.ts.map +1 -0
  104. package/dist/types/actions/sendCalls.d.ts +35 -0
  105. package/dist/types/actions/sendCalls.d.ts.map +1 -0
  106. package/dist/types/actions/sendPreparedCalls.d.ts +44 -0
  107. package/dist/types/actions/sendPreparedCalls.d.ts.map +1 -0
  108. package/dist/types/actions/signMessage.d.ts +28 -0
  109. package/dist/types/actions/signMessage.d.ts.map +1 -0
  110. package/dist/types/actions/signPreparedCalls.d.ts +33 -0
  111. package/dist/types/actions/signPreparedCalls.d.ts.map +1 -0
  112. package/dist/types/actions/signSignatureRequest.d.ts +42 -0
  113. package/dist/types/actions/signSignatureRequest.d.ts.map +1 -0
  114. package/dist/types/actions/signTypedData.d.ts +41 -0
  115. package/dist/types/actions/signTypedData.d.ts.map +1 -0
  116. package/dist/types/client.d.ts +35 -0
  117. package/dist/types/client.d.ts.map +1 -0
  118. package/dist/types/decorators/smartWalletActions.d.ts +37 -0
  119. package/dist/types/decorators/smartWalletActions.d.ts.map +1 -0
  120. package/dist/types/experimental/actions/requestQuoteV0.d.ts +55 -0
  121. package/dist/types/experimental/actions/requestQuoteV0.d.ts.map +1 -0
  122. package/dist/types/experimental/swapActionsDecorator.d.ts +14 -0
  123. package/dist/types/experimental/swapActionsDecorator.d.ts.map +1 -0
  124. package/dist/types/exports/experimental.d.ts +5 -0
  125. package/dist/types/exports/experimental.d.ts.map +1 -0
  126. package/dist/types/exports/index.d.ts +32 -0
  127. package/dist/types/exports/index.d.ts.map +1 -0
  128. package/dist/types/exports/internal.d.ts +7 -0
  129. package/dist/types/exports/internal.d.ts.map +1 -0
  130. package/dist/types/internal.d.ts +12 -0
  131. package/dist/types/internal.d.ts.map +1 -0
  132. package/dist/types/logger.d.ts +3 -0
  133. package/dist/types/logger.d.ts.map +1 -0
  134. package/dist/types/provider.d.ts +27 -0
  135. package/dist/types/provider.d.ts.map +1 -0
  136. package/dist/types/testSetup.d.ts +4 -0
  137. package/dist/types/testSetup.d.ts.map +1 -0
  138. package/dist/types/types.d.ts +35 -0
  139. package/dist/types/types.d.ts.map +1 -0
  140. package/dist/types/utils/assertions.d.ts +19 -0
  141. package/dist/types/utils/assertions.d.ts.map +1 -0
  142. package/dist/types/utils/capabilities.d.ts +11 -0
  143. package/dist/types/utils/capabilities.d.ts.map +1 -0
  144. package/dist/types/utils/format.d.ts +8 -0
  145. package/dist/types/utils/format.d.ts.map +1 -0
  146. package/dist/types/utils/viemDecode.d.ts +9 -0
  147. package/dist/types/utils/viemDecode.d.ts.map +1 -0
  148. package/dist/types/utils/viemEncode.d.ts +41 -0
  149. package/dist/types/utils/viemEncode.d.ts.map +1 -0
  150. package/dist/types/version.d.ts +2 -0
  151. package/dist/types/version.d.ts.map +1 -0
  152. package/package.json +76 -0
  153. package/src/actions/formatSign.ts +64 -0
  154. package/src/actions/grantPermissions.ts +125 -0
  155. package/src/actions/listAccounts.ts +66 -0
  156. package/src/actions/prepareCalls.ts +85 -0
  157. package/src/actions/prepareSign.ts +67 -0
  158. package/src/actions/requestAccount.ts +100 -0
  159. package/src/actions/sendCalls.ts +67 -0
  160. package/src/actions/sendPreparedCalls.ts +70 -0
  161. package/src/actions/signMessage.ts +74 -0
  162. package/src/actions/signPreparedCalls.ts +120 -0
  163. package/src/actions/signSignatureRequest.ts +135 -0
  164. package/src/actions/signTypedData.ts +90 -0
  165. package/src/client.ts +107 -0
  166. package/src/decorators/smartWalletActions.ts +123 -0
  167. package/src/experimental/actions/requestQuoteV0.ts +95 -0
  168. package/src/experimental/swapActionsDecorator.ts +34 -0
  169. package/src/exports/experimental.ts +7 -0
  170. package/src/exports/index.ts +44 -0
  171. package/src/exports/internal.ts +8 -0
  172. package/src/internal.ts +25 -0
  173. package/src/logger.ts +9 -0
  174. package/src/provider.ts +261 -0
  175. package/src/testSetup.ts +24 -0
  176. package/src/types.ts +61 -0
  177. package/src/utils/assertions.ts +32 -0
  178. package/src/utils/capabilities.ts +24 -0
  179. package/src/utils/format.ts +61 -0
  180. package/src/utils/viemDecode.ts +313 -0
  181. package/src/utils/viemEncode.ts +345 -0
  182. package/src/version.ts +3 -0
@@ -0,0 +1,120 @@
1
+ import { assertNever, BaseError } from "@alchemy/common";
2
+ import type { PrepareCallsResult } from "./prepareCalls.ts";
3
+ import { signSignatureRequest } from "./signSignatureRequest.js";
4
+ import type { Prettify } from "viem";
5
+ import type {
6
+ PreparedCall_Authorization,
7
+ PreparedCall_UserOpV060,
8
+ PreparedCall_UserOpV070,
9
+ } from "@alchemy/wallet-api-types";
10
+ import type { InnerWalletApiClient } from "../types.js";
11
+ import { LOGGER } from "../logger.js";
12
+ import type { SendPreparedCallsParams } from "./sendPreparedCalls.js";
13
+
14
+ export type SignPreparedCallsParams = Prettify<PrepareCallsResult>;
15
+
16
+ export type SignPreparedCallsResult = SendPreparedCallsParams;
17
+
18
+ /**
19
+ * Signs prepared calls using the provided signer.
20
+ *
21
+ * @param {InnerWalletApiClient} client - The wallet client to use for signing
22
+ * @param {SignPreparedCallsParams} params - The prepared calls with signature requests
23
+ * @returns {Promise<SignPreparedCallsResult>} A Promise that resolves to the signed calls
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * // Prepare a user operation call.
28
+ * const preparedCalls = await client.prepareCalls({
29
+ * calls: [{
30
+ * to: "0x1234...",
31
+ * data: "0xabcdef...",
32
+ * value: "0x0"
33
+ * }],
34
+ * });
35
+ *
36
+ * // Sign the prepared calls.
37
+ * const signedCalls = await client.signPreparedCalls(preparedCalls);
38
+ *
39
+ * // Send the signed calls.
40
+ * const result = await client.sendPreparedCalls(signedCalls);
41
+ * ```
42
+ */
43
+ export async function signPreparedCalls(
44
+ client: InnerWalletApiClient,
45
+ params: SignPreparedCallsParams,
46
+ ): Promise<SignPreparedCallsResult> {
47
+ LOGGER.debug("signPreparedCalls:start", { type: params.type });
48
+ const signAuthorizationCall = async (call: PreparedCall_Authorization) => {
49
+ const { signatureRequest: _signatureRequest, ...rest } = call;
50
+ const signature = await signSignatureRequest(client, {
51
+ type: "eip7702Auth",
52
+ data: {
53
+ ...rest.data,
54
+ chainId: call.chainId,
55
+ },
56
+ });
57
+ return {
58
+ ...rest,
59
+ signature,
60
+ };
61
+ };
62
+
63
+ const signUserOperationCall = async (
64
+ call: PreparedCall_UserOpV060 | PreparedCall_UserOpV070,
65
+ ) => {
66
+ const { signatureRequest, ...rest } = call;
67
+
68
+ if (!signatureRequest) {
69
+ LOGGER.warn("signPreparedCalls:missing-signatureRequest", {
70
+ type: call.type,
71
+ });
72
+ throw new BaseError(
73
+ "Signature request is required for signing user operation calls. Ensure `onlyEstimation` is set to `false` when calling `prepareCalls`.",
74
+ );
75
+ }
76
+
77
+ const signature = await signSignatureRequest(client, signatureRequest);
78
+ const res = {
79
+ ...rest,
80
+ signature,
81
+ } as const;
82
+ LOGGER.debug("signPreparedCalls:userOp:ok");
83
+ return res;
84
+ };
85
+
86
+ if (params.type === "array") {
87
+ const res = {
88
+ type: "array" as const,
89
+ data: await Promise.all(
90
+ params.data.map((call) =>
91
+ call.type === "authorization"
92
+ ? signAuthorizationCall(call)
93
+ : signUserOperationCall(call),
94
+ ),
95
+ ),
96
+ };
97
+ LOGGER.debug("signPreparedCalls:array:ok", { count: res.data.length });
98
+ return res;
99
+ } else if (
100
+ params.type === "user-operation-v060" ||
101
+ params.type === "user-operation-v070"
102
+ ) {
103
+ const res = await signUserOperationCall(params);
104
+ LOGGER.debug("signPreparedCalls:single-userOp:ok");
105
+ return res;
106
+ } else if (params.type === "paymaster-permit") {
107
+ LOGGER.warn("signPreparedCalls:invalid-call-type", { type: params.type });
108
+ throw new BaseError(
109
+ `Invalid call type ${params.type} for signing prepared calls`,
110
+ );
111
+ } else {
112
+ LOGGER.warn("signPreparedCalls:unexpected-call-type", {
113
+ type: (params as { type?: unknown }).type,
114
+ });
115
+ return assertNever(
116
+ params,
117
+ `Unexpected call type in ${params} for signing prepared calls`,
118
+ );
119
+ }
120
+ }
@@ -0,0 +1,135 @@
1
+ import { type Hex, hexToNumber, type Prettify, serializeSignature } from "viem";
2
+ import type {
3
+ PersonalSignSignatureRequest,
4
+ TypedDataSignatureRequest,
5
+ AuthorizationSignatureRequest,
6
+ Eip7702UnsignedAuth,
7
+ } from "@alchemy/wallet-api-types";
8
+ import { vToYParity } from "ox/Signature";
9
+ import type { InnerWalletApiClient, WithoutRawPayload } from "../types";
10
+ import { assertNever } from "@alchemy/common";
11
+ import { getAction } from "viem/utils";
12
+ import { signAuthorization, signMessage, signTypedData } from "viem/actions";
13
+ import { LOGGER } from "../logger.js";
14
+
15
+ export type SignSignatureRequestParams = Prettify<
16
+ WithoutRawPayload<
17
+ | PersonalSignSignatureRequest
18
+ | TypedDataSignatureRequest
19
+ | (AuthorizationSignatureRequest & {
20
+ data: Eip7702UnsignedAuth;
21
+ })
22
+ >
23
+ >;
24
+
25
+ export type SignSignatureRequestResult = Prettify<{
26
+ type: "secp256k1";
27
+ data: Hex;
28
+ }>;
29
+
30
+ /**
31
+ * Signs a signature request using the provided signer.
32
+ * This method handles different types of signature requests including personal_sign, eth_signTypedData_v4, and authorization.
33
+ *
34
+ * @param {SmartAccountSigner} signer - The signer to use for signing the request
35
+ * @param {SignSignatureRequestParams} params - The signature request parameters
36
+ * @param {string} params.type - The type of signature request ('personal_sign', 'eth_signTypedData_v4', or 'signature_with_authorization')
37
+ * @param {SignSignatureRequestParams["data"]} params.data - The data to sign, format depends on the signature type
38
+ * @returns {Promise<SignSignatureRequestResult>} A Promise that resolves to the signature result
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * // Sign a personal message
43
+ * const result = await client.signSignatureRequest({
44
+ * type: 'personal_sign',
45
+ * data: 'Hello, world!'
46
+ * });
47
+ *
48
+ * // Sign typed data (EIP-712)
49
+ * const result = await client.signSignatureRequest({
50
+ * type: 'eth_signTypedData_v4',
51
+ * data: {
52
+ * domain: { ... },
53
+ * types: { ... },
54
+ * primaryType: '...',
55
+ * message: { ... }
56
+ * }
57
+ * });
58
+ * ```
59
+ */
60
+
61
+ export async function signSignatureRequest(
62
+ client: InnerWalletApiClient,
63
+ params: SignSignatureRequestParams,
64
+ ): Promise<SignSignatureRequestResult> {
65
+ 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
+
76
+ switch (params.type) {
77
+ 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;
87
+ }
88
+ 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;
98
+ }
99
+ case "eip7702Auth": {
100
+ const {
101
+ r,
102
+ s,
103
+ v,
104
+ 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,
112
+ });
113
+ // yParity *should* already be a number, but some 3rd
114
+ // party signers may mistakenly return it as a bigint.
115
+ const yParity =
116
+ _yParity != null ? Number(_yParity) : vToYParity(Number(v));
117
+
118
+ const res = {
119
+ type: "secp256k1",
120
+ data: serializeSignature({
121
+ r,
122
+ s,
123
+ yParity,
124
+ }),
125
+ } as const;
126
+ LOGGER.debug("signSignatureRequest:eip7702Auth:ok");
127
+ return res;
128
+ }
129
+ default:
130
+ LOGGER.warn("signSignatureRequest:unknown-type", {
131
+ type: (params as { type?: unknown }).type,
132
+ });
133
+ return assertNever(params, `Unexpected signature request type.`);
134
+ }
135
+ }
@@ -0,0 +1,90 @@
1
+ import {
2
+ type Address,
3
+ type Hex,
4
+ type Prettify,
5
+ type TypedDataDefinition,
6
+ } from "viem";
7
+ import type { InnerWalletApiClient } from "../types.ts";
8
+ import { requestAccount } from "./requestAccount.js";
9
+ import { prepareSign } from "./prepareSign.js";
10
+ import { signSignatureRequest } from "./signSignatureRequest.js";
11
+ import { formatSign } from "./formatSign.js";
12
+ import { typedDataToJsonSafe } from "../utils/format.js";
13
+ import { LOGGER } from "../logger.js";
14
+
15
+ export type SignTypedDataParams = Prettify<
16
+ TypedDataDefinition & {
17
+ account?: Address;
18
+ }
19
+ >;
20
+
21
+ export type SignTypedDataResult = Prettify<Hex>;
22
+
23
+ /**
24
+ * Signs typed data (EIP-712) using the smart account.
25
+ * This method requests the account associated with the signer and uses it to sign the typed data.
26
+ *
27
+ * @param {InnerWalletApiClient} client - The wallet API client to use for the request
28
+ * @param {SignerClient} signerClient - The wallet client to use for signing
29
+ * @param {TypedDataDefinition} params - The typed data to sign, following EIP-712 format
30
+ * @returns {Promise<SignTypedDataResult>} A Promise that resolves to the signature as a hex string
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * // Sign typed data
35
+ * const signature = await client.signTypedData({
36
+ * domain: {
37
+ * name: 'Example DApp',
38
+ * version: '1',
39
+ * chainId: 1,
40
+ * verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
41
+ * },
42
+ * types: {
43
+ * Person: [
44
+ * { name: 'name', type: 'string' },
45
+ * { name: 'wallet', type: 'address' }
46
+ * ]
47
+ * },
48
+ * primaryType: 'Person',
49
+ * message: {
50
+ * name: 'John Doe',
51
+ * wallet: '0xAaAaAaAaAaAaAaAaAaAAAAAAAAaaaAaAaAaaAaAa'
52
+ * }
53
+ * });
54
+ * ```
55
+ */
56
+
57
+ export async function signTypedData(
58
+ client: InnerWalletApiClient,
59
+ params: SignTypedDataParams,
60
+ ): Promise<SignTypedDataResult> {
61
+ LOGGER.debug("signTypedData:start", {
62
+ hasExplicitAccount: params.account != null,
63
+ primaryType: params.primaryType,
64
+ });
65
+ const accountAddress = params.account ?? client.account?.address;
66
+ const account = await requestAccount(
67
+ client,
68
+ accountAddress != null ? { accountAddress } : undefined,
69
+ );
70
+
71
+ const prepared = await prepareSign(client, {
72
+ from: account.address,
73
+ signatureRequest: {
74
+ type: "eth_signTypedData_v4",
75
+ data: typedDataToJsonSafe(params),
76
+ },
77
+ });
78
+
79
+ const signed = await signSignatureRequest(client, prepared.signatureRequest);
80
+
81
+ const formatted = await formatSign(client, {
82
+ from: account.address,
83
+ signature: {
84
+ type: "ecdsa",
85
+ data: signed.data,
86
+ },
87
+ });
88
+ LOGGER.debug("signTypedData:done", { from: account.address });
89
+ return formatted.signature;
90
+ }
package/src/client.ts ADDED
@@ -0,0 +1,107 @@
1
+ import {
2
+ createClient,
3
+ type Address,
4
+ type Chain,
5
+ type LocalAccount,
6
+ createWalletClient,
7
+ } from "viem";
8
+ import { smartWalletActions } from "./decorators/smartWalletActions.js";
9
+ import { type AlchemyTransport } from "@alchemy/common";
10
+ import type { SignerClient, SmartWalletClient } from "./types.js";
11
+ import { createInternalState } from "./internal.js";
12
+ import type { CreationOptionsBySignerAddress } from "@alchemy/wallet-api-types";
13
+
14
+ export type CreateSmartWalletClientParams<
15
+ TAccount extends Address | undefined = Address | undefined,
16
+ > = {
17
+ signer: LocalAccount | SignerClient;
18
+ transport: AlchemyTransport;
19
+ chain: Chain;
20
+ account?: TAccount;
21
+ // TODO(v5): Reconsider if the client store store the policyIds, especially as
22
+ // new paymaster fields (i.e. for erc-20 support) are introduced. It might make
23
+ // more sense for them to be stored at a higher level like in the wagmi config
24
+ // or hooks.
25
+ policyId?: string;
26
+ policyIds?: string[];
27
+ };
28
+
29
+ /**
30
+ * Creates a smart wallet client with wallet API actions.
31
+ *
32
+ * @param {CreateSmartWalletClientParams} params - Parameters for creating the smart wallet client.
33
+ * @param {LocalAccount | JsonRpcAccount} params.account - The account to use for signing.
34
+ * @param {AlchemyTransport} params.transport - The transport to use for RPC calls.
35
+ * @param {Chain} params.chain - The blockchain network to connect to.
36
+ * @param {string[]} params.policyIds - Optional policy IDs for paymaster service.
37
+ * @returns {WalletClient} A wallet client extended with smart wallet actions.
38
+ */
39
+ export const createSmartWalletClient = <
40
+ TAccount extends Address | undefined = Address | undefined,
41
+ >({
42
+ account,
43
+ transport,
44
+ chain,
45
+ signer,
46
+ policyId,
47
+ policyIds,
48
+ }: CreateSmartWalletClientParams<TAccount>): SmartWalletClient<TAccount> => {
49
+ const _policyIds = [...(policyId ? [policyId] : []), ...(policyIds ?? [])];
50
+
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
+ return createClient({
64
+ account,
65
+ transport,
66
+ chain,
67
+ name: "alchemySmartWalletClient",
68
+ })
69
+ .extend(() => ({
70
+ policyIds: _policyIds,
71
+ internal: createInternalState(),
72
+ owner: signerClient,
73
+ }))
74
+ .extend(smartWalletActions<TAccount>);
75
+ };
76
+
77
+ /**
78
+ * Creates a smart wallet client and requests an account in a single operation.
79
+ * This is a convenience function that combines client creation with account initialization.
80
+ *
81
+ * @param {CreateSmartWalletClientParams<undefined>} clientParams - Parameters for creating the smart wallet client (without an account).
82
+ * @param {CreationOptionsBySignerAddress | { accountAddress: Address }} accountOptions - Options for requesting the account. Can either be creation options for a new account or an object with an existing account address.
83
+ * @returns {Promise<SmartWalletClient<Address>>} A promise that resolves to a smart wallet client with an initialized account.
84
+ */
85
+ export const createSmartWalletClientAndRequestAccount = async (
86
+ clientParams: CreateSmartWalletClientParams<undefined>,
87
+ accountOptions:
88
+ | CreationOptionsBySignerAddress
89
+ | { accountAddress: Address } = {},
90
+ ): Promise<SmartWalletClient<Address>> => {
91
+ const clientWithoutAccount = createSmartWalletClient(clientParams);
92
+
93
+ const account = await clientWithoutAccount.requestAccount(
94
+ "accountAddress" in accountOptions
95
+ ? {
96
+ accountAddress: accountOptions.accountAddress,
97
+ }
98
+ : {
99
+ creationHint: accountOptions,
100
+ },
101
+ );
102
+
103
+ return createSmartWalletClient({
104
+ ...clientParams,
105
+ account: account.address,
106
+ });
107
+ };
@@ -0,0 +1,123 @@
1
+ import { type Hex, type Address } from "viem";
2
+ import {
3
+ requestAccount,
4
+ type RequestAccountParams,
5
+ type RequestAccountResult,
6
+ } from "../actions/requestAccount.js";
7
+ import {
8
+ prepareCalls,
9
+ type PrepareCallsParams,
10
+ type PrepareCallsResult,
11
+ } from "../actions/prepareCalls.js";
12
+ import {
13
+ sendPreparedCalls,
14
+ type SendPreparedCallsParams,
15
+ type SendPreparedCallsResult,
16
+ } from "../actions/sendPreparedCalls.js";
17
+ import {
18
+ sendCalls,
19
+ type SendCallsParams,
20
+ type SendCallsResult,
21
+ } from "../actions/sendCalls.js";
22
+ import {
23
+ listAccounts,
24
+ type ListAccountsParams,
25
+ type ListAccountsResult,
26
+ } from "../actions/listAccounts.js";
27
+ import {
28
+ signSignatureRequest,
29
+ type SignSignatureRequestParams,
30
+ type SignSignatureRequestResult,
31
+ } from "../actions/signSignatureRequest.js";
32
+ import {
33
+ signPreparedCalls,
34
+ type SignPreparedCallsParams,
35
+ type SignPreparedCallsResult,
36
+ } from "../actions/signPreparedCalls.js";
37
+ import { signMessage, type SignMessageParams } from "../actions/signMessage.js";
38
+ import {
39
+ signTypedData,
40
+ type SignTypedDataParams,
41
+ } from "../actions/signTypedData.js";
42
+ import {
43
+ grantPermissions,
44
+ type GrantPermissionsParams,
45
+ type GrantPermissionsResult,
46
+ } from "../actions/grantPermissions.js";
47
+ import type { InnerWalletApiClient } from "../types.js";
48
+ import {
49
+ getCallsStatus,
50
+ waitForCallsStatus,
51
+ getCapabilities,
52
+ type GetCallsStatusParameters,
53
+ type GetCallsStatusReturnType,
54
+ type WaitForCallsStatusParameters,
55
+ type WaitForCallsStatusReturnType,
56
+ type GetCapabilitiesParameters,
57
+ type GetCapabilitiesReturnType,
58
+ } from "viem/actions";
59
+
60
+ export type SmartWalletActions<
61
+ TAccount extends Address | undefined = Address | undefined,
62
+ > = {
63
+ requestAccount: (
64
+ params?: RequestAccountParams,
65
+ ) => Promise<RequestAccountResult>;
66
+ prepareCalls: (
67
+ params: PrepareCallsParams<TAccount>,
68
+ ) => Promise<PrepareCallsResult>;
69
+ sendPreparedCalls: (
70
+ params: SendPreparedCallsParams,
71
+ ) => Promise<SendPreparedCallsResult>;
72
+ sendCalls: (params: SendCallsParams<TAccount>) => Promise<SendCallsResult>;
73
+ listAccounts: (params: ListAccountsParams) => Promise<ListAccountsResult>;
74
+ signSignatureRequest: (
75
+ params: SignSignatureRequestParams,
76
+ ) => Promise<SignSignatureRequestResult>;
77
+ signPreparedCalls: (
78
+ params: SignPreparedCallsParams,
79
+ ) => Promise<SignPreparedCallsResult>;
80
+ signMessage: (params: SignMessageParams) => Promise<Hex>;
81
+ signTypedData: (params: SignTypedDataParams) => Promise<Hex>;
82
+ grantPermissions: (
83
+ params: GrantPermissionsParams<TAccount>,
84
+ ) => Promise<GrantPermissionsResult>;
85
+ getCallsStatus: (
86
+ params: GetCallsStatusParameters,
87
+ ) => Promise<GetCallsStatusReturnType>;
88
+ waitForCallsStatus: (
89
+ params: WaitForCallsStatusParameters,
90
+ ) => Promise<WaitForCallsStatusReturnType>;
91
+ getCapabilities: (
92
+ params?: GetCapabilitiesParameters | undefined,
93
+ ) => Promise<GetCapabilitiesReturnType>;
94
+ };
95
+
96
+ /**
97
+ * Decorator that adds smart wallet actions to a wallet API client.
98
+ * Provides both Alchemy-specific methods and standard viem wallet actions.
99
+ *
100
+ * @param {InnerWalletApiClient} client The wallet API client instance
101
+ * @returns {SmartWalletActions<TAccount>} An object containing smart wallet action methods
102
+ */
103
+ export const smartWalletActions = <
104
+ TAccount extends Address | undefined = Address | undefined,
105
+ >(
106
+ client: InnerWalletApiClient,
107
+ ): SmartWalletActions<TAccount> => ({
108
+ // Alchemy methods.
109
+ requestAccount: (params) => requestAccount(client, params),
110
+ prepareCalls: (params) => prepareCalls(client, params),
111
+ listAccounts: (params) => listAccounts(client, params),
112
+ sendPreparedCalls: (params) => sendPreparedCalls(client, params),
113
+ sendCalls: (params) => sendCalls(client, params), // TODO(v5): adapt this to fit viem's exact interface?
114
+ signSignatureRequest: (params) => signSignatureRequest(client, params),
115
+ signPreparedCalls: (params) => signPreparedCalls(client, params),
116
+ signMessage: (params) => signMessage(client, params),
117
+ signTypedData: (params) => signTypedData(client, params),
118
+ grantPermissions: (params) => grantPermissions(client, params),
119
+ // Viem methods.
120
+ getCallsStatus: (params) => getCallsStatus(client, params),
121
+ waitForCallsStatus: (params) => waitForCallsStatus(client, params),
122
+ getCapabilities: (params) => getCapabilities(client, params),
123
+ });
@@ -0,0 +1,95 @@
1
+ import {
2
+ toHex,
3
+ type Address,
4
+ type IsUndefined,
5
+ type Prettify,
6
+ type UnionOmit,
7
+ } from "viem";
8
+ import type { OptionalChainId, InnerWalletApiClient } from "../../types.ts";
9
+ import type { WalletServerRpcSchemaType } from "@alchemy/wallet-api-types/rpc";
10
+ import { AccountNotFoundError } from "@alchemy/common";
11
+ import { mergeClientCapabilities } from "../../utils/capabilities.js";
12
+
13
+ type RpcSchema = Extract<
14
+ WalletServerRpcSchemaType,
15
+ {
16
+ Request: {
17
+ method: "wallet_requestQuote_v0";
18
+ };
19
+ }
20
+ >;
21
+
22
+ export type RequestQuoteV0Params<
23
+ TAccount extends Address | undefined = Address | undefined,
24
+ > = Prettify<
25
+ OptionalChainId<UnionOmit<RpcSchema["Request"]["params"][0], "from">>
26
+ > &
27
+ (IsUndefined<TAccount> extends true ? { from: Address } : { from?: never });
28
+
29
+ export type RequestQuoteV0Result = Prettify<RpcSchema["ReturnType"]>;
30
+
31
+ /**
32
+ * Requests a quote for a token swap, returning either prepared calls for smart wallets
33
+ * or raw calls for EOA wallets depending on the returnRawCalls parameter.
34
+ *
35
+ * @param {InnerWalletApiClient} client - The wallet API client to use for the request
36
+ * @param {RequestQuoteV0Params<TAccount>} params - Parameters for requesting a swap quote
37
+ * @param {Address} params.fromToken - The address of the token to swap from
38
+ * @param {Address} params.toToken - The address of the token to swap to
39
+ * @param {Hex} [params.fromAmount] - The amount to swap from (mutually exclusive with minimumToAmount)
40
+ * @param {Hex} [params.minimumToAmount] - The minimum amount to receive (mutually exclusive with fromAmount)
41
+ * @param {Address} [params.from] - The address to execute the swap from (required if the client wasn't initialized with an account)
42
+ * @param {Hex} [params.slippage] - The maximum acceptable slippage percentage
43
+ * @param {boolean} [params.returnRawCalls] - Whether to return raw calls for EOA wallets (defaults to false for smart wallets)
44
+ * @param {object} [params.capabilities] - Optional capabilities to include with the request (only available when returnRawCalls is false)
45
+ * @param {Array<{to: Address, data?: Hex, value?: Hex}>} [params.postCalls] - Optional calls to execute after the swap
46
+ * @returns {Promise<RequestQuoteV0Result>} A Promise that resolves to either prepared calls or raw calls depending on returnRawCalls
47
+ *
48
+ * @example
49
+ * ```ts twoslash
50
+ * // Request a quote for smart wallet (prepared calls)
51
+ * const quote = await client.requestQuoteV0({
52
+ * fromToken: "0xA0b86a33E6441e1d6a8E8C7a8E8E8E8E8E8E8E8E",
53
+ * toToken: "0xB0b86a33E6441e1d6a8E8C7a8E8E8E8E8E8E8E8E",
54
+ * fromAmount: "0x1000000000000000000", // 1 ETH
55
+ * capabilities: {
56
+ * paymasterService: { policyId: "your-policy-id" }
57
+ * }
58
+ * });
59
+ *
60
+ * // Request a quote for EOA wallet (raw calls)
61
+ * const rawQuote = await client.requestQuoteV0({
62
+ * fromToken: "0xA0b86a33E6441e1d6a8E8C7a8E8E8E8E8E8E8E8E",
63
+ * toToken: "0xB0b86a33E6441e1d6a8E8C7a8E8E8E8E8E8E8E8E",
64
+ * fromAmount: "0x1000000000000000000",
65
+ * returnRawCalls: true
66
+ * });
67
+ * ```
68
+ */
69
+ export async function requestQuoteV0<
70
+ TAccount extends Address | undefined = Address | undefined,
71
+ >(
72
+ client: InnerWalletApiClient,
73
+ params: RequestQuoteV0Params<TAccount>,
74
+ ): Promise<RequestQuoteV0Result> {
75
+ const from = params.from ?? client.account?.address;
76
+ if (!from) {
77
+ throw new AccountNotFoundError();
78
+ }
79
+
80
+ const capabilities = params.returnRawCalls
81
+ ? undefined
82
+ : mergeClientCapabilities(client, params.capabilities);
83
+
84
+ return await client.request({
85
+ method: "wallet_requestQuote_v0",
86
+ params: [
87
+ {
88
+ ...params,
89
+ chainId: params.chainId ?? toHex(client.chain.id),
90
+ from,
91
+ ...(capabilities && { capabilities }),
92
+ },
93
+ ],
94
+ });
95
+ }