@coinbase/cdp-sdk 1.17.0 → 1.19.0

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 (90) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/_cjs/accounts/evm/resolveViemClients.js +241 -0
  3. package/_cjs/accounts/evm/resolveViemClients.js.map +1 -0
  4. package/_cjs/accounts/evm/toEvmServerAccount.js +1 -1
  5. package/_cjs/accounts/evm/toEvmServerAccount.js.map +1 -1
  6. package/_cjs/accounts/evm/toNetworkScopedEvmServerAccount.js +37 -1
  7. package/_cjs/accounts/evm/toNetworkScopedEvmServerAccount.js.map +1 -1
  8. package/_cjs/auth/hooks/axios/withAuth.js +5 -0
  9. package/_cjs/auth/hooks/axios/withAuth.js.map +1 -1
  10. package/_cjs/auth/utils/jwt.js +4 -1
  11. package/_cjs/auth/utils/jwt.js.map +1 -1
  12. package/_cjs/index.js +3 -1
  13. package/_cjs/index.js.map +1 -1
  14. package/_cjs/openapi-client/cdpApiClient.js +8 -2
  15. package/_cjs/openapi-client/cdpApiClient.js.map +1 -1
  16. package/_cjs/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js +2 -0
  17. package/_cjs/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js.map +1 -1
  18. package/_cjs/openapi-client/generated/index.msw.js +4 -4
  19. package/_cjs/openapi-client/generated/index.msw.js.map +1 -1
  20. package/_cjs/utils/bigint.js +24 -0
  21. package/_cjs/utils/bigint.js.map +1 -0
  22. package/_cjs/utils/hash.js +7 -0
  23. package/_cjs/utils/hash.js.map +1 -0
  24. package/_cjs/utils/sortKeys.js +26 -0
  25. package/_cjs/utils/sortKeys.js.map +1 -0
  26. package/_cjs/version.js +1 -1
  27. package/_esm/accounts/evm/resolveViemClients.js +205 -0
  28. package/_esm/accounts/evm/resolveViemClients.js.map +1 -0
  29. package/_esm/accounts/evm/toEvmServerAccount.js +1 -1
  30. package/_esm/accounts/evm/toEvmServerAccount.js.map +1 -1
  31. package/_esm/accounts/evm/toNetworkScopedEvmServerAccount.js +37 -1
  32. package/_esm/accounts/evm/toNetworkScopedEvmServerAccount.js.map +1 -1
  33. package/_esm/auth/hooks/axios/withAuth.js +5 -0
  34. package/_esm/auth/hooks/axios/withAuth.js.map +1 -1
  35. package/_esm/auth/utils/jwt.js +4 -1
  36. package/_esm/auth/utils/jwt.js.map +1 -1
  37. package/_esm/index.js +1 -0
  38. package/_esm/index.js.map +1 -1
  39. package/_esm/openapi-client/cdpApiClient.js +7 -1
  40. package/_esm/openapi-client/cdpApiClient.js.map +1 -1
  41. package/_esm/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js +2 -0
  42. package/_esm/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js.map +1 -1
  43. package/_esm/openapi-client/generated/index.msw.js +4 -4
  44. package/_esm/openapi-client/generated/index.msw.js.map +1 -1
  45. package/_esm/utils/bigint.js +20 -0
  46. package/_esm/utils/bigint.js.map +1 -0
  47. package/_esm/utils/hash.js +3 -0
  48. package/_esm/utils/hash.js.map +1 -0
  49. package/_esm/utils/sortKeys.js +22 -0
  50. package/_esm/utils/sortKeys.js.map +1 -0
  51. package/_esm/version.js +1 -1
  52. package/_types/accounts/evm/resolveViemClients.d.ts +47 -0
  53. package/_types/accounts/evm/resolveViemClients.d.ts.map +1 -0
  54. package/_types/accounts/evm/toNetworkScopedEvmServerAccount.d.ts +1 -1
  55. package/_types/accounts/evm/toNetworkScopedEvmServerAccount.d.ts.map +1 -1
  56. package/_types/accounts/evm/types.d.ts +11 -4
  57. package/_types/accounts/evm/types.d.ts.map +1 -1
  58. package/_types/auth/hooks/axios/withAuth.d.ts.map +1 -1
  59. package/_types/auth/utils/jwt.d.ts.map +1 -1
  60. package/_types/index.d.ts +1 -0
  61. package/_types/index.d.ts.map +1 -1
  62. package/_types/openapi-client/cdpApiClient.d.ts +4 -0
  63. package/_types/openapi-client/cdpApiClient.d.ts.map +1 -1
  64. package/_types/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.d.ts +2 -0
  65. package/_types/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.d.ts.map +1 -1
  66. package/_types/openapi-client/generated/index.msw.d.ts +4 -4
  67. package/_types/openapi-client/generated/index.msw.d.ts.map +1 -1
  68. package/_types/policies/schema.d.ts +96 -96
  69. package/_types/utils/bigint.d.ts +8 -0
  70. package/_types/utils/bigint.d.ts.map +1 -0
  71. package/_types/utils/hash.d.ts +2 -0
  72. package/_types/utils/hash.d.ts.map +1 -0
  73. package/_types/utils/sortKeys.d.ts +8 -0
  74. package/_types/utils/sortKeys.d.ts.map +1 -0
  75. package/_types/version.d.ts +1 -1
  76. package/accounts/evm/resolveViemClients.ts +259 -0
  77. package/accounts/evm/toEvmServerAccount.ts +1 -1
  78. package/accounts/evm/toNetworkScopedEvmServerAccount.ts +51 -3
  79. package/accounts/evm/types.ts +24 -6
  80. package/auth/hooks/axios/withAuth.ts +6 -0
  81. package/auth/utils/jwt.ts +4 -1
  82. package/index.ts +2 -0
  83. package/openapi-client/cdpApiClient.ts +13 -1
  84. package/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.ts +2 -0
  85. package/openapi-client/generated/index.msw.ts +4 -4
  86. package/package.json +1 -1
  87. package/utils/bigint.ts +19 -0
  88. package/utils/hash.ts +3 -0
  89. package/utils/sortKeys.ts +26 -0
  90. package/version.ts +1 -1
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Converts bigint values in an object to strings for safe serialization
3
+ *
4
+ * @param obj - The object to convert
5
+ * @returns A new object with bigint values converted to strings
6
+ */
7
+ export declare const convertBigIntsToStrings: (obj: any) => any;
8
+ //# sourceMappingURL=bigint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bigint.d.ts","sourceRoot":"","sources":["../../utils/bigint.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,KAAK,GAAG,KAAG,GAWlD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const hash: (data: Buffer) => string;
2
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../utils/hash.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,WAAoD,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Recursively sorts object keys to ensure consistent JSON stringification
3
+ *
4
+ * @param obj - The object to sort
5
+ * @returns A new object with sorted keys
6
+ */
7
+ export declare const sortKeys: (obj: any) => any;
8
+ //# sourceMappingURL=sortKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sortKeys.d.ts","sourceRoot":"","sources":["../../utils/sortKeys.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,GAAG,KAAG,GAkBnC,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const version = "1.17.0";
1
+ export declare const version = "1.19.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1,259 @@
1
+ import {
2
+ Account,
3
+ createPublicClient,
4
+ createWalletClient,
5
+ http,
6
+ Transport,
7
+ type Chain,
8
+ type PublicClient,
9
+ type WalletClient,
10
+ } from "viem";
11
+ import { toAccount } from "viem/accounts";
12
+ import * as chains from "viem/chains";
13
+
14
+ import { generateJwt } from "../../auth/utils/jwt.js";
15
+ import { config } from "../../openapi-client/cdpApiClient.js";
16
+
17
+ import type { EvmAccount } from "./types.js";
18
+
19
+ /**
20
+ * Network identifier to viem chain mapping
21
+ */
22
+ const NETWORK_TO_CHAIN_MAP: Record<string, Chain> = {
23
+ base: chains.base,
24
+ "base-sepolia": chains.baseSepolia,
25
+ ethereum: chains.mainnet,
26
+ "ethereum-sepolia": chains.sepolia,
27
+ polygon: chains.polygon,
28
+ "polygon-mumbai": chains.polygonMumbai,
29
+ arbitrum: chains.arbitrum,
30
+ "arbitrum-sepolia": chains.arbitrumSepolia,
31
+ optimism: chains.optimism,
32
+ "optimism-sepolia": chains.optimismSepolia,
33
+ };
34
+
35
+ /**
36
+ * Get a chain from the viem chains object
37
+ *
38
+ * @param id - The chain ID
39
+ * @returns The chain
40
+ */
41
+ function getChain(id: number): Chain {
42
+ const chainList = Object.values(chains) as Chain[];
43
+ const found = chainList.find(chain => chain.id === id);
44
+ if (!found) throw new Error(`Unsupported chain ID: ${id}`);
45
+ return found;
46
+ }
47
+
48
+ /**
49
+ * Determines if the input string is a network identifier or a Node URL
50
+ *
51
+ * @param input - The string to check
52
+ * @returns True if the input is a network identifier, false otherwise
53
+ */
54
+ function isNetworkIdentifier(input: string): boolean {
55
+ const normalizedInput = input.toLowerCase();
56
+ return NETWORK_TO_CHAIN_MAP[normalizedInput] !== undefined;
57
+ }
58
+
59
+ /**
60
+ * Resolves a network identifier to a viem chain
61
+ *
62
+ * @param network - The network identifier to resolve
63
+ * @returns The resolved viem chain
64
+ */
65
+ function resolveNetworkToChain(network: string): Chain {
66
+ const chain = NETWORK_TO_CHAIN_MAP[network.toLowerCase()];
67
+ if (!chain) {
68
+ throw new Error(`Unsupported network identifier: ${network}`);
69
+ }
70
+ return chain;
71
+ }
72
+
73
+ /**
74
+ * Resolves a Node URL to a viem chain by making a getChainId call
75
+ *
76
+ * @param nodeUrl - The Node URL to resolve
77
+ * @returns Promise resolving to the viem chain
78
+ */
79
+ async function resolveNodeUrlToChain(nodeUrl: string): Promise<Chain> {
80
+ // First validate that it's a proper URL
81
+ if (!isValidUrl(nodeUrl)) {
82
+ throw new Error(`Invalid URL format: ${nodeUrl}`);
83
+ }
84
+
85
+ // Create a temporary public client to get the chain ID
86
+ const tempPublicClient = createPublicClient({
87
+ transport: http(nodeUrl),
88
+ });
89
+
90
+ try {
91
+ const chainId = await tempPublicClient.getChainId();
92
+ const chain = getChain(Number(chainId));
93
+ return chain;
94
+ } catch (error) {
95
+ throw new Error(
96
+ `Failed to resolve chain ID from Node URL: ${error instanceof Error ? error.message : "Unknown error"}`,
97
+ );
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Determines if the input string is a valid URL
103
+ *
104
+ * @param input - The string to validate as a URL
105
+ * @returns True if the input is a valid URL, false otherwise
106
+ */
107
+ function isValidUrl(input: string): boolean {
108
+ try {
109
+ new URL(input);
110
+ return true;
111
+ } catch {
112
+ return false;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Options for resolving viem clients
118
+ */
119
+ export type ResolveViemClientsOptions = {
120
+ /** The network identifier (e.g., "base", "base-sepolia") or Node URL */
121
+ networkOrNodeUrl: string;
122
+ /** Optional account to use for the wallet client */
123
+ account: EvmAccount;
124
+ };
125
+
126
+ /**
127
+ * Result of resolving viem clients
128
+ */
129
+ export type ResolvedViemClients = {
130
+ /** The resolved viem chain */
131
+ chain: Chain;
132
+ /** The public client for reading blockchain data */
133
+ publicClient: PublicClient<Transport, Chain>;
134
+ /** The wallet client for sending transactions */
135
+ walletClient: WalletClient<Transport, Chain, Account>;
136
+ };
137
+
138
+ /**
139
+ * Get the base node RPC URL for a given network
140
+ *
141
+ * @param network - The network identifier
142
+ * @returns The base node RPC URL or undefined if the network is not supported
143
+ */
144
+ async function getBaseNodeRpcUrl(network: "base" | "base-sepolia"): Promise<string | undefined> {
145
+ if (!config) {
146
+ return;
147
+ }
148
+
149
+ try {
150
+ const basePath = config.basePath?.replace("/platform", "");
151
+
152
+ const jwt = await generateJwt({
153
+ apiKeyId: config.apiKeyId,
154
+ apiKeySecret: config.apiKeySecret,
155
+ requestMethod: "GET",
156
+ requestHost: basePath.replace("https://", ""),
157
+ requestPath: "/apikeys/v1/tokens/active",
158
+ });
159
+
160
+ const response = await fetch(`${basePath}/apikeys/v1/tokens/active`, {
161
+ headers: {
162
+ Authorization: `Bearer ${jwt}`,
163
+ "Content-Type": "application/json",
164
+ },
165
+ });
166
+
167
+ const json = await response.json();
168
+ return `${basePath}/rpc/v1/${network}/${json.id}`;
169
+ } catch {
170
+ return;
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Resolves viem clients based on a network identifier or Node URL.
176
+ *
177
+ * @param options - Configuration options
178
+ * @param options.networkOrNodeUrl - Either a network identifier (e.g., "base", "base-sepolia") or a full Node URL
179
+ * @param options.account - Optional account to use for the wallet client
180
+ * @returns Promise resolving to an object containing the chain, publicClient, and walletClient
181
+ *
182
+ * @example
183
+ * ```typescript
184
+ * // Using network identifier
185
+ * const clients = await resolveViemClients({
186
+ * networkOrNodeUrl: "base",
187
+ * account: myAccount
188
+ * });
189
+ *
190
+ * // Using Node URL
191
+ * const clients = await resolveViemClients({
192
+ * networkOrNodeUrl: "https://mainnet.base.org",
193
+ * account: myAccount
194
+ * });
195
+ * ```
196
+ */
197
+ export async function resolveViemClients(
198
+ options: ResolveViemClientsOptions,
199
+ ): Promise<ResolvedViemClients> {
200
+ const { networkOrNodeUrl } = options;
201
+
202
+ let chain: Chain;
203
+
204
+ // If it's a valid network identifier, use the mapping
205
+ if (isNetworkIdentifier(networkOrNodeUrl)) {
206
+ const rpcUrl =
207
+ networkOrNodeUrl === "base" || networkOrNodeUrl === "base-sepolia"
208
+ ? await getBaseNodeRpcUrl(networkOrNodeUrl)
209
+ : undefined;
210
+
211
+ chain = resolveNetworkToChain(networkOrNodeUrl);
212
+ const publicClient = createPublicClient({
213
+ chain,
214
+ transport: http(rpcUrl),
215
+ });
216
+ const walletClient = createWalletClient({
217
+ account: toAccount(options.account),
218
+ chain,
219
+ transport: http(rpcUrl),
220
+ });
221
+ return {
222
+ chain,
223
+ publicClient,
224
+ walletClient,
225
+ };
226
+ }
227
+
228
+ // If it's not a valid network identifier, try to treat it as a Node URL
229
+ try {
230
+ chain = await resolveNodeUrlToChain(networkOrNodeUrl);
231
+ const publicClient = createPublicClient({
232
+ chain,
233
+ transport: http(networkOrNodeUrl),
234
+ });
235
+ const walletClient = createWalletClient({
236
+ account: toAccount(options.account),
237
+ chain,
238
+ transport: http(networkOrNodeUrl),
239
+ });
240
+ return {
241
+ chain,
242
+ publicClient,
243
+ walletClient,
244
+ };
245
+ } catch (error) {
246
+ // If the error is from resolveNodeUrlToChain, re-throw it as-is
247
+ if (
248
+ error instanceof Error &&
249
+ (error.message.includes("Invalid URL format") ||
250
+ error.message.includes("Unsupported chain ID") ||
251
+ error.message.includes("Failed to resolve chain ID"))
252
+ ) {
253
+ throw error;
254
+ }
255
+
256
+ // Otherwise, throw a generic error about unsupported input
257
+ throw new Error(`Unsupported network identifier or invalid Node URL: ${networkOrNodeUrl}`);
258
+ }
259
+ }
@@ -169,7 +169,7 @@ export function toEvmServerAccount(
169
169
  name: options.account.name,
170
170
  type: "evm-server",
171
171
  policies: options.account.policies,
172
- __experimental_useNetwork: async (networkOrRpcUrl: string) => {
172
+ useNetwork: async (networkOrRpcUrl: string) => {
173
173
  return toNetworkScopedEvmServerAccount(apiClient, {
174
174
  account,
175
175
  network: networkOrRpcUrl,
@@ -1,6 +1,13 @@
1
+ import { WaitForTransactionReceiptParameters } from "viem";
2
+ import { base, baseSepolia, sepolia } from "viem/chains";
3
+
4
+ import { resolveViemClients } from "./resolveViemClients.js";
5
+
1
6
  import type { EvmServerAccount, NetworkScopedEvmServerAccount } from "./types.js";
7
+ import type { RequestFaucetOptions } from "../../actions/evm/requestFaucet.js";
8
+ import type { TransactionResult } from "../../actions/evm/sendTransaction.js";
2
9
  import type { CdpOpenApiClientType } from "../../openapi-client/index.js";
3
- import type { Address } from "../../types/misc.js";
10
+ import type { Address, TransactionRequestEIP1559 } from "../../types/misc.js";
4
11
 
5
12
  /**
6
13
  * Options for converting a pre-existing EvmAccount to a NetworkScopedEvmServerAccount.
@@ -22,10 +29,17 @@ export type ToNetworkScopedEvmServerAccountOptions = {
22
29
  * @param {string} options.network - The network to scope the account to.
23
30
  * @returns {NetworkScopedEvmServerAccount} A configured NetworkScopedEvmServerAccount instance ready for signing.
24
31
  */
25
- export function toNetworkScopedEvmServerAccount(
32
+ export async function toNetworkScopedEvmServerAccount(
26
33
  apiClient: CdpOpenApiClientType,
27
34
  options: ToNetworkScopedEvmServerAccountOptions,
28
- ): NetworkScopedEvmServerAccount {
35
+ ): Promise<NetworkScopedEvmServerAccount> {
36
+ const { publicClient, walletClient, chain } = await resolveViemClients({
37
+ networkOrNodeUrl: options.network,
38
+ account: options.account,
39
+ });
40
+
41
+ const shouldUseApi = chain.id === base.id || chain.id === baseSepolia.id;
42
+
29
43
  const account: NetworkScopedEvmServerAccount = {
30
44
  address: options.account.address as Address,
31
45
  network: options.network,
@@ -36,6 +50,40 @@ export function toNetworkScopedEvmServerAccount(
36
50
  name: options.account.name,
37
51
  type: "evm-server",
38
52
  policies: options.account.policies,
53
+ requestFaucet: async (faucetOptions: Omit<RequestFaucetOptions, "address" | "network">) => {
54
+ if (chain.id !== baseSepolia.id && chain.id !== sepolia.id) {
55
+ throw new Error(
56
+ "Requesting a faucet is supported only on base-sepolia or ethereum-sepolia",
57
+ );
58
+ }
59
+ return options.account.requestFaucet({
60
+ ...faucetOptions,
61
+ network: chain.id === baseSepolia.id ? "base-sepolia" : "ethereum-sepolia",
62
+ });
63
+ },
64
+ sendTransaction: async txOpts => {
65
+ if (shouldUseApi) {
66
+ return options.account.sendTransaction({
67
+ ...txOpts,
68
+ network: chain.id === base.id ? "base" : "base-sepolia",
69
+ });
70
+ } else {
71
+ const hash = await walletClient.sendTransaction(
72
+ txOpts.transaction as TransactionRequestEIP1559,
73
+ );
74
+ return { transactionHash: hash };
75
+ }
76
+ },
77
+ waitForTransactionReceipt: async (
78
+ options: WaitForTransactionReceiptParameters | TransactionResult,
79
+ ) => {
80
+ if ("transactionHash" in options) {
81
+ return publicClient.waitForTransactionReceipt({
82
+ hash: options.transactionHash,
83
+ });
84
+ }
85
+ return publicClient.waitForTransactionReceipt(options);
86
+ },
39
87
  };
40
88
 
41
89
  return account;
@@ -1,11 +1,16 @@
1
+ import { RequestFaucetOptions, RequestFaucetResult } from "../../actions/evm/requestFaucet.js";
2
+ import { TransactionResult, SendTransactionOptions } from "../../actions/evm/sendTransaction.js";
3
+
1
4
  import type { AccountActions, SmartAccountActions } from "../../actions/evm/types.js";
2
5
  import type { Address, Hash, Hex } from "../../types/misc.js";
3
6
  import type { Prettify } from "../../types/utils.js";
4
7
  import type {
5
8
  SignableMessage,
9
+ TransactionReceipt,
6
10
  TransactionSerializable,
7
11
  TypedData,
8
12
  TypedDataDefinition,
13
+ WaitForTransactionReceiptParameters,
9
14
  } from "viem";
10
15
 
11
16
  /**
@@ -42,8 +47,8 @@ export type EvmServerAccount = Prettify<
42
47
  name?: string;
43
48
  /** Indicates this is a server-managed account. */
44
49
  type: "evm-server";
45
- /** Subject to breaking changes. A function that returns a network-scoped server-managed account. */
46
- __experimental_useNetwork: (network: string) => Promise<NetworkScopedEvmServerAccount>;
50
+ /** A function that returns a network-scoped server-managed account. */
51
+ useNetwork: (network: string) => Promise<NetworkScopedEvmServerAccount>;
47
52
  }
48
53
  >;
49
54
 
@@ -72,12 +77,25 @@ export type NetworkScopedEvmSmartAccount = Prettify<
72
77
  }
73
78
  >;
74
79
 
80
+ type NetworkScopedAccountActions = Prettify<{
81
+ requestFaucet: (
82
+ options: Omit<RequestFaucetOptions, "address" | "network">,
83
+ ) => Promise<RequestFaucetResult>;
84
+ sendTransaction: (
85
+ options: Omit<SendTransactionOptions, "address" | "network">,
86
+ ) => Promise<TransactionResult>;
87
+ waitForTransactionReceipt: (
88
+ options: WaitForTransactionReceiptParameters | TransactionResult,
89
+ ) => Promise<TransactionReceipt>;
90
+ }>;
91
+
75
92
  /**
76
93
  * A network-scoped server-managed ethereum account
77
94
  */
78
95
  export type NetworkScopedEvmServerAccount = Prettify<
79
- Omit<EvmServerAccount, keyof AccountActions | "__experimental_useNetwork"> & {
80
- /** The network this account is scoped to */
81
- network: string;
82
- }
96
+ Omit<EvmServerAccount, keyof AccountActions | "useNetwork"> &
97
+ NetworkScopedAccountActions & {
98
+ /** The network this account is scoped to */
99
+ network: string;
100
+ }
83
101
  >;
@@ -1,5 +1,6 @@
1
1
  import { AxiosInstance, AxiosHeaders } from "axios";
2
2
 
3
+ import { convertBigIntsToStrings } from "../../../utils/bigint.js";
3
4
  import { getAuthHeaders } from "../../utils/http.js";
4
5
 
5
6
  export interface AuthInterceptorOptions {
@@ -57,6 +58,11 @@ export function withAuth(axiosClient: AxiosInstance, options: AuthInterceptorOpt
57
58
  // Parse URL to get host and path
58
59
  const url = new URL(fullyQualifiedURL);
59
60
 
61
+ // Convert bigints in request body to strings for safe serialization
62
+ if (axiosConfig.data) {
63
+ axiosConfig.data = convertBigIntsToStrings(axiosConfig.data);
64
+ }
65
+
60
66
  // Get authentication headers
61
67
  const headers = await getAuthHeaders({
62
68
  apiKeyId: options.apiKeyId,
package/auth/utils/jwt.ts CHANGED
@@ -3,6 +3,8 @@ import { createPrivateKey } from "crypto";
3
3
 
4
4
  import { SignJWT, importPKCS8, importJWK, JWTPayload } from "jose";
5
5
 
6
+ import { hash } from "../../utils/hash.js";
7
+ import { sortKeys } from "../../utils/sortKeys.js";
6
8
  import { InvalidWalletSecretFormatError, UndefinedWalletSecretError } from "../errors.js";
7
9
 
8
10
  /**
@@ -190,7 +192,8 @@ export async function generateWalletJwt(options: WalletJwtOptions): Promise<stri
190
192
  };
191
193
 
192
194
  if (Object.keys(options.requestData).length > 0) {
193
- claims.req = options.requestData;
195
+ const sortedData = sortKeys(options.requestData);
196
+ claims.reqHash = hash(Buffer.from(JSON.stringify(sortedData)));
194
197
  }
195
198
 
196
199
  try {
package/index.ts CHANGED
@@ -7,3 +7,5 @@ export {
7
7
  type CreatePolicyBody,
8
8
  type UpdatePolicyBody,
9
9
  } from "./policies/schema.js";
10
+
11
+ export { parseEther } from "viem";
@@ -11,6 +11,8 @@ import {
11
11
  UnknownError,
12
12
  } from "./errors.js";
13
13
 
14
+ import type { Prettify } from "../types/utils.js";
15
+
14
16
  /**
15
17
  * The options for the CDP API.
16
18
  */
@@ -54,14 +56,24 @@ export type CdpOptions = {
54
56
 
55
57
  let axiosInstance: AxiosInstance;
56
58
 
59
+ export let config: Prettify<Omit<CdpOptions, "basePath"> & { basePath: string }> | undefined =
60
+ undefined;
61
+
57
62
  /**
58
63
  * Configures the CDP client with the given options.
59
64
  *
60
65
  * @param {CdpOptions} options - The CDP options.
61
66
  */
62
67
  export const configure = (options: CdpOptions) => {
68
+ const baseURL = options.basePath || "https://api.cdp.coinbase.com/platform";
69
+
70
+ config = {
71
+ ...options,
72
+ basePath: baseURL,
73
+ };
74
+
63
75
  axiosInstance = Axios.create({
64
- baseURL: options.basePath || "https://api.cdp.coinbase.com/platform",
76
+ baseURL,
65
77
  });
66
78
 
67
79
  axiosInstance = withAuth(axiosInstance, {
@@ -56,6 +56,7 @@ export const ErrorType = {
56
56
  unauthorized: "unauthorized",
57
57
  policy_violation: "policy_violation",
58
58
  policy_in_use: "policy_in_use",
59
+ account_limit_exceeded: "account_limit_exceeded",
59
60
  } as const;
60
61
 
61
62
  /**
@@ -487,6 +488,7 @@ export type ListEvmTokenBalancesNetwork =
487
488
  export const ListEvmTokenBalancesNetwork = {
488
489
  base: "base",
489
490
  "base-sepolia": "base-sepolia",
491
+ ethereum: "ethereum",
490
492
  } as const;
491
493
 
492
494
  /**
@@ -1,8 +1,8 @@
1
+ export * from "./evm-swaps/evm-swaps.msw.js";
1
2
  export * from "./evm-token-balances/evm-token-balances.msw.js";
2
3
  export * from "./evm-accounts/evm-accounts.msw.js";
3
- export * from "./evm-smart-accounts/evm-smart-accounts.msw.js";
4
- export * from "./faucets/faucets.msw.js";
5
- export * from "./evm-swaps/evm-swaps.msw.js";
6
- export * from "./payments-alpha/payments-alpha.msw.js";
7
4
  export * from "./policy-engine/policy-engine.msw.js";
5
+ export * from "./faucets/faucets.msw.js";
6
+ export * from "./evm-smart-accounts/evm-smart-accounts.msw.js";
8
7
  export * from "./solana-accounts/solana-accounts.msw.js";
8
+ export * from "./payments-alpha/payments-alpha.msw.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coinbase/cdp-sdk",
3
- "version": "1.17.0",
3
+ "version": "1.19.0",
4
4
  "description": "SDK for interacting with the Coinbase Developer Platform Wallet API",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
@@ -0,0 +1,19 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /**
3
+ * Converts bigint values in an object to strings for safe serialization
4
+ *
5
+ * @param obj - The object to convert
6
+ * @returns A new object with bigint values converted to strings
7
+ */
8
+ export const convertBigIntsToStrings = (obj: any): any => {
9
+ if (typeof obj === "bigint") {
10
+ return obj.toString();
11
+ }
12
+ if (Array.isArray(obj)) {
13
+ return obj.map(convertBigIntsToStrings);
14
+ }
15
+ if (obj && typeof obj === "object") {
16
+ return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, convertBigIntsToStrings(v)]));
17
+ }
18
+ return obj;
19
+ };
package/utils/hash.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { createHash } from "crypto";
2
+
3
+ export const hash = (data: Buffer) => createHash("sha256").update(data).digest("hex");
@@ -0,0 +1,26 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /**
3
+ * Recursively sorts object keys to ensure consistent JSON stringification
4
+ *
5
+ * @param obj - The object to sort
6
+ * @returns A new object with sorted keys
7
+ */
8
+ export const sortKeys = (obj: any): any => {
9
+ if (!obj || typeof obj !== "object") {
10
+ return obj;
11
+ }
12
+
13
+ if (Array.isArray(obj)) {
14
+ return obj.map(sortKeys);
15
+ }
16
+
17
+ return Object.keys(obj)
18
+ .sort()
19
+ .reduce(
20
+ (acc, key) => {
21
+ acc[key] = sortKeys(obj[key]);
22
+ return acc;
23
+ },
24
+ {} as Record<string, any>,
25
+ );
26
+ };
package/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = "1.17.0";
1
+ export const version = "1.19.0";