@alchemy/wallet-apis 5.0.0-beta.8 → 5.0.1

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 (201) hide show
  1. package/README.md +2 -0
  2. package/dist/esm/actions/prepareCalls.d.ts +8 -3
  3. package/dist/esm/actions/prepareCalls.js +8 -0
  4. package/dist/esm/actions/prepareCalls.js.map +1 -1
  5. package/dist/esm/actions/requestAccount.d.ts +4 -3
  6. package/dist/esm/actions/requestAccount.js.map +1 -1
  7. package/dist/esm/actions/sendCalls.d.ts +5 -2
  8. package/dist/esm/actions/sendCalls.js +5 -2
  9. package/dist/esm/actions/sendCalls.js.map +1 -1
  10. package/dist/esm/actions/sendPreparedCalls.d.ts +3 -1
  11. package/dist/esm/actions/sendPreparedCalls.js.map +1 -1
  12. package/dist/esm/actions/signPreparedCalls.d.ts +2 -0
  13. package/dist/esm/actions/signPreparedCalls.js +14 -1
  14. package/dist/esm/actions/signPreparedCalls.js.map +1 -1
  15. package/dist/esm/actions/signSignatureRequest.d.ts +4 -4
  16. package/dist/esm/actions/signSignatureRequest.js +1 -1
  17. package/dist/esm/actions/signSignatureRequest.js.map +1 -1
  18. package/dist/esm/actions/signTypedData.d.ts +14 -4
  19. package/dist/esm/actions/signTypedData.js.map +1 -1
  20. package/dist/esm/actions/solana/getCallsStatus.d.ts +24 -0
  21. package/dist/esm/actions/solana/getCallsStatus.js +44 -0
  22. package/dist/esm/actions/solana/getCallsStatus.js.map +1 -0
  23. package/dist/esm/actions/solana/prepareCalls.d.ts +46 -0
  24. package/dist/esm/actions/solana/prepareCalls.js +70 -0
  25. package/dist/esm/actions/solana/prepareCalls.js.map +1 -0
  26. package/dist/esm/actions/solana/sendCalls.d.ts +34 -0
  27. package/dist/esm/actions/solana/sendCalls.js +44 -0
  28. package/dist/esm/actions/solana/sendCalls.js.map +1 -0
  29. package/dist/esm/actions/solana/sendPreparedCalls.d.ts +24 -0
  30. package/dist/esm/actions/solana/sendPreparedCalls.js +32 -0
  31. package/dist/esm/actions/solana/sendPreparedCalls.js.map +1 -0
  32. package/dist/esm/actions/solana/signPreparedCalls.d.ts +23 -0
  33. package/dist/esm/actions/solana/signPreparedCalls.js +24 -0
  34. package/dist/esm/actions/solana/signPreparedCalls.js.map +1 -0
  35. package/dist/esm/actions/solana/signSignatureRequest.d.ts +10 -0
  36. package/dist/esm/actions/solana/signSignatureRequest.js +33 -0
  37. package/dist/esm/actions/solana/signSignatureRequest.js.map +1 -0
  38. package/dist/esm/actions/solana/waitForCallsStatus.d.ts +24 -0
  39. package/dist/esm/actions/solana/waitForCallsStatus.js +46 -0
  40. package/dist/esm/actions/solana/waitForCallsStatus.js.map +1 -0
  41. package/dist/esm/actions/undelegateAccount.d.ts +37 -0
  42. package/dist/esm/actions/undelegateAccount.js +49 -0
  43. package/dist/esm/actions/undelegateAccount.js.map +1 -0
  44. package/dist/esm/adapters/SolanaSignerError.d.ts +4 -0
  45. package/dist/esm/adapters/SolanaSignerError.js +13 -0
  46. package/dist/esm/adapters/SolanaSignerError.js.map +1 -0
  47. package/dist/esm/adapters/fromKeypair.d.ts +21 -0
  48. package/dist/esm/adapters/fromKeypair.js +46 -0
  49. package/dist/esm/adapters/fromKeypair.js.map +1 -0
  50. package/dist/esm/adapters/fromKitSigner.d.ts +21 -0
  51. package/dist/esm/adapters/fromKitSigner.js +61 -0
  52. package/dist/esm/adapters/fromKitSigner.js.map +1 -0
  53. package/dist/esm/adapters/fromWalletAdapter.d.ts +26 -0
  54. package/dist/esm/adapters/fromWalletAdapter.js +45 -0
  55. package/dist/esm/adapters/fromWalletAdapter.js.map +1 -0
  56. package/dist/esm/adapters/fromWalletStandard.d.ts +31 -0
  57. package/dist/esm/adapters/fromWalletStandard.js +53 -0
  58. package/dist/esm/adapters/fromWalletStandard.js.map +1 -0
  59. package/dist/esm/adapters/resolveSignerSlot.d.ts +10 -0
  60. package/dist/esm/adapters/resolveSignerSlot.js +39 -0
  61. package/dist/esm/adapters/resolveSignerSlot.js.map +1 -0
  62. package/dist/esm/client.d.ts +29 -14
  63. package/dist/esm/client.js +63 -19
  64. package/dist/esm/client.js.map +1 -1
  65. package/dist/esm/decorators/smartWalletActions.d.ts +2 -0
  66. package/dist/esm/decorators/smartWalletActions.js +4 -2
  67. package/dist/esm/decorators/smartWalletActions.js.map +1 -1
  68. package/dist/esm/decorators/solanaSmartWalletActions.d.ts +16 -0
  69. package/dist/esm/decorators/solanaSmartWalletActions.js +16 -0
  70. package/dist/esm/decorators/solanaSmartWalletActions.js.map +1 -0
  71. package/dist/esm/experimental/actions/requestQuoteV0.d.ts +48 -11
  72. package/dist/esm/experimental/actions/requestQuoteV0.js +8 -4
  73. package/dist/esm/experimental/actions/requestQuoteV0.js.map +1 -1
  74. package/dist/esm/experimental/swapActionsDecorator.d.ts +3 -0
  75. package/dist/esm/experimental/swapActionsDecorator.js.map +1 -1
  76. package/dist/esm/exports/index.d.ts +5 -3
  77. package/dist/esm/exports/index.js +1 -0
  78. package/dist/esm/exports/index.js.map +1 -1
  79. package/dist/esm/exports/solana.d.ts +24 -0
  80. package/dist/esm/exports/solana.js +15 -0
  81. package/dist/esm/exports/solana.js.map +1 -0
  82. package/dist/esm/types.d.ts +28 -4
  83. package/dist/esm/types.js.map +1 -1
  84. package/dist/esm/utils/assertions.d.ts +4 -2
  85. package/dist/esm/utils/assertions.js +6 -0
  86. package/dist/esm/utils/assertions.js.map +1 -1
  87. package/dist/esm/utils/capabilities.d.ts +22 -6
  88. package/dist/esm/utils/capabilities.js +19 -2
  89. package/dist/esm/utils/capabilities.js.map +1 -1
  90. package/dist/esm/utils/format.d.ts +2 -2
  91. package/dist/esm/utils/format.js +4 -3
  92. package/dist/esm/utils/format.js.map +1 -1
  93. package/dist/esm/utils/schema.d.ts +14 -14
  94. package/dist/esm/utils/schema.js +35 -39
  95. package/dist/esm/utils/schema.js.map +1 -1
  96. package/dist/esm/version.d.ts +1 -1
  97. package/dist/esm/version.js +1 -1
  98. package/dist/esm/version.js.map +1 -1
  99. package/dist/types/actions/prepareCalls.d.ts +8 -3
  100. package/dist/types/actions/prepareCalls.d.ts.map +1 -1
  101. package/dist/types/actions/requestAccount.d.ts +4 -3
  102. package/dist/types/actions/requestAccount.d.ts.map +1 -1
  103. package/dist/types/actions/sendCalls.d.ts +5 -2
  104. package/dist/types/actions/sendCalls.d.ts.map +1 -1
  105. package/dist/types/actions/sendPreparedCalls.d.ts +3 -1
  106. package/dist/types/actions/sendPreparedCalls.d.ts.map +1 -1
  107. package/dist/types/actions/signPreparedCalls.d.ts +2 -0
  108. package/dist/types/actions/signPreparedCalls.d.ts.map +1 -1
  109. package/dist/types/actions/signSignatureRequest.d.ts +4 -4
  110. package/dist/types/actions/signSignatureRequest.d.ts.map +1 -1
  111. package/dist/types/actions/signTypedData.d.ts +14 -4
  112. package/dist/types/actions/signTypedData.d.ts.map +1 -1
  113. package/dist/types/actions/solana/getCallsStatus.d.ts +25 -0
  114. package/dist/types/actions/solana/getCallsStatus.d.ts.map +1 -0
  115. package/dist/types/actions/solana/prepareCalls.d.ts +47 -0
  116. package/dist/types/actions/solana/prepareCalls.d.ts.map +1 -0
  117. package/dist/types/actions/solana/sendCalls.d.ts +35 -0
  118. package/dist/types/actions/solana/sendCalls.d.ts.map +1 -0
  119. package/dist/types/actions/solana/sendPreparedCalls.d.ts +25 -0
  120. package/dist/types/actions/solana/sendPreparedCalls.d.ts.map +1 -0
  121. package/dist/types/actions/solana/signPreparedCalls.d.ts +24 -0
  122. package/dist/types/actions/solana/signPreparedCalls.d.ts.map +1 -0
  123. package/dist/types/actions/solana/signSignatureRequest.d.ts +11 -0
  124. package/dist/types/actions/solana/signSignatureRequest.d.ts.map +1 -0
  125. package/dist/types/actions/solana/waitForCallsStatus.d.ts +25 -0
  126. package/dist/types/actions/solana/waitForCallsStatus.d.ts.map +1 -0
  127. package/dist/types/actions/undelegateAccount.d.ts +38 -0
  128. package/dist/types/actions/undelegateAccount.d.ts.map +1 -0
  129. package/dist/types/adapters/SolanaSignerError.d.ts +5 -0
  130. package/dist/types/adapters/SolanaSignerError.d.ts.map +1 -0
  131. package/dist/types/adapters/fromKeypair.d.ts +22 -0
  132. package/dist/types/adapters/fromKeypair.d.ts.map +1 -0
  133. package/dist/types/adapters/fromKitSigner.d.ts +22 -0
  134. package/dist/types/adapters/fromKitSigner.d.ts.map +1 -0
  135. package/dist/types/adapters/fromWalletAdapter.d.ts +27 -0
  136. package/dist/types/adapters/fromWalletAdapter.d.ts.map +1 -0
  137. package/dist/types/adapters/fromWalletStandard.d.ts +32 -0
  138. package/dist/types/adapters/fromWalletStandard.d.ts.map +1 -0
  139. package/dist/types/adapters/resolveSignerSlot.d.ts +11 -0
  140. package/dist/types/adapters/resolveSignerSlot.d.ts.map +1 -0
  141. package/dist/types/client.d.ts +29 -14
  142. package/dist/types/client.d.ts.map +1 -1
  143. package/dist/types/decorators/smartWalletActions.d.ts +2 -0
  144. package/dist/types/decorators/smartWalletActions.d.ts.map +1 -1
  145. package/dist/types/decorators/solanaSmartWalletActions.d.ts +17 -0
  146. package/dist/types/decorators/solanaSmartWalletActions.d.ts.map +1 -0
  147. package/dist/types/experimental/actions/requestQuoteV0.d.ts +48 -11
  148. package/dist/types/experimental/actions/requestQuoteV0.d.ts.map +1 -1
  149. package/dist/types/experimental/swapActionsDecorator.d.ts +3 -0
  150. package/dist/types/experimental/swapActionsDecorator.d.ts.map +1 -1
  151. package/dist/types/exports/index.d.ts +5 -3
  152. package/dist/types/exports/index.d.ts.map +1 -1
  153. package/dist/types/exports/solana.d.ts +25 -0
  154. package/dist/types/exports/solana.d.ts.map +1 -0
  155. package/dist/types/types.d.ts +28 -4
  156. package/dist/types/types.d.ts.map +1 -1
  157. package/dist/types/utils/assertions.d.ts +4 -2
  158. package/dist/types/utils/assertions.d.ts.map +1 -1
  159. package/dist/types/utils/capabilities.d.ts +22 -6
  160. package/dist/types/utils/capabilities.d.ts.map +1 -1
  161. package/dist/types/utils/format.d.ts +2 -2
  162. package/dist/types/utils/format.d.ts.map +1 -1
  163. package/dist/types/utils/schema.d.ts +14 -14
  164. package/dist/types/utils/schema.d.ts.map +1 -1
  165. package/dist/types/version.d.ts +1 -1
  166. package/dist/types/version.d.ts.map +1 -1
  167. package/package.json +26 -9
  168. package/src/actions/prepareCalls.ts +21 -3
  169. package/src/actions/requestAccount.ts +7 -5
  170. package/src/actions/sendCalls.ts +5 -2
  171. package/src/actions/sendPreparedCalls.ts +4 -1
  172. package/src/actions/signPreparedCalls.ts +15 -2
  173. package/src/actions/signSignatureRequest.ts +8 -8
  174. package/src/actions/signTypedData.ts +15 -7
  175. package/src/actions/solana/getCallsStatus.ts +79 -0
  176. package/src/actions/solana/prepareCalls.ts +120 -0
  177. package/src/actions/solana/sendCalls.ts +66 -0
  178. package/src/actions/solana/sendPreparedCalls.ts +65 -0
  179. package/src/actions/solana/signPreparedCalls.ts +50 -0
  180. package/src/actions/solana/signSignatureRequest.ts +63 -0
  181. package/src/actions/solana/waitForCallsStatus.ts +84 -0
  182. package/src/actions/undelegateAccount.ts +68 -0
  183. package/src/adapters/SolanaSignerError.ts +5 -0
  184. package/src/adapters/fromKeypair.ts +58 -0
  185. package/src/adapters/fromKitSigner.ts +82 -0
  186. package/src/adapters/fromWalletAdapter.ts +58 -0
  187. package/src/adapters/fromWalletStandard.ts +100 -0
  188. package/src/adapters/resolveSignerSlot.ts +46 -0
  189. package/src/client.ts +131 -18
  190. package/src/decorators/smartWalletActions.ts +11 -2
  191. package/src/decorators/solanaSmartWalletActions.ts +62 -0
  192. package/src/experimental/actions/requestQuoteV0.ts +40 -15
  193. package/src/experimental/swapActionsDecorator.ts +3 -0
  194. package/src/exports/index.ts +10 -4
  195. package/src/exports/solana.ts +36 -0
  196. package/src/types.ts +38 -7
  197. package/src/utils/assertions.ts +17 -2
  198. package/src/utils/capabilities.ts +40 -8
  199. package/src/utils/format.ts +8 -3
  200. package/src/utils/schema.ts +58 -69
  201. package/src/version.ts +1 -1
@@ -0,0 +1,120 @@
1
+ import type { Prettify } from "viem";
2
+ import type {
3
+ DistributiveOmit,
4
+ InnerSolanaWalletApiClient,
5
+ } from "../../types.js";
6
+ import { isSolanaChain } from "../../utils/assertions.js";
7
+ import type { SolanaChainId } from "@alchemy/wallet-api-types";
8
+ import { SolanaPrepareCallsParams as SolanaPrepareCallsSchema } from "@alchemy/wallet-api-types";
9
+ import { wallet_prepareCalls as MethodSchema } from "@alchemy/wallet-api-types/rpc";
10
+ import type { z } from "zod";
11
+ import { BaseError } from "@alchemy/common";
12
+ import { LOGGER } from "../../logger.js";
13
+ import {
14
+ mergeSolanaClientCapabilities,
15
+ type WithCapabilities,
16
+ } from "../../utils/capabilities.js";
17
+ import {
18
+ methodSchema,
19
+ encode,
20
+ decode,
21
+ type MethodResponse,
22
+ } from "../../utils/schema.js";
23
+
24
+ const schema = methodSchema(MethodSchema);
25
+ type PrepareCallsResponse = MethodResponse<typeof MethodSchema>;
26
+
27
+ type BaseSolanaPrepareCallsParams = z.output<typeof SolanaPrepareCallsSchema>;
28
+
29
+ export type SolanaPrepareCallsParams = Prettify<
30
+ WithCapabilities<
31
+ DistributiveOmit<BaseSolanaPrepareCallsParams, "from" | "chainId"> & {
32
+ account?: string;
33
+ chainId?: SolanaChainId;
34
+ }
35
+ >
36
+ >;
37
+
38
+ type SolanaPrepareCallsResponse = Extract<
39
+ PrepareCallsResponse,
40
+ { type: "solana-transaction-v0" }
41
+ >;
42
+
43
+ function isSolanaResponse(
44
+ response: PrepareCallsResponse,
45
+ ): response is SolanaPrepareCallsResponse {
46
+ return response.type === "solana-transaction-v0";
47
+ }
48
+
49
+ export type SolanaPrepareCallsResult = SolanaPrepareCallsResponse;
50
+
51
+ /**
52
+ * Prepares Solana instructions for execution by building a versioned transaction.
53
+ * Returns the compiled transaction and a signature request that needs to be signed
54
+ * before submitting to sendPreparedCalls.
55
+ *
56
+ * @param {InnerSolanaWalletApiClient} client - The Solana wallet API client
57
+ * @param {SolanaPrepareCallsParams} params - Parameters for preparing Solana calls
58
+ * @param {Array<{programId: string, accounts?: Array, data: Hex}>} params.calls - Array of Solana instructions
59
+ * @param {string} [params.account] - The Solana address to execute from. Defaults to the signer's address.
60
+ * @param {SolanaChainId} [params.chainId] - The Solana chain ID. Defaults to the client's chain.
61
+ * @param {object} [params.capabilities] - Optional capabilities (e.g. paymaster sponsorship)
62
+ * @returns {Promise<SolanaPrepareCallsResult>} The prepared Solana transaction with signature request
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * const result = await client.prepareCalls({
67
+ * calls: [{
68
+ * programId: "11111111111111111111111111111111",
69
+ * data: "0x...",
70
+ * }],
71
+ * capabilities: {
72
+ * paymaster: { policyId: "your-policy-id" }
73
+ * }
74
+ * });
75
+ * ```
76
+ */
77
+ export async function prepareCalls(
78
+ client: InnerSolanaWalletApiClient,
79
+ params: SolanaPrepareCallsParams,
80
+ ): Promise<SolanaPrepareCallsResult> {
81
+ const { account, chainId, capabilities: caps, ...rest } = params;
82
+ const from = account ?? client.solanaAccount;
83
+ if (!isSolanaChain(client.chain)) {
84
+ throw new BaseError("Expected a Solana chain on the client");
85
+ }
86
+ const resolvedChainId = chainId ?? client.chain.solanaChainId;
87
+
88
+ const merged = mergeSolanaClientCapabilities(client, caps);
89
+ const capabilities = merged?.paymaster
90
+ ? { paymasterService: merged.paymaster }
91
+ : undefined;
92
+
93
+ LOGGER.debug("solana:prepareCalls:start", {
94
+ callsCount: params.calls?.length,
95
+ hasCapabilities: !!caps,
96
+ });
97
+
98
+ const rpcParams = encode(SolanaPrepareCallsSchema, {
99
+ ...rest,
100
+ chainId: resolvedChainId,
101
+ from,
102
+ capabilities,
103
+ });
104
+
105
+ const rpcResp = await client.request({
106
+ method: "wallet_prepareCalls",
107
+ params: [rpcParams],
108
+ });
109
+
110
+ LOGGER.debug("solana:prepareCalls:done");
111
+ const decoded = decode(schema.response, rpcResp);
112
+
113
+ if (!isSolanaResponse(decoded)) {
114
+ throw new BaseError(
115
+ `Unexpected EVM response from Solana prepareCalls: ${decoded.type}`,
116
+ );
117
+ }
118
+
119
+ return decoded;
120
+ }
@@ -0,0 +1,66 @@
1
+ import type { Prettify } from "viem";
2
+ import type {
3
+ DistributiveOmit,
4
+ InnerSolanaWalletApiClient,
5
+ } from "../../types.js";
6
+ import type { SolanaChainId } from "@alchemy/wallet-api-types";
7
+ import { prepareCalls, type SolanaPrepareCallsParams } from "./prepareCalls.js";
8
+ import { signPreparedCalls } from "./signPreparedCalls.js";
9
+ import {
10
+ sendPreparedCalls,
11
+ type SolanaSendPreparedCallsResult,
12
+ } from "./sendPreparedCalls.js";
13
+ import { LOGGER } from "../../logger.js";
14
+
15
+ export type SolanaSendCallsParams = Prettify<
16
+ DistributiveOmit<SolanaPrepareCallsParams, "chainId"> & {
17
+ chainId?: SolanaChainId;
18
+ }
19
+ >;
20
+
21
+ export type SolanaSendCallsResult = Prettify<SolanaSendPreparedCallsResult>;
22
+
23
+ /**
24
+ * Prepares, signs, and submits Solana instructions in a single call.
25
+ * Internally calls `prepareCalls`, `signPreparedCalls`, and `sendPreparedCalls`.
26
+ *
27
+ * @param {InnerSolanaWalletApiClient} client - The Solana wallet API client
28
+ * @param {SolanaSendCallsParams} params - Parameters for sending Solana calls
29
+ * @param {Array<{programId: string, accounts?: Array, data: Hex}>} params.calls - Array of Solana instructions
30
+ * @param {string} [params.account] - The Solana address to execute from. Defaults to the signer's address.
31
+ * @param {object} [params.capabilities] - Optional capabilities (e.g. paymaster sponsorship)
32
+ * @returns {Promise<SolanaSendCallsResult>} The result containing the call ID
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const result = await client.sendCalls({
37
+ * calls: [{
38
+ * programId: "11111111111111111111111111111111",
39
+ * data: "0x...",
40
+ * }],
41
+ * capabilities: {
42
+ * paymaster: { policyId: "your-policy-id" }
43
+ * }
44
+ * });
45
+ * ```
46
+ */
47
+ export async function sendCalls(
48
+ client: InnerSolanaWalletApiClient,
49
+ params: SolanaSendCallsParams,
50
+ ): Promise<SolanaSendCallsResult> {
51
+ LOGGER.info("solana:sendCalls:start", {
52
+ calls: params.calls?.length,
53
+ hasCapabilities: !!params.capabilities,
54
+ });
55
+
56
+ const { chainId, ...rest } = params;
57
+ const prepared = await prepareCalls(client, {
58
+ ...rest,
59
+ ...(chainId != null ? { chainId } : {}),
60
+ });
61
+
62
+ const signed = await signPreparedCalls(client, prepared);
63
+ const res = await sendPreparedCalls(client, signed);
64
+ LOGGER.info("solana:sendCalls:done");
65
+ return res;
66
+ }
@@ -0,0 +1,65 @@
1
+ import type { Prettify } from "viem";
2
+ import type { InnerSolanaWalletApiClient } from "../../types.js";
3
+ import { PreparedCall_SolanaV0_Signed as PreparedCall_SolanaV0_SignedSchema } from "@alchemy/wallet-api-types";
4
+ import type { z } from "zod";
5
+ import { BaseError } from "@alchemy/common";
6
+ import { LOGGER } from "../../logger.js";
7
+ import { wallet_sendPreparedCalls as MethodSchema } from "@alchemy/wallet-api-types/rpc";
8
+ import {
9
+ methodSchema,
10
+ encode,
11
+ decode,
12
+ type MethodResponse,
13
+ } from "../../utils/schema.js";
14
+
15
+ const schema = methodSchema(MethodSchema);
16
+ type SendPreparedCallsResponse = MethodResponse<typeof MethodSchema>;
17
+
18
+ export type SolanaSendPreparedCallsParams = Prettify<
19
+ z.output<typeof PreparedCall_SolanaV0_SignedSchema>
20
+ >;
21
+
22
+ type SolanaSendPreparedCallsResponse = Extract<
23
+ SendPreparedCallsResponse,
24
+ { details: { type: "solana-transaction-v0" } }
25
+ >;
26
+
27
+ export type SolanaSendPreparedCallsResult = SolanaSendPreparedCallsResponse;
28
+
29
+ function isSolanaResponse(
30
+ response: SendPreparedCallsResponse,
31
+ ): response is SolanaSendPreparedCallsResult {
32
+ return response.details.type === "solana-transaction-v0";
33
+ }
34
+
35
+ /**
36
+ * Sends a signed Solana transaction.
37
+ * This method is used after signing the signature request returned from prepareCalls.
38
+ *
39
+ * @param {InnerSolanaWalletApiClient} client - The Solana wallet API client
40
+ * @param {SolanaSendPreparedCallsParams} params - The signed Solana transaction
41
+ * @returns {Promise<SolanaSendPreparedCallsResult>} The result containing the call ID
42
+ */
43
+ export async function sendPreparedCalls(
44
+ client: InnerSolanaWalletApiClient,
45
+ params: SolanaSendPreparedCallsParams,
46
+ ): Promise<SolanaSendPreparedCallsResult> {
47
+ LOGGER.debug("solana:sendPreparedCalls:start", { type: params.type });
48
+
49
+ const rpcParams = encode(PreparedCall_SolanaV0_SignedSchema, params);
50
+ const rpcResp = await client.request({
51
+ method: "wallet_sendPreparedCalls",
52
+ params: [rpcParams],
53
+ });
54
+
55
+ LOGGER.debug("solana:sendPreparedCalls:done");
56
+ const decoded = decode(schema.response, rpcResp);
57
+
58
+ if (!isSolanaResponse(decoded)) {
59
+ throw new BaseError(
60
+ `Unexpected EVM response from Solana sendPreparedCalls: ${decoded.details.type}`,
61
+ );
62
+ }
63
+
64
+ return decoded;
65
+ }
@@ -0,0 +1,50 @@
1
+ import type { Prettify } from "viem";
2
+ import type { InnerSolanaWalletApiClient } from "../../types.js";
3
+ import {
4
+ signSolanaSignatureRequest,
5
+ type SolanaSignatureResult,
6
+ } from "./signSignatureRequest.js";
7
+ import type { SolanaPrepareCallsResult } from "./prepareCalls.js";
8
+ import { LOGGER } from "../../logger.js";
9
+
10
+ export type SolanaSignPreparedCallsParams = Prettify<SolanaPrepareCallsResult>;
11
+
12
+ export type SolanaSignPreparedCallsResult = Prettify<
13
+ Omit<
14
+ SolanaPrepareCallsResult,
15
+ "signatureRequest" | "feePayment" | "details"
16
+ > & {
17
+ signature: SolanaSignatureResult;
18
+ }
19
+ >;
20
+
21
+ /**
22
+ * Signs a prepared Solana transaction using the client's Ed25519 signer.
23
+ *
24
+ * @param {InnerSolanaWalletApiClient} client - The Solana wallet client
25
+ * @param {SolanaSignPreparedCallsParams} params - The prepared Solana transaction with signature request
26
+ * @returns {Promise<SolanaSignPreparedCallsResult>} The signed Solana transaction
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const prepared = await client.prepareCalls({ ... });
31
+ * const signed = await client.signPreparedCalls(prepared);
32
+ * const result = await client.sendPreparedCalls(signed);
33
+ * ```
34
+ */
35
+ export async function signPreparedCalls(
36
+ client: InnerSolanaWalletApiClient,
37
+ params: SolanaSignPreparedCallsParams,
38
+ ): Promise<SolanaSignPreparedCallsResult> {
39
+ LOGGER.debug("solana:signPreparedCalls:start");
40
+
41
+ const signature = await signSolanaSignatureRequest(
42
+ client.owner,
43
+ params.signatureRequest,
44
+ );
45
+
46
+ const { signatureRequest: _, feePayment: __, details: ___, ...rest } = params;
47
+
48
+ LOGGER.debug("solana:signPreparedCalls:done");
49
+ return { ...rest, signature };
50
+ }
@@ -0,0 +1,63 @@
1
+ import type { SolanaSigner } from "../../types.js";
2
+ import { LOGGER } from "../../logger.js";
3
+ import { hexToBytes } from "viem";
4
+ import { Base58 } from "ox";
5
+ import { findSignerSlot } from "../../adapters/resolveSignerSlot.js";
6
+ import { SolanaSignerError } from "../../adapters/SolanaSignerError.js";
7
+
8
+ export type SolanaSignatureRequestParams = {
9
+ type: "solana_signTransaction";
10
+ data: `0x${string}`;
11
+ };
12
+
13
+ export type SolanaSignatureResult = {
14
+ type: "ed25519";
15
+ data: string;
16
+ };
17
+
18
+ export async function signSolanaSignatureRequest(
19
+ signer: SolanaSigner,
20
+ signatureRequest: SolanaSignatureRequestParams,
21
+ ): Promise<SolanaSignatureResult> {
22
+ const txBytes = hexToBytes(signatureRequest.data);
23
+
24
+ const slotIndex = await findSignerSlot(txBytes, signer.address);
25
+ if (slotIndex < 0) {
26
+ throw new SolanaSignerError(
27
+ `Signer ${signer.address} is not a required signer in this transaction`,
28
+ );
29
+ }
30
+
31
+ LOGGER.debug("signSolanaSignatureRequest:signing");
32
+
33
+ const { signedTransaction } = await signer.signTransaction({
34
+ transaction: txBytes,
35
+ });
36
+
37
+ if (signedTransaction[0] !== txBytes[0]) {
38
+ throw new SolanaSignerError(
39
+ `Signer returned a transaction with a different signature count (expected ${txBytes[0]}, got ${signedTransaction[0]})`,
40
+ );
41
+ }
42
+
43
+ const offset = 1 + slotIndex * 64;
44
+ const rawSignature = signedTransaction.slice(offset, offset + 64);
45
+
46
+ if (rawSignature.length !== 64) {
47
+ throw new SolanaSignerError(
48
+ `Signed transaction too short to contain signature at slot ${slotIndex}`,
49
+ );
50
+ }
51
+
52
+ if (rawSignature.every((b) => b === 0)) {
53
+ throw new SolanaSignerError(
54
+ `Signer ${signer.address} did not produce a signature at slot ${slotIndex}`,
55
+ );
56
+ }
57
+
58
+ LOGGER.debug("signSolanaSignatureRequest:ok");
59
+ return {
60
+ type: "ed25519",
61
+ data: Base58.fromBytes(rawSignature),
62
+ };
63
+ }
@@ -0,0 +1,84 @@
1
+ import type { InnerSolanaWalletApiClient } from "../../types.js";
2
+ import {
3
+ getCallsStatus,
4
+ type SolanaGetCallsStatusResult,
5
+ } from "./getCallsStatus.js";
6
+ import { BaseError } from "@alchemy/common";
7
+ import { LOGGER } from "../../logger.js";
8
+
9
+ export type SolanaWaitForCallsStatusParams = {
10
+ id: `0x${string}`;
11
+ pollingInterval?: number;
12
+ retryCount?: number;
13
+ retryDelay?: (opts: { count: number }) => number;
14
+ status?: (result: SolanaGetCallsStatusResult) => boolean;
15
+ throwOnFailure?: boolean;
16
+ timeout?: number;
17
+ };
18
+
19
+ export type SolanaWaitForCallsStatusResult = SolanaGetCallsStatusResult;
20
+
21
+ /**
22
+ * Polls getCallsStatus until the call reaches a terminal state.
23
+ * Similar API to viem's waitForCallsStatus with retry, exponential backoff,
24
+ * configurable status predicate, throwOnFailure, and timeout.
25
+ *
26
+ * @param {InnerSolanaWalletApiClient} client - The Solana wallet API client
27
+ * @param {SolanaWaitForCallsStatusParams} params - The call ID and optional polling config
28
+ * @returns {Promise<SolanaWaitForCallsStatusResult>} The final status
29
+ */
30
+ export async function waitForCallsStatus(
31
+ client: InnerSolanaWalletApiClient,
32
+ params: SolanaWaitForCallsStatusParams,
33
+ ): Promise<SolanaWaitForCallsStatusResult> {
34
+ const {
35
+ id,
36
+ pollingInterval = client.pollingInterval,
37
+ retryCount = 4,
38
+ retryDelay = ({ count }: { count: number }) => ~~(1 << count) * 200,
39
+ status: isReady = ({ statusCode }) =>
40
+ statusCode === 200 || statusCode >= 300,
41
+ throwOnFailure = false,
42
+ timeout = 60_000,
43
+ } = params;
44
+
45
+ LOGGER.debug("solana:waitForCallsStatus:start", { id });
46
+
47
+ const start = Date.now();
48
+
49
+ while (Date.now() - start < timeout) {
50
+ let result: SolanaGetCallsStatusResult | undefined;
51
+
52
+ for (let attempt = 0; attempt <= retryCount; attempt++) {
53
+ try {
54
+ result = await getCallsStatus(client, { id });
55
+ break;
56
+ } catch (error) {
57
+ if (attempt >= retryCount) throw error;
58
+ await new Promise((r) => setTimeout(r, retryDelay({ count: attempt })));
59
+ }
60
+ }
61
+
62
+ if (!result) throw new BaseError("Unexpected: no result after retries");
63
+
64
+ if (throwOnFailure && result.status === "failure") {
65
+ throw new BaseError(
66
+ `Solana call bundle failed with status code ${result.statusCode}`,
67
+ );
68
+ }
69
+
70
+ if (isReady(result)) {
71
+ LOGGER.debug("solana:waitForCallsStatus:done", {
72
+ status: result.status,
73
+ statusCode: result.statusCode,
74
+ });
75
+ return result;
76
+ }
77
+
78
+ await new Promise((r) => setTimeout(r, pollingInterval));
79
+ }
80
+
81
+ throw new BaseError(
82
+ `Timed out while waiting for call bundle with id "${id}" to be confirmed.`,
83
+ );
84
+ }
@@ -0,0 +1,68 @@
1
+ import { zeroAddress, type Chain, type Prettify } from "viem";
2
+ import type { InnerWalletApiClient } from "../types.js";
3
+ import { LOGGER } from "../logger.js";
4
+ import { resolveAddress, type AccountParam } from "../utils/resolve.js";
5
+ import { sendCalls, type SendCallsResult } from "./sendCalls.js";
6
+
7
+ export type UndelegateAccountParams = Prettify<{
8
+ account?: AccountParam;
9
+ chain?: Pick<Chain, "id">;
10
+ capabilities?: {
11
+ paymaster?: {
12
+ policyId: string;
13
+ };
14
+ };
15
+ }>;
16
+
17
+ export type UndelegateAccountResult = Prettify<SendCallsResult>;
18
+
19
+ /**
20
+ * Prepares, signs, and sends an EIP-7702 undelegation to remove delegation from an EOA.
21
+ * Gas is sponsored by Alchemy (requires Enterprise plan).
22
+ *
23
+ * A BSO (Bundler Sponsorship Override) policy ID must be provided either via
24
+ * `params.capabilities.paymaster.policyId` or pre-configured on the client via `policyIds`.
25
+ *
26
+ * @param {InnerWalletApiClient} client - The wallet API client to use for the request
27
+ * @param {UndelegateAccountParams} params - Parameters for undelegating the account
28
+ * @param {AccountParam} [params.account] - The account to undelegate. Defaults to the client's account (signer address).
29
+ * @param {object} [params.chain] - The chain. Defaults to the client's chain.
30
+ * @param {object} [params.capabilities] - Optional capabilities. If omitted, falls back to the policy ID(s) set on the client.
31
+ * @param {object} [params.capabilities.paymaster] - Paymaster capabilities. Requires a BSO policy ID.
32
+ * @param {string} [params.capabilities.paymaster.policyId] - The BSO policy ID to use for gas sponsorship.
33
+ * @returns {Promise<UndelegateAccountResult>} A Promise that resolves to the result containing the call ID.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const result = await client.undelegateAccount();
38
+ * const status = await client.waitForCallsStatus({ id: result.id });
39
+ * ```
40
+ */
41
+ export async function undelegateAccount(
42
+ client: InnerWalletApiClient,
43
+ params?: UndelegateAccountParams,
44
+ ): Promise<UndelegateAccountResult> {
45
+ const account = params?.account
46
+ ? resolveAddress(params.account)
47
+ : client.account.address;
48
+
49
+ LOGGER.info("undelegateAccount:start", {
50
+ account,
51
+ chain: params?.chain,
52
+ });
53
+
54
+ const result = await sendCalls(client, {
55
+ calls: [],
56
+ account,
57
+ ...(params?.chain != null ? { chain: params.chain } : {}),
58
+ capabilities: {
59
+ ...params?.capabilities,
60
+ eip7702Auth: {
61
+ delegation: zeroAddress,
62
+ },
63
+ },
64
+ });
65
+
66
+ LOGGER.info("undelegateAccount:done", { id: result.id });
67
+ return result;
68
+ }
@@ -0,0 +1,5 @@
1
+ import { BaseError } from "@alchemy/common";
2
+
3
+ export class SolanaSignerError extends BaseError {
4
+ override name = "SolanaSignerError";
5
+ }
@@ -0,0 +1,58 @@
1
+ import type { SolanaSigner } from "../types.js";
2
+ import { SolanaSignerError } from "./SolanaSignerError.js";
3
+ import { findSignerSlot } from "./resolveSignerSlot.js";
4
+
5
+ /** Raw Ed25519 keypair signer (e.g. `Keypair` from `@solana/web3.js` v1 or a bare Ed25519 key). */
6
+ export interface SolanaKeypairSigner {
7
+ address: string;
8
+ signMessage(message: Uint8Array): Promise<Uint8Array>;
9
+ }
10
+
11
+ /**
12
+ * Adapts a raw Ed25519 keypair signer into a {@link SolanaSigner}.
13
+ *
14
+ * Use this for legacy `@solana/web3.js` v1 `Keypair` signers or any signer
15
+ * that exposes a `signMessage(bytes) => signature` interface. For
16
+ * `@solana/kit` signers, use {@link fromKitSigner}. For browser wallets
17
+ * (wallet adapter, Phantom, etc.), use {@link fromWalletAdapter}. For
18
+ * wallet-standard wallets, use {@link fromWalletStandard}.
19
+ *
20
+ * Requires `@solana/kit` or `@solana/web3.js` as a peer dependency.
21
+ *
22
+ * @param {SolanaKeypairSigner} signer - The raw Ed25519 keypair signer to adapt
23
+ * @returns {SolanaSigner} A SolanaSigner compatible with `createSmartWalletClient`
24
+ */
25
+ export function fromKeypair(signer: SolanaKeypairSigner): SolanaSigner {
26
+ return {
27
+ address: signer.address,
28
+ async signTransaction({ transaction }) {
29
+ const numSigs = transaction[0];
30
+ const messageStart = 1 + numSigs * 64;
31
+ const messageBytes = transaction.slice(messageStart);
32
+ let sig: Uint8Array;
33
+ try {
34
+ sig = await signer.signMessage(messageBytes);
35
+ } catch (e) {
36
+ throw new SolanaSignerError("Keypair signer failed to sign message", {
37
+ cause: e as Error,
38
+ });
39
+ }
40
+ if (sig.length !== 64) {
41
+ throw new SolanaSignerError(
42
+ `Expected a 64-byte Ed25519 signature but received ${sig.length} bytes`,
43
+ );
44
+ }
45
+
46
+ const slotIndex = await findSignerSlot(transaction, signer.address);
47
+ if (slotIndex < 0) {
48
+ throw new SolanaSignerError(
49
+ `Signer ${signer.address} is not a required signer in this transaction`,
50
+ );
51
+ }
52
+
53
+ const signedTx = new Uint8Array(transaction);
54
+ signedTx.set(sig, 1 + slotIndex * 64);
55
+ return { signedTransaction: signedTx };
56
+ },
57
+ };
58
+ }
@@ -0,0 +1,82 @@
1
+ import type { SolanaSigner } from "../types.js";
2
+ import { SolanaSignerError } from "./SolanaSignerError.js";
3
+ import { findSignerSlot } from "./resolveSignerSlot.js";
4
+
5
+ /** Any {@link https://solanakit.com @solana/kit} signer that implements `signTransactions` (e.g. `TransactionPartialSigner`, `KeyPairSigner`). */
6
+ export interface SolanaTransactionPartialSigner {
7
+ address: string;
8
+ signTransactions(
9
+ transactions: readonly unknown[],
10
+ ): Promise<readonly Record<string, Uint8Array>[]>;
11
+ }
12
+
13
+ /**
14
+ * Adapts an {@link https://solanakit.com @solana/kit} signer into a {@link SolanaSigner}.
15
+ *
16
+ * Accepts any signer that implements `signTransactions`, including
17
+ * `KeyPairSigner`, `TransactionPartialSigner`, and `NoopSigner`. For raw
18
+ * Ed25519 keypairs, use {@link fromKeypair}. For browser wallets (wallet
19
+ * adapter, Phantom, etc.), use {@link fromWalletAdapter}. For
20
+ * wallet-standard wallets, use {@link fromWalletStandard}.
21
+ *
22
+ * Requires `@solana/kit` as a peer dependency.
23
+ *
24
+ * @param {SolanaTransactionPartialSigner} signer - The @solana/kit signer to adapt
25
+ * @returns {SolanaSigner} A SolanaSigner compatible with `createSmartWalletClient`
26
+ */
27
+ export function fromKitSigner(
28
+ signer: SolanaTransactionPartialSigner,
29
+ ): SolanaSigner {
30
+ return {
31
+ address: signer.address,
32
+ async signTransaction({ transaction }) {
33
+ let tx: unknown;
34
+ try {
35
+ const { getTransactionCodec } = await import("@solana/kit");
36
+ const codec = getTransactionCodec();
37
+ tx = codec.decode(transaction);
38
+ } catch (e) {
39
+ throw new SolanaSignerError("Failed to decode transaction", {
40
+ cause: e as Error,
41
+ });
42
+ }
43
+
44
+ let sigDict: Record<string, Uint8Array> | undefined;
45
+ try {
46
+ [sigDict] = await signer.signTransactions([tx]);
47
+ } catch (e) {
48
+ throw new SolanaSignerError("Kit signer failed to sign transaction", {
49
+ cause: e as Error,
50
+ });
51
+ }
52
+ if (!sigDict) {
53
+ throw new SolanaSignerError(
54
+ "TransactionPartialSigner returned no signatures",
55
+ );
56
+ }
57
+
58
+ const sig = sigDict[signer.address];
59
+ if (!sig) {
60
+ throw new SolanaSignerError(
61
+ `TransactionPartialSigner did not produce a signature for ${signer.address}`,
62
+ );
63
+ }
64
+ if (sig.length !== 64) {
65
+ throw new SolanaSignerError(
66
+ `Expected a 64-byte Ed25519 signature but received ${sig.length} bytes`,
67
+ );
68
+ }
69
+
70
+ const slotIndex = await findSignerSlot(transaction, signer.address);
71
+ if (slotIndex < 0) {
72
+ throw new SolanaSignerError(
73
+ `Signer ${signer.address} is not a required signer in this transaction`,
74
+ );
75
+ }
76
+
77
+ const signedTx = new Uint8Array(transaction);
78
+ signedTx.set(sig, 1 + slotIndex * 64);
79
+ return { signedTransaction: signedTx };
80
+ },
81
+ };
82
+ }