@coinbase/cdp-sdk 1.17.0 → 1.18.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 (29) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/_cjs/accounts/evm/resolveViemClients.js +204 -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 +32 -1
  7. package/_cjs/accounts/evm/toNetworkScopedEvmServerAccount.js.map +1 -1
  8. package/_cjs/version.js +1 -1
  9. package/_esm/accounts/evm/resolveViemClients.js +168 -0
  10. package/_esm/accounts/evm/resolveViemClients.js.map +1 -0
  11. package/_esm/accounts/evm/toEvmServerAccount.js +1 -1
  12. package/_esm/accounts/evm/toEvmServerAccount.js.map +1 -1
  13. package/_esm/accounts/evm/toNetworkScopedEvmServerAccount.js +32 -1
  14. package/_esm/accounts/evm/toNetworkScopedEvmServerAccount.js.map +1 -1
  15. package/_esm/version.js +1 -1
  16. package/_types/accounts/evm/resolveViemClients.d.ts +47 -0
  17. package/_types/accounts/evm/resolveViemClients.d.ts.map +1 -0
  18. package/_types/accounts/evm/toNetworkScopedEvmServerAccount.d.ts +1 -1
  19. package/_types/accounts/evm/toNetworkScopedEvmServerAccount.d.ts.map +1 -1
  20. package/_types/accounts/evm/types.d.ts +11 -4
  21. package/_types/accounts/evm/types.d.ts.map +1 -1
  22. package/_types/policies/schema.d.ts +96 -96
  23. package/_types/version.d.ts +1 -1
  24. package/accounts/evm/resolveViemClients.ts +215 -0
  25. package/accounts/evm/toEvmServerAccount.ts +1 -1
  26. package/accounts/evm/toNetworkScopedEvmServerAccount.ts +43 -3
  27. package/accounts/evm/types.ts +24 -6
  28. package/package.json +1 -1
  29. package/version.ts +1 -1
@@ -1,2 +1,2 @@
1
- export declare const version = "1.17.0";
1
+ export declare const version = "1.18.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1,215 @@
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 type { EvmAccount } from "./types.js";
15
+
16
+ /**
17
+ * Network identifier to viem chain mapping
18
+ */
19
+ const NETWORK_TO_CHAIN_MAP: Record<string, Chain> = {
20
+ base: chains.base,
21
+ "base-sepolia": chains.baseSepolia,
22
+ ethereum: chains.mainnet,
23
+ "ethereum-sepolia": chains.sepolia,
24
+ polygon: chains.polygon,
25
+ "polygon-mumbai": chains.polygonMumbai,
26
+ arbitrum: chains.arbitrum,
27
+ "arbitrum-sepolia": chains.arbitrumSepolia,
28
+ optimism: chains.optimism,
29
+ "optimism-sepolia": chains.optimismSepolia,
30
+ };
31
+
32
+ /**
33
+ * Get a chain from the viem chains object
34
+ *
35
+ * @param id - The chain ID
36
+ * @returns The chain
37
+ */
38
+ function getChain(id: number): Chain {
39
+ const chainList = Object.values(chains) as Chain[];
40
+ const found = chainList.find(chain => chain.id === id);
41
+ if (!found) throw new Error(`Unsupported chain ID: ${id}`);
42
+ return found;
43
+ }
44
+
45
+ /**
46
+ * Determines if the input string is a network identifier or a Node URL
47
+ *
48
+ * @param input - The string to check
49
+ * @returns True if the input is a network identifier, false otherwise
50
+ */
51
+ function isNetworkIdentifier(input: string): boolean {
52
+ const normalizedInput = input.toLowerCase();
53
+ return NETWORK_TO_CHAIN_MAP[normalizedInput] !== undefined;
54
+ }
55
+
56
+ /**
57
+ * Resolves a network identifier to a viem chain
58
+ *
59
+ * @param network - The network identifier to resolve
60
+ * @returns The resolved viem chain
61
+ */
62
+ function resolveNetworkToChain(network: string): Chain {
63
+ const chain = NETWORK_TO_CHAIN_MAP[network.toLowerCase()];
64
+ if (!chain) {
65
+ throw new Error(`Unsupported network identifier: ${network}`);
66
+ }
67
+ return chain;
68
+ }
69
+
70
+ /**
71
+ * Resolves a Node URL to a viem chain by making a getChainId call
72
+ *
73
+ * @param nodeUrl - The Node URL to resolve
74
+ * @returns Promise resolving to the viem chain
75
+ */
76
+ async function resolveNodeUrlToChain(nodeUrl: string): Promise<Chain> {
77
+ // First validate that it's a proper URL
78
+ if (!isValidUrl(nodeUrl)) {
79
+ throw new Error(`Invalid URL format: ${nodeUrl}`);
80
+ }
81
+
82
+ // Create a temporary public client to get the chain ID
83
+ const tempPublicClient = createPublicClient({
84
+ transport: http(nodeUrl),
85
+ });
86
+
87
+ try {
88
+ const chainId = await tempPublicClient.getChainId();
89
+ const chain = getChain(Number(chainId));
90
+ return chain;
91
+ } catch (error) {
92
+ throw new Error(
93
+ `Failed to resolve chain ID from Node URL: ${error instanceof Error ? error.message : "Unknown error"}`,
94
+ );
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Determines if the input string is a valid URL
100
+ *
101
+ * @param input - The string to validate as a URL
102
+ * @returns True if the input is a valid URL, false otherwise
103
+ */
104
+ function isValidUrl(input: string): boolean {
105
+ try {
106
+ new URL(input);
107
+ return true;
108
+ } catch {
109
+ return false;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Options for resolving viem clients
115
+ */
116
+ export type ResolveViemClientsOptions = {
117
+ /** The network identifier (e.g., "base", "base-sepolia") or Node URL */
118
+ networkOrNodeUrl: string;
119
+ /** Optional account to use for the wallet client */
120
+ account: EvmAccount;
121
+ };
122
+
123
+ /**
124
+ * Result of resolving viem clients
125
+ */
126
+ export type ResolvedViemClients = {
127
+ /** The resolved viem chain */
128
+ chain: Chain;
129
+ /** The public client for reading blockchain data */
130
+ publicClient: PublicClient<Transport, Chain>;
131
+ /** The wallet client for sending transactions */
132
+ walletClient: WalletClient<Transport, Chain, Account>;
133
+ };
134
+
135
+ /**
136
+ * Resolves viem clients based on a network identifier or Node URL.
137
+ *
138
+ * @param options - Configuration options
139
+ * @param options.networkOrNodeUrl - Either a network identifier (e.g., "base", "base-sepolia") or a full Node URL
140
+ * @param options.account - Optional account to use for the wallet client
141
+ * @returns Promise resolving to an object containing the chain, publicClient, and walletClient
142
+ *
143
+ * @example
144
+ * ```typescript
145
+ * // Using network identifier
146
+ * const clients = await resolveViemClients({
147
+ * networkOrNodeUrl: "base",
148
+ * account: myAccount
149
+ * });
150
+ *
151
+ * // Using Node URL
152
+ * const clients = await resolveViemClients({
153
+ * networkOrNodeUrl: "https://mainnet.base.org",
154
+ * account: myAccount
155
+ * });
156
+ * ```
157
+ */
158
+ export async function resolveViemClients(
159
+ options: ResolveViemClientsOptions,
160
+ ): Promise<ResolvedViemClients> {
161
+ const { networkOrNodeUrl } = options;
162
+
163
+ let chain: Chain;
164
+
165
+ // If it's a valid network identifier, use the mapping
166
+ if (isNetworkIdentifier(networkOrNodeUrl)) {
167
+ chain = resolveNetworkToChain(networkOrNodeUrl);
168
+ const publicClient = createPublicClient({
169
+ chain,
170
+ transport: http(),
171
+ });
172
+ const walletClient = createWalletClient({
173
+ account: toAccount(options.account),
174
+ chain,
175
+ transport: http(),
176
+ });
177
+ return {
178
+ chain,
179
+ publicClient,
180
+ walletClient,
181
+ };
182
+ }
183
+
184
+ // If it's not a valid network identifier, try to treat it as a Node URL
185
+ try {
186
+ chain = await resolveNodeUrlToChain(networkOrNodeUrl);
187
+ const publicClient = createPublicClient({
188
+ chain,
189
+ transport: http(networkOrNodeUrl),
190
+ });
191
+ const walletClient = createWalletClient({
192
+ account: toAccount(options.account),
193
+ chain,
194
+ transport: http(networkOrNodeUrl),
195
+ });
196
+ return {
197
+ chain,
198
+ publicClient,
199
+ walletClient,
200
+ };
201
+ } catch (error) {
202
+ // If the error is from resolveNodeUrlToChain, re-throw it as-is
203
+ if (
204
+ error instanceof Error &&
205
+ (error.message.includes("Invalid URL format") ||
206
+ error.message.includes("Unsupported chain ID") ||
207
+ error.message.includes("Failed to resolve chain ID"))
208
+ ) {
209
+ throw error;
210
+ }
211
+
212
+ // Otherwise, throw a generic error about unsupported input
213
+ throw new Error(`Unsupported network identifier or invalid Node URL: ${networkOrNodeUrl}`);
214
+ }
215
+ }
@@ -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,12 @@
1
+ import { WaitForTransactionReceiptParameters } from "viem";
2
+ import { base, baseSepolia, sepolia } from "viem/chains";
3
+
4
+ import { resolveViemClients } from "./resolveViemClients.js";
5
+ import { RequestFaucetOptions } from "../../actions/evm/requestFaucet.js";
6
+
1
7
  import type { EvmServerAccount, NetworkScopedEvmServerAccount } from "./types.js";
2
8
  import type { CdpOpenApiClientType } from "../../openapi-client/index.js";
3
- import type { Address } from "../../types/misc.js";
9
+ import type { Address, TransactionRequestEIP1559 } from "../../types/misc.js";
4
10
 
5
11
  /**
6
12
  * Options for converting a pre-existing EvmAccount to a NetworkScopedEvmServerAccount.
@@ -22,10 +28,17 @@ export type ToNetworkScopedEvmServerAccountOptions = {
22
28
  * @param {string} options.network - The network to scope the account to.
23
29
  * @returns {NetworkScopedEvmServerAccount} A configured NetworkScopedEvmServerAccount instance ready for signing.
24
30
  */
25
- export function toNetworkScopedEvmServerAccount(
31
+ export async function toNetworkScopedEvmServerAccount(
26
32
  apiClient: CdpOpenApiClientType,
27
33
  options: ToNetworkScopedEvmServerAccountOptions,
28
- ): NetworkScopedEvmServerAccount {
34
+ ): Promise<NetworkScopedEvmServerAccount> {
35
+ const { publicClient, walletClient, chain } = await resolveViemClients({
36
+ networkOrNodeUrl: options.network,
37
+ account: options.account,
38
+ });
39
+
40
+ const shouldUseApi = chain.id === base.id || chain.id === baseSepolia.id;
41
+
29
42
  const account: NetworkScopedEvmServerAccount = {
30
43
  address: options.account.address as Address,
31
44
  network: options.network,
@@ -36,6 +49,33 @@ export function toNetworkScopedEvmServerAccount(
36
49
  name: options.account.name,
37
50
  type: "evm-server",
38
51
  policies: options.account.policies,
52
+ requestFaucet: async (faucetOptions: Omit<RequestFaucetOptions, "address" | "network">) => {
53
+ if (chain.id !== baseSepolia.id && chain.id !== sepolia.id) {
54
+ throw new Error(
55
+ "Requesting a faucet is supported only on base-sepolia or ethereum-sepolia",
56
+ );
57
+ }
58
+ return options.account.requestFaucet({
59
+ ...faucetOptions,
60
+ network: chain.id === baseSepolia.id ? "base-sepolia" : "ethereum-sepolia",
61
+ });
62
+ },
63
+ sendTransaction: async txOpts => {
64
+ if (shouldUseApi) {
65
+ return options.account.sendTransaction({
66
+ ...txOpts,
67
+ network: chain.id === base.id ? "base" : "base-sepolia",
68
+ });
69
+ } else {
70
+ const hash = await walletClient.sendTransaction(
71
+ txOpts.transaction as TransactionRequestEIP1559,
72
+ );
73
+ return { transactionHash: hash };
74
+ }
75
+ },
76
+ waitForTransactionReceipt: async (options: WaitForTransactionReceiptParameters) => {
77
+ return publicClient.waitForTransactionReceipt(options);
78
+ },
39
79
  };
40
80
 
41
81
  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,
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
  >;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coinbase/cdp-sdk",
3
- "version": "1.17.0",
3
+ "version": "1.18.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",
package/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = "1.17.0";
1
+ export const version = "1.18.0";