@alchemy/wallet-apis 0.0.0-alpha.19 → 0.0.0-alpha.21

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 (56) hide show
  1. package/dist/esm/actions/formatSign.js +3 -4
  2. package/dist/esm/actions/formatSign.js.map +1 -1
  3. package/dist/esm/actions/grantPermissions.js +3 -4
  4. package/dist/esm/actions/grantPermissions.js.map +1 -1
  5. package/dist/esm/actions/listAccounts.js +3 -4
  6. package/dist/esm/actions/listAccounts.js.map +1 -1
  7. package/dist/esm/actions/prepareCalls.d.ts +14 -3
  8. package/dist/esm/actions/prepareCalls.js +19 -5
  9. package/dist/esm/actions/prepareCalls.js.map +1 -1
  10. package/dist/esm/actions/prepareSign.js +3 -4
  11. package/dist/esm/actions/prepareSign.js.map +1 -1
  12. package/dist/esm/actions/requestAccount.js +3 -4
  13. package/dist/esm/actions/requestAccount.js.map +1 -1
  14. package/dist/esm/actions/sendCalls.js +2 -5
  15. package/dist/esm/actions/sendCalls.js.map +1 -1
  16. package/dist/esm/actions/sendPreparedCalls.js +3 -4
  17. package/dist/esm/actions/sendPreparedCalls.js.map +1 -1
  18. package/dist/esm/experimental/actions/requestQuoteV0.js +3 -4
  19. package/dist/esm/experimental/actions/requestQuoteV0.js.map +1 -1
  20. package/dist/esm/utils/capabilities.d.ts +14 -7
  21. package/dist/esm/utils/capabilities.js +3 -2
  22. package/dist/esm/utils/capabilities.js.map +1 -1
  23. package/dist/esm/utils/schema.d.ts +3 -1
  24. package/dist/esm/utils/schema.js +58 -0
  25. package/dist/esm/utils/schema.js.map +1 -1
  26. package/dist/esm/version.d.ts +1 -1
  27. package/dist/esm/version.js +1 -1
  28. package/dist/esm/version.js.map +1 -1
  29. package/dist/types/actions/formatSign.d.ts.map +1 -1
  30. package/dist/types/actions/grantPermissions.d.ts.map +1 -1
  31. package/dist/types/actions/listAccounts.d.ts.map +1 -1
  32. package/dist/types/actions/prepareCalls.d.ts +14 -3
  33. package/dist/types/actions/prepareCalls.d.ts.map +1 -1
  34. package/dist/types/actions/prepareSign.d.ts.map +1 -1
  35. package/dist/types/actions/requestAccount.d.ts.map +1 -1
  36. package/dist/types/actions/sendCalls.d.ts.map +1 -1
  37. package/dist/types/actions/sendPreparedCalls.d.ts.map +1 -1
  38. package/dist/types/experimental/actions/requestQuoteV0.d.ts.map +1 -1
  39. package/dist/types/utils/capabilities.d.ts +14 -7
  40. package/dist/types/utils/capabilities.d.ts.map +1 -1
  41. package/dist/types/utils/schema.d.ts +3 -1
  42. package/dist/types/utils/schema.d.ts.map +1 -1
  43. package/dist/types/version.d.ts +1 -1
  44. package/package.json +4 -4
  45. package/src/actions/formatSign.ts +5 -4
  46. package/src/actions/grantPermissions.ts +9 -11
  47. package/src/actions/listAccounts.ts +5 -7
  48. package/src/actions/prepareCalls.ts +42 -6
  49. package/src/actions/prepareSign.ts +5 -4
  50. package/src/actions/requestAccount.ts +8 -7
  51. package/src/actions/sendCalls.ts +2 -8
  52. package/src/actions/sendPreparedCalls.ts +4 -6
  53. package/src/experimental/actions/requestQuoteV0.ts +5 -4
  54. package/src/utils/capabilities.ts +23 -11
  55. package/src/utils/schema.ts +79 -1
  56. package/src/version.ts +1 -1
@@ -5,8 +5,12 @@ import deepEqual from "deep-equal";
5
5
  import type { DistributiveOmit, InnerWalletApiClient } from "../types";
6
6
  import { LOGGER } from "../logger.js";
7
7
  import { isLocalAccount } from "../utils/assertions.js";
8
- import { Value } from "typebox/value";
9
- import { methodSchema, type MethodParams } from "../utils/schema.js";
8
+ import {
9
+ methodSchema,
10
+ encode,
11
+ decode,
12
+ type MethodParams,
13
+ } from "../utils/schema.js";
10
14
 
11
15
  const schema = methodSchema(MethodSchema);
12
16
  type BaseRequestAccountParams = MethodParams<typeof MethodSchema>;
@@ -90,17 +94,14 @@ export async function requestAccount(
90
94
  };
91
95
  }
92
96
 
93
- const rpcParams = Value.Encode(
94
- schema.request,
95
- args satisfies BaseRequestAccountParams,
96
- );
97
+ const rpcParams = encode(schema.request, args);
97
98
 
98
99
  const rpcResp = await client.request({
99
100
  method: "wallet_requestAccount",
100
101
  params: [rpcParams],
101
102
  });
102
103
 
103
- const resp = Value.Decode(schema.response, rpcResp);
104
+ const resp = decode(schema.response, rpcResp);
104
105
 
105
106
  client.internal?.setAccount({
106
107
  address: resp.accountAddress,
@@ -8,10 +8,7 @@ import {
8
8
  } from "./sendPreparedCalls.js";
9
9
  import { LOGGER } from "../logger.js";
10
10
  import { signSignatureRequest } from "./signSignatureRequest.js";
11
- import {
12
- extractCapabilitiesForSending,
13
- fromRpcCapabilities,
14
- } from "../utils/capabilities.js";
11
+ import { extractCapabilitiesForSending } from "../utils/capabilities.js";
15
12
 
16
13
  export type SendCallsParams = Prettify<
17
14
  DistributiveOmit<PrepareCallsParams, "chainId"> & {
@@ -77,10 +74,7 @@ export async function sendCalls(
77
74
  );
78
75
 
79
76
  const secondCallParams = {
80
- account: calls.modifiedRequest.from,
81
- calls: calls.modifiedRequest.calls,
82
- chainId: calls.modifiedRequest.chainId,
83
- capabilities: fromRpcCapabilities(calls.modifiedRequest.capabilities),
77
+ ...calls.modifiedRequest,
84
78
  // WebAuthn signatures are not supported for paymaster permits (throws above).
85
79
  paymasterPermitSignature: signature as Exclude<
86
80
  typeof signature,
@@ -7,9 +7,10 @@ import {
7
7
  type WithCapabilities,
8
8
  } from "../utils/capabilities.js";
9
9
  import { wallet_sendPreparedCalls as MethodSchema } from "@alchemy/wallet-api-types/rpc";
10
- import { Value } from "typebox/value";
11
10
  import {
12
11
  methodSchema,
12
+ encode,
13
+ decode,
13
14
  type MethodParams,
14
15
  type MethodResponse,
15
16
  } from "../utils/schema.js";
@@ -79,10 +80,7 @@ export async function sendPreparedCalls(
79
80
  capabilities: toRpcCapabilities(capabilities),
80
81
  };
81
82
 
82
- const rpcParams = Value.Encode(
83
- schema.request,
84
- fullParams satisfies BaseSendPreparedCallsParams,
85
- );
83
+ const rpcParams = encode(schema.request, fullParams);
86
84
 
87
85
  const rpcResp = await client.request({
88
86
  method: "wallet_sendPreparedCalls",
@@ -90,5 +88,5 @@ export async function sendPreparedCalls(
90
88
  });
91
89
 
92
90
  LOGGER.debug("sendPreparedCalls:done");
93
- return Value.Decode(schema.response, rpcResp);
91
+ return decode(schema.response, rpcResp);
94
92
  }
@@ -7,9 +7,10 @@ import {
7
7
  } from "../../utils/capabilities.js";
8
8
  import { resolveAddress, type AccountParam } from "../../utils/resolve.js";
9
9
  import { wallet_requestQuote_v0 as MethodSchema } from "@alchemy/wallet-api-types/rpc";
10
- import { Value } from "typebox/value";
11
10
  import {
12
11
  methodSchema,
12
+ encode,
13
+ decode,
13
14
  type MethodParams,
14
15
  type MethodResponse,
15
16
  } from "../../utils/schema.js";
@@ -84,17 +85,17 @@ export async function requestQuoteV0(
84
85
  );
85
86
 
86
87
  const { account: _, chainId: __, ...rest } = params;
87
- const rpcParams = Value.Encode(schema.request, {
88
+ const rpcParams = encode(schema.request, {
88
89
  ...rest,
89
90
  chainId: params.chainId ?? client.chain.id,
90
91
  from,
91
92
  ...(capabilities && { capabilities: toRpcCapabilities(capabilities) }),
92
- } satisfies BaseRequestQuoteV0Params);
93
+ });
93
94
 
94
95
  const rpcResp = await client.request({
95
96
  method: "wallet_requestQuote_v0",
96
97
  params: [rpcParams],
97
98
  });
98
99
 
99
- return Value.Decode(schema.response, rpcResp);
100
+ return decode(schema.response, rpcResp);
100
101
  }
@@ -1,9 +1,21 @@
1
- import type {
2
- PrepareCallsCapabilities as RpcPrepareCallsCapabilities,
3
- SendPreparedCallsCapabilities as RpcSendPreparedCallsCapabilities,
1
+ import {
2
+ PrepareCallsCapabilities as PrepareCallsCapabilitiesSchema,
3
+ SendPreparedCallsCapabilities as SendPreparedCallsCapabilitiesSchema,
4
4
  } from "@alchemy/wallet-api-types/capabilities";
5
+ import type { StaticDecode } from "typebox";
5
6
  import type { InnerWalletApiClient } from "../types.js";
6
7
 
8
+ /**
9
+ * Decoded capabilities matching the schema shape (uses `paymasterService` key).
10
+ * `ResolveCapabilities` renames this to `paymaster` for client-facing types.
11
+ */
12
+ type DecodedPrepareCallsCaps = StaticDecode<
13
+ typeof PrepareCallsCapabilitiesSchema
14
+ >;
15
+ type DecodedSendPreparedCallsCaps = StaticDecode<
16
+ typeof SendPreparedCallsCapabilitiesSchema
17
+ >;
18
+
7
19
  /**
8
20
  * Renames `paymasterService` (RPC) to `paymaster` in a capabilities type. This
9
21
  * is because our RPC schema's paymasterService capability does not exactly match
@@ -17,10 +29,10 @@ type ResolveCapabilities<T> = T extends {
17
29
  : T;
18
30
 
19
31
  export type PrepareCallsCapabilities =
20
- ResolveCapabilities<RpcPrepareCallsCapabilities>;
32
+ ResolveCapabilities<DecodedPrepareCallsCaps>;
21
33
 
22
34
  export type SendPreparedCallsCapabilities =
23
- ResolveCapabilities<RpcSendPreparedCallsCapabilities>;
35
+ ResolveCapabilities<DecodedSendPreparedCallsCaps>;
24
36
 
25
37
  /**
26
38
  * Transforms a type so that any `capabilities` field uses `paymaster`
@@ -36,7 +48,7 @@ export type WithCapabilities<T> = T extends {
36
48
 
37
49
  function hasNoPaymasterField(
38
50
  value: object,
39
- ): value is RpcPrepareCallsCapabilities | RpcSendPreparedCallsCapabilities {
51
+ ): value is DecodedPrepareCallsCaps | DecodedSendPreparedCallsCaps {
40
52
  return !("paymaster" in value);
41
53
  }
42
54
 
@@ -51,14 +63,14 @@ function hasNoPaymasterServiceField(
51
63
  * for use with Value.Encode before sending to the RPC.
52
64
  *
53
65
  * @param {PrepareCallsCapabilities | SendPreparedCallsCapabilities | undefined} capabilities - Capabilities object containing a `paymaster` field
54
- * @returns {RpcPrepareCallsCapabilities | RpcSendPreparedCallsCapabilities | undefined} RPC capabilities with `paymasterService`, or undefined if input is undefined
66
+ * @returns {DecodedPrepareCallsCaps | DecodedSendPreparedCallsCaps | undefined} RPC capabilities with `paymasterService`, or undefined if input is undefined
55
67
  */
56
68
  export function toRpcCapabilities(
57
69
  capabilities:
58
70
  | PrepareCallsCapabilities
59
71
  | SendPreparedCallsCapabilities
60
72
  | undefined,
61
- ): RpcPrepareCallsCapabilities | RpcSendPreparedCallsCapabilities | undefined {
73
+ ): DecodedPrepareCallsCaps | DecodedSendPreparedCallsCaps | undefined {
62
74
  if (!capabilities) return undefined;
63
75
  const { paymaster, ...rest } = capabilities;
64
76
  const result =
@@ -73,13 +85,13 @@ export function toRpcCapabilities(
73
85
  * Converts RPC capabilities (with `paymasterService`) from Value.Decode
74
86
  * to capabilities (with `paymaster`).
75
87
  *
76
- * @param {RpcPrepareCallsCapabilities | RpcSendPreparedCallsCapabilities | undefined} capabilities - RPC capabilities object containing a `paymasterService` field
88
+ * @param {DecodedPrepareCallsCaps | DecodedSendPreparedCallsCaps | undefined} capabilities - RPC capabilities object containing a `paymasterService` field
77
89
  * @returns {PrepareCallsCapabilities | SendPreparedCallsCapabilities | undefined} Capabilities with `paymaster`, or undefined if input is undefined
78
90
  */
79
91
  export function fromRpcCapabilities(
80
92
  capabilities:
81
- | RpcPrepareCallsCapabilities
82
- | RpcSendPreparedCallsCapabilities
93
+ | DecodedPrepareCallsCaps
94
+ | DecodedSendPreparedCallsCaps
83
95
  | undefined,
84
96
  ): PrepareCallsCapabilities | SendPreparedCallsCapabilities | undefined {
85
97
  if (!capabilities) return undefined;
@@ -1,4 +1,12 @@
1
- import type { TObject, TSchema, TTuple, StaticDecode } from "typebox";
1
+ import type {
2
+ TObject,
3
+ TSchema,
4
+ TTuple,
5
+ StaticDecode,
6
+ StaticEncode,
7
+ } from "typebox";
8
+ import { Value, EncodeError, DecodeError, Pointer } from "typebox/value";
9
+ import { BaseError } from "@alchemy/common";
2
10
 
3
11
  /** Constraint for RPC method schemas from `@alchemy/wallet-api-types/rpc`. */
4
12
  type RpcMethodSchema = TObject<{
@@ -30,3 +38,73 @@ export type MethodParams<T extends RpcMethodSchema> = StaticDecode<
30
38
  export type MethodResponse<T extends RpcMethodSchema> = StaticDecode<
31
39
  T["properties"]["ReturnType"]
32
40
  >;
41
+
42
+ /**
43
+ * Formats an {@link EncodeError} or {@link DecodeError} into a human-readable
44
+ * string describing what went wrong, including the JSON path and the schema's
45
+ * custom error message (if any).
46
+ *
47
+ * @param {TSchema} schema - The TypeBox schema that validation was run against.
48
+ * @param {EncodeError | DecodeError} error - The error thrown by {@link Value.Encode} or {@link Value.Decode}.
49
+ * @returns {string} A formatted error string prefixed with `"Invalid params"`.
50
+ */
51
+ function formatCodecError(
52
+ schema: TSchema,
53
+ error: EncodeError | DecodeError,
54
+ ): string {
55
+ // Use only the first error — it's the most specific. Subsequent errors are
56
+ // typically cascade noise from union/anyOf branches.
57
+ const causeError = error.cause.errors[0];
58
+ // errors is typed as an open array — guard against the (practically
59
+ // impossible) empty case.
60
+ if (!causeError) return "Invalid params";
61
+
62
+ const path = causeError.instancePath || "(root)";
63
+
64
+ // Prefer the schema's custom errorMessage annotation over the generic locale message.
65
+ let message = causeError.message;
66
+ const schemaPointer = causeError.schemaPath.replace(/^#/, "");
67
+ if (schemaPointer) {
68
+ const schemaNode = Pointer.Get(schema, schemaPointer);
69
+ if (
70
+ schemaNode &&
71
+ typeof schemaNode === "object" &&
72
+ "errorMessage" in schemaNode &&
73
+ typeof (schemaNode as Record<string, unknown>).errorMessage === "string"
74
+ ) {
75
+ message = (schemaNode as Record<string, unknown>).errorMessage as string;
76
+ }
77
+ }
78
+
79
+ return `Invalid params: ${path}: ${message}`;
80
+ }
81
+
82
+ // Type-safe wrapper around `Value.Encode` with human-readable errors.
83
+ export function encode<const T extends TSchema>(
84
+ schema: T,
85
+ value: StaticDecode<T>,
86
+ ): StaticEncode<T> {
87
+ try {
88
+ return Value.Encode(schema, value);
89
+ } catch (error) {
90
+ if (error instanceof EncodeError) {
91
+ throw new BaseError(formatCodecError(schema, error), { cause: error });
92
+ }
93
+ throw error;
94
+ }
95
+ }
96
+
97
+ // Type-safe wrapper around `Value.Decode` with human-readable errors.
98
+ export function decode<const T extends TSchema>(
99
+ schema: T,
100
+ value: StaticEncode<T>,
101
+ ): StaticDecode<T> {
102
+ try {
103
+ return Value.Decode(schema, value);
104
+ } catch (error) {
105
+ if (error instanceof DecodeError) {
106
+ throw new BaseError(formatCodecError(schema, error), { cause: error });
107
+ }
108
+ throw error;
109
+ }
110
+ }
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.19";
3
+ export const VERSION = "0.0.0-alpha.21";