@coinbase/cdp-sdk 1.20.0 → 1.21.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 (118) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +8 -0
  3. package/_cjs/accounts/evm/chainToNetworkMapper.js +33 -0
  4. package/_cjs/accounts/evm/chainToNetworkMapper.js.map +1 -0
  5. package/_cjs/accounts/evm/getBaseNodeRpcUrl.js +38 -0
  6. package/_cjs/accounts/evm/getBaseNodeRpcUrl.js.map +1 -0
  7. package/_cjs/accounts/evm/networkCapabilities.js +91 -0
  8. package/_cjs/accounts/evm/networkCapabilities.js.map +1 -0
  9. package/_cjs/accounts/evm/resolveViemClients.js +2 -35
  10. package/_cjs/accounts/evm/resolveViemClients.js.map +1 -1
  11. package/_cjs/accounts/evm/toEvmServerAccount.js +1 -1
  12. package/_cjs/accounts/evm/toEvmServerAccount.js.map +1 -1
  13. package/_cjs/accounts/evm/toEvmSmartAccount.js +2 -2
  14. package/_cjs/accounts/evm/toEvmSmartAccount.js.map +1 -1
  15. package/_cjs/accounts/evm/toNetworkScopedEvmServerAccount.js +86 -32
  16. package/_cjs/accounts/evm/toNetworkScopedEvmServerAccount.js.map +1 -1
  17. package/_cjs/accounts/evm/toNetworkScopedEvmSmartAccount.js +126 -2
  18. package/_cjs/accounts/evm/toNetworkScopedEvmSmartAccount.js.map +1 -1
  19. package/_cjs/actions/evm/sendUserOperation.js +8 -1
  20. package/_cjs/actions/evm/sendUserOperation.js.map +1 -1
  21. package/_cjs/actions/evm/transfer/transferWithViem.js +2 -1
  22. package/_cjs/actions/evm/transfer/transferWithViem.js.map +1 -1
  23. package/_cjs/client/evm/evm.js +2 -2
  24. package/_cjs/client/evm/evm.js.map +1 -1
  25. package/_cjs/client/solana/solana.js +74 -0
  26. package/_cjs/client/solana/solana.js.map +1 -1
  27. package/_cjs/constants.js +18 -1
  28. package/_cjs/constants.js.map +1 -1
  29. package/_cjs/openapi-client/generated/solana-accounts/solana-accounts.js +10 -1
  30. package/_cjs/openapi-client/generated/solana-accounts/solana-accounts.js.map +1 -1
  31. package/_cjs/version.js +1 -1
  32. package/_esm/accounts/evm/chainToNetworkMapper.js +30 -0
  33. package/_esm/accounts/evm/chainToNetworkMapper.js.map +1 -0
  34. package/_esm/accounts/evm/getBaseNodeRpcUrl.js +35 -0
  35. package/_esm/accounts/evm/getBaseNodeRpcUrl.js.map +1 -0
  36. package/_esm/accounts/evm/networkCapabilities.js +86 -0
  37. package/_esm/accounts/evm/networkCapabilities.js.map +1 -0
  38. package/_esm/accounts/evm/resolveViemClients.js +1 -34
  39. package/_esm/accounts/evm/resolveViemClients.js.map +1 -1
  40. package/_esm/accounts/evm/toEvmServerAccount.js +1 -1
  41. package/_esm/accounts/evm/toEvmServerAccount.js.map +1 -1
  42. package/_esm/accounts/evm/toEvmSmartAccount.js +2 -2
  43. package/_esm/accounts/evm/toEvmSmartAccount.js.map +1 -1
  44. package/_esm/accounts/evm/toNetworkScopedEvmServerAccount.js +87 -33
  45. package/_esm/accounts/evm/toNetworkScopedEvmServerAccount.js.map +1 -1
  46. package/_esm/accounts/evm/toNetworkScopedEvmSmartAccount.js +126 -2
  47. package/_esm/accounts/evm/toNetworkScopedEvmSmartAccount.js.map +1 -1
  48. package/_esm/actions/evm/sendUserOperation.js +8 -1
  49. package/_esm/actions/evm/sendUserOperation.js.map +1 -1
  50. package/_esm/actions/evm/transfer/transferWithViem.js +2 -1
  51. package/_esm/actions/evm/transfer/transferWithViem.js.map +1 -1
  52. package/_esm/client/evm/evm.js +2 -2
  53. package/_esm/client/evm/evm.js.map +1 -1
  54. package/_esm/client/solana/solana.js +71 -0
  55. package/_esm/client/solana/solana.js.map +1 -1
  56. package/_esm/constants.js +17 -0
  57. package/_esm/constants.js.map +1 -1
  58. package/_esm/openapi-client/generated/solana-accounts/solana-accounts.js +8 -0
  59. package/_esm/openapi-client/generated/solana-accounts/solana-accounts.js.map +1 -1
  60. package/_esm/version.js +1 -1
  61. package/_types/accounts/evm/chainToNetworkMapper.d.ts +11 -0
  62. package/_types/accounts/evm/chainToNetworkMapper.d.ts.map +1 -0
  63. package/_types/accounts/evm/getBaseNodeRpcUrl.d.ts +8 -0
  64. package/_types/accounts/evm/getBaseNodeRpcUrl.d.ts.map +1 -0
  65. package/_types/accounts/evm/networkCapabilities.d.ts +103 -0
  66. package/_types/accounts/evm/networkCapabilities.d.ts.map +1 -0
  67. package/_types/accounts/evm/resolveViemClients.d.ts.map +1 -1
  68. package/_types/accounts/evm/toEvmServerAccount.d.ts.map +1 -1
  69. package/_types/accounts/evm/toEvmSmartAccount.d.ts.map +1 -1
  70. package/_types/accounts/evm/toNetworkScopedEvmServerAccount.d.ts +3 -3
  71. package/_types/accounts/evm/toNetworkScopedEvmServerAccount.d.ts.map +1 -1
  72. package/_types/accounts/evm/toNetworkScopedEvmSmartAccount.d.ts +9 -6
  73. package/_types/accounts/evm/toNetworkScopedEvmSmartAccount.d.ts.map +1 -1
  74. package/_types/accounts/evm/types.d.ts +109 -14
  75. package/_types/accounts/evm/types.d.ts.map +1 -1
  76. package/_types/actions/evm/sendUserOperation.d.ts.map +1 -1
  77. package/_types/actions/evm/transfer/transferWithViem.d.ts +1 -1
  78. package/_types/actions/evm/transfer/transferWithViem.d.ts.map +1 -1
  79. package/_types/client/evm/evm.d.ts.map +1 -1
  80. package/_types/client/evm/evm.types.d.ts +1 -1
  81. package/_types/client/evm/evm.types.d.ts.map +1 -1
  82. package/_types/client/solana/solana.d.ts +40 -1
  83. package/_types/client/solana/solana.d.ts.map +1 -1
  84. package/_types/client/solana/solana.types.d.ts +15 -1
  85. package/_types/client/solana/solana.types.d.ts.map +1 -1
  86. package/_types/constants.d.ts +4 -0
  87. package/_types/constants.d.ts.map +1 -1
  88. package/_types/openapi-client/generated/solana-accounts/solana-accounts.d.ts +5 -0
  89. package/_types/openapi-client/generated/solana-accounts/solana-accounts.d.ts.map +1 -1
  90. package/_types/openapi-client/index.d.ts +10 -0
  91. package/_types/openapi-client/index.d.ts.map +1 -1
  92. package/_types/version.d.ts +1 -1
  93. package/accounts/evm/chainToNetworkMapper.ts +37 -0
  94. package/accounts/evm/getBaseNodeRpcUrl.ts +40 -0
  95. package/accounts/evm/networkCapabilities.ts +117 -0
  96. package/accounts/evm/resolveViemClients.ts +1 -38
  97. package/accounts/evm/toEvmServerAccount.ts +3 -3
  98. package/accounts/evm/toEvmSmartAccount.ts +3 -3
  99. package/accounts/evm/toNetworkScopedEvmServerAccount.ts +116 -44
  100. package/accounts/evm/toNetworkScopedEvmSmartAccount.ts +178 -11
  101. package/accounts/evm/types.ts +253 -25
  102. package/actions/evm/sendUserOperation.ts +9 -1
  103. package/actions/evm/transfer/transferWithViem.ts +4 -3
  104. package/client/evm/evm.ts +2 -2
  105. package/client/evm/evm.types.ts +1 -1
  106. package/client/solana/solana.ts +89 -0
  107. package/client/solana/solana.types.ts +16 -0
  108. package/constants.ts +18 -0
  109. package/openapi-client/generated/solana-accounts/solana-accounts.ts +20 -0
  110. package/package.json +1 -1
  111. package/version.ts +1 -1
  112. package/_cjs/client/evm/constants.js +0 -21
  113. package/_cjs/client/evm/constants.js.map +0 -1
  114. package/_esm/client/evm/constants.js +0 -18
  115. package/_esm/client/evm/constants.js.map +0 -1
  116. package/_types/client/evm/constants.d.ts +0 -5
  117. package/_types/client/evm/constants.d.ts.map +0 -1
  118. package/client/evm/constants.ts +0 -17
@@ -1,7 +1,50 @@
1
+ import {
2
+ ListTokenBalancesNetworks,
3
+ RequestFaucetNetworks,
4
+ QuoteFundNetworks,
5
+ FundNetworks,
6
+ TransferNetworks,
7
+ QuoteSwapNetworks,
8
+ SwapNetworks,
9
+ } from "./networkCapabilities.js";
10
+ import { FundOptions } from "../../actions/evm/fund/fund.js";
11
+ import { Quote } from "../../actions/evm/fund/Quote.js";
12
+ import { QuoteFundOptions } from "../../actions/evm/fund/quoteFund.js";
13
+ import { FundOperationResult } from "../../actions/evm/fund/types.js";
14
+ import {
15
+ WaitForFundOperationOptions,
16
+ WaitForFundOperationResult,
17
+ } from "../../actions/evm/fund/waitForFundOperationReceipt.js";
18
+ import {
19
+ ListTokenBalancesOptions,
20
+ ListTokenBalancesResult,
21
+ } from "../../actions/evm/listTokenBalances.js";
1
22
  import { RequestFaucetOptions, RequestFaucetResult } from "../../actions/evm/requestFaucet.js";
2
23
  import { TransactionResult, SendTransactionOptions } from "../../actions/evm/sendTransaction.js";
3
- import { TransferOptions } from "../../actions/evm/transfer/types.js";
24
+ import {
25
+ SendUserOperationOptions,
26
+ SendUserOperationReturnType,
27
+ } from "../../actions/evm/sendUserOperation.js";
28
+ import {
29
+ AccountQuoteSwapOptions,
30
+ AccountQuoteSwapResult,
31
+ AccountSwapOptions,
32
+ AccountSwapResult,
33
+ SmartAccountQuoteSwapOptions,
34
+ SmartAccountQuoteSwapResult,
35
+ SmartAccountSwapOptions,
36
+ SmartAccountSwapResult,
37
+ } from "../../actions/evm/swap/types.js";
38
+ import {
39
+ WaitForUserOperationOptions,
40
+ WaitForUserOperationReturnType,
41
+ } from "../../actions/evm/waitForUserOperation.js";
42
+ import { GetUserOperationOptions, UserOperation } from "../../client/evm/evm.types.js";
4
43
 
44
+ import type {
45
+ SmartAccountTransferOptions,
46
+ TransferOptions,
47
+ } from "../../actions/evm/transfer/types.js";
5
48
  import type { AccountActions, SmartAccountActions } from "../../actions/evm/types.js";
6
49
  import type { Address, Hash, Hex } from "../../types/misc.js";
7
50
  import type { Prettify } from "../../types/utils.js";
@@ -38,6 +81,27 @@ export type EvmAccount = {
38
81
  policies?: string[];
39
82
  };
40
83
 
84
+ /**
85
+ * Known EVM networks supported by the SDK.
86
+ */
87
+ export type KnownEvmNetworks =
88
+ | "base"
89
+ | "base-sepolia"
90
+ | "ethereum"
91
+ | "ethereum-sepolia"
92
+ | "ethereum-hoodi"
93
+ | "polygon"
94
+ | "polygon-mumbai"
95
+ | "arbitrum"
96
+ | "arbitrum-sepolia"
97
+ | "optimism"
98
+ | "optimism-sepolia";
99
+
100
+ /**
101
+ * Network input that accepts known networks or RPC URLs
102
+ */
103
+ export type NetworkOrRpcUrl = KnownEvmNetworks | (string & {});
104
+
41
105
  /**
42
106
  * Server-managed ethereum account
43
107
  */
@@ -48,8 +112,23 @@ export type EvmServerAccount = Prettify<
48
112
  name?: string;
49
113
  /** Indicates this is a server-managed account. */
50
114
  type: "evm-server";
51
- /** A function that returns a network-scoped server-managed account. */
52
- useNetwork: (network: string) => Promise<NetworkScopedEvmServerAccount>;
115
+ /**
116
+ * A function that returns a network-scoped server-managed account.
117
+ *
118
+ * @param network - The network name or RPC URL
119
+ * @example
120
+ * // For known networks, type is inferred automatically:
121
+ * const baseAccount = await account.useNetwork("base");
122
+ *
123
+ * // For custom RPC URLs with type hints (requires casting):
124
+ * const typedAccount = await account.useNetwork<"base">("https://mainnet.base.org" as "base");
125
+ *
126
+ * // For custom RPC URLs without type hints (only sendTransaction and waitForTransactionReceipt methods available):
127
+ * const customAccount = await account.useNetwork("https://mainnet.base.org");
128
+ */
129
+ useNetwork: <Network extends NetworkOrRpcUrl>(
130
+ network: Network,
131
+ ) => Promise<NetworkScopedEvmServerAccount<Network>>;
53
132
  }
54
133
  >;
55
134
 
@@ -62,8 +141,23 @@ type EvmSmartAccountProperties = {
62
141
  owners: EvmAccount[];
63
142
  /** Identifier for the smart account type. */
64
143
  type: "evm-smart";
65
- /** Subject to breaking changes. A function that returns a network-scoped smart account. */
66
- __experimental_useNetwork: (network: string) => Promise<NetworkScopedEvmSmartAccount>;
144
+ /**
145
+ * A function that returns a network-scoped smart account.
146
+ *
147
+ * @param network - The network name or RPC URL
148
+ * @example
149
+ * // For known networks, type is inferred automatically:
150
+ * const baseAccount = await smartAccount.useNetwork("base");
151
+ *
152
+ * // For custom RPC URLs with type hints (requires casting):
153
+ * const typedAccount = await smartAccount.useNetwork<"base">("https://mainnet.base.org" as "base");
154
+ *
155
+ * // For custom RPC URLs without type hints (only sendTransaction, transfer and waitForTransactionReceipt methods available):
156
+ * const customAccount = await smartAccount.useNetwork("https://mainnet.base.org");
157
+ */
158
+ useNetwork: <Network extends KnownEvmNetworks>(
159
+ network: Network,
160
+ ) => Promise<NetworkScopedEvmSmartAccount<Network>>;
67
161
  };
68
162
 
69
163
  /**
@@ -71,33 +165,167 @@ type EvmSmartAccountProperties = {
71
165
  */
72
166
  export type EvmSmartAccount = Prettify<EvmSmartAccountProperties & SmartAccountActions>;
73
167
 
74
- export type NetworkScopedEvmSmartAccount = Prettify<
75
- Omit<EvmSmartAccountProperties, "__experimental_useNetwork"> & {
76
- /** The network to scope the smart account object to. */
77
- network: string;
78
- }
168
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
169
+ type DistributedOmit<T, K extends PropertyKey> = T extends any ? Omit<T, K> : never;
170
+
171
+ /**
172
+ * Helper type for network-specific smart account actions
173
+ */
174
+ type NetworkSpecificSmartAccountActions<Network extends string> = Prettify<
175
+ // Always include sendUserOperation, waitForUserOperation and getUserOperation
176
+ {
177
+ sendUserOperation: <const callData extends unknown[]>(
178
+ options: Omit<SendUserOperationOptions<callData>, "smartAccount" | "network">,
179
+ ) => Promise<SendUserOperationReturnType>;
180
+ waitForUserOperation: (
181
+ options: Omit<WaitForUserOperationOptions, "smartAccountAddress" | "network">,
182
+ ) => Promise<WaitForUserOperationReturnType>;
183
+ getUserOperation: (
184
+ options: Omit<GetUserOperationOptions, "smartAccount" | "network">,
185
+ ) => Promise<UserOperation>;
186
+ } & (Network extends TransferNetworks
187
+ ? {
188
+ transfer: (
189
+ options: Omit<SmartAccountTransferOptions, "network">,
190
+ ) => Promise<SendUserOperationReturnType>;
191
+ }
192
+ : EmptyObject) &
193
+ // Conditionally include listTokenBalances
194
+ (Network extends ListTokenBalancesNetworks
195
+ ? {
196
+ listTokenBalances: (
197
+ options: Omit<ListTokenBalancesOptions, "address" | "network">,
198
+ ) => Promise<ListTokenBalancesResult>;
199
+ }
200
+ : EmptyObject) &
201
+ // Conditionally include requestFaucet
202
+ (Network extends RequestFaucetNetworks
203
+ ? {
204
+ requestFaucet: (
205
+ options: Omit<RequestFaucetOptions, "address" | "network">,
206
+ ) => Promise<RequestFaucetResult>;
207
+ }
208
+ : EmptyObject) &
209
+ // Conditionally include quoteFund
210
+ (Network extends QuoteFundNetworks
211
+ ? {
212
+ quoteFund: (options: Omit<QuoteFundOptions, "address" | "network">) => Promise<Quote>;
213
+ }
214
+ : EmptyObject) &
215
+ // Conditionally include fund
216
+ (Network extends FundNetworks
217
+ ? {
218
+ fund: (options: Omit<FundOptions, "address" | "network">) => Promise<FundOperationResult>;
219
+ waitForFundOperationReceipt: (
220
+ options: Omit<WaitForFundOperationOptions, "network">,
221
+ ) => Promise<WaitForFundOperationResult>;
222
+ }
223
+ : EmptyObject) &
224
+ // Conditionally include quoteSwap
225
+ (Network extends QuoteSwapNetworks
226
+ ? {
227
+ quoteSwap: (
228
+ options: Omit<SmartAccountQuoteSwapOptions, "network">,
229
+ ) => Promise<SmartAccountQuoteSwapResult>;
230
+ }
231
+ : EmptyObject) &
232
+ // Conditionally include swap
233
+ (Network extends SwapNetworks
234
+ ? {
235
+ swap: (
236
+ options: DistributedOmit<SmartAccountSwapOptions, "network">,
237
+ ) => Promise<SmartAccountSwapResult>;
238
+ }
239
+ : EmptyObject)
240
+ >;
241
+
242
+ /**
243
+ * A network-scoped smart account
244
+ */
245
+ export type NetworkScopedEvmSmartAccount<Network extends string = string> = Prettify<
246
+ Omit<EvmSmartAccountProperties, "useNetwork"> &
247
+ NetworkSpecificSmartAccountActions<Network> & {
248
+ /** The network this account is scoped to */
249
+ network: Network;
250
+ }
79
251
  >;
80
252
 
81
- type NetworkScopedAccountActions = Prettify<{
82
- requestFaucet: (
83
- options: Omit<RequestFaucetOptions, "address" | "network">,
84
- ) => Promise<RequestFaucetResult>;
85
- sendTransaction: (
86
- options: Omit<SendTransactionOptions, "address" | "network">,
87
- ) => Promise<TransactionResult>;
88
- waitForTransactionReceipt: (
89
- options: WaitForTransactionReceiptParameters | TransactionResult,
90
- ) => Promise<TransactionReceipt>;
91
- transfer: (options: Omit<TransferOptions, "address" | "network">) => Promise<TransactionResult>;
92
- }>;
253
+ /**
254
+ * Helper type to surface a TypeError when calling a method that doesn't exist based on the network
255
+ */
256
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
257
+ type EmptyObject = {};
258
+
259
+ /**
260
+ * Conditional account actions based on network
261
+ */
262
+ type NetworkSpecificAccountActions<Network extends string> = Prettify<
263
+ // Always include sendTransaction, transfer and waitForTransactionReceipt
264
+ {
265
+ sendTransaction: (
266
+ options: Omit<SendTransactionOptions, "address" | "network">,
267
+ ) => Promise<TransactionResult>;
268
+ transfer: (options: Omit<TransferOptions, "address" | "network">) => Promise<TransactionResult>;
269
+ waitForTransactionReceipt: (
270
+ options: WaitForTransactionReceiptParameters | TransactionResult,
271
+ ) => Promise<TransactionReceipt>;
272
+ } & (Network extends ListTokenBalancesNetworks // Conditionally include listTokenBalances
273
+ ? {
274
+ listTokenBalances: (
275
+ options: Omit<ListTokenBalancesOptions, "address" | "network">,
276
+ ) => Promise<ListTokenBalancesResult>;
277
+ }
278
+ : EmptyObject) &
279
+ // Conditionally include requestFaucet
280
+ (Network extends RequestFaucetNetworks
281
+ ? {
282
+ requestFaucet: (
283
+ options: Omit<RequestFaucetOptions, "address" | "network">,
284
+ ) => Promise<RequestFaucetResult>;
285
+ }
286
+ : EmptyObject) &
287
+ // Conditionally include quoteFund
288
+ (Network extends QuoteFundNetworks
289
+ ? {
290
+ quoteFund: (options: Omit<QuoteFundOptions, "address">) => Promise<Quote>;
291
+ }
292
+ : EmptyObject) &
293
+ // Conditionally include fund
294
+ (Network extends FundNetworks
295
+ ? {
296
+ fund: (options: Omit<FundOptions, "address">) => Promise<FundOperationResult>;
297
+ waitForFundOperationReceipt: (
298
+ options: WaitForFundOperationOptions,
299
+ ) => Promise<WaitForFundOperationResult>;
300
+ }
301
+ : EmptyObject) &
302
+ // Conditionally include transfer
303
+ (Network extends TransferNetworks
304
+ ? {
305
+ transfer: (options: TransferOptions) => Promise<{ transactionHash: Hex }>;
306
+ }
307
+ : EmptyObject) &
308
+ // Conditionally include quoteSwap
309
+ (Network extends QuoteSwapNetworks
310
+ ? {
311
+ quoteSwap: (options: AccountQuoteSwapOptions) => Promise<AccountQuoteSwapResult>;
312
+ }
313
+ : EmptyObject) &
314
+ // Conditionally include swap
315
+ (Network extends SwapNetworks
316
+ ? {
317
+ swap: (options: AccountSwapOptions) => Promise<AccountSwapResult>;
318
+ }
319
+ : EmptyObject)
320
+ >;
93
321
 
94
322
  /**
95
323
  * A network-scoped server-managed ethereum account
96
324
  */
97
- export type NetworkScopedEvmServerAccount = Prettify<
325
+ export type NetworkScopedEvmServerAccount<Network extends string = string> = Prettify<
98
326
  Omit<EvmServerAccount, keyof AccountActions | "useNetwork"> &
99
- NetworkScopedAccountActions & {
327
+ NetworkSpecificAccountActions<Network> & {
100
328
  /** The network this account is scoped to */
101
- network: string;
329
+ network: Network;
102
330
  }
103
331
  >;
@@ -1,5 +1,6 @@
1
1
  import { encodeFunctionData } from "viem";
2
2
 
3
+ import { getBaseNodeRpcUrl } from "../../accounts/evm/getBaseNodeRpcUrl.js";
3
4
  import {
4
5
  EvmUserOperationNetwork,
5
6
  EvmUserOperationStatus,
@@ -106,7 +107,14 @@ export async function sendUserOperation<T extends readonly unknown[]>(
106
107
  client: CdpOpenApiClientType,
107
108
  options: SendUserOperationOptions<T>,
108
109
  ): Promise<SendUserOperationReturnType> {
109
- const { calls, network, paymasterUrl } = options;
110
+ const { calls, network, paymasterUrl: _paymasterUrl } = options;
111
+
112
+ const paymasterUrl = await (async () => {
113
+ if (!_paymasterUrl && network === "base") {
114
+ return getBaseNodeRpcUrl("base");
115
+ }
116
+ return _paymasterUrl;
117
+ })();
110
118
 
111
119
  if (calls.length === 0) {
112
120
  throw new Error("Calls array is empty");
@@ -1,6 +1,7 @@
1
1
  import { encodeFunctionData, erc20Abi } from "viem";
2
2
 
3
3
  import { getErc20Address } from "./utils.js";
4
+ import { mapChainToNetwork } from "../../../accounts/evm/chainToNetworkMapper.js";
4
5
 
5
6
  import type { Network, TransferOptions } from "./types.js";
6
7
  import type { EvmAccount } from "../../../accounts/evm/types.js";
@@ -21,12 +22,11 @@ import type { Account, Chain, Transport, WalletClient } from "viem";
21
22
  export async function transferWithViem<T extends EvmAccount>(
22
23
  walletClient: WalletClient<Transport, Chain, Account>,
23
24
  from: T,
24
- transferArgs: TransferOptions,
25
+ transferArgs: Omit<TransferOptions, "address" | "network">,
25
26
  ): Promise<TransactionResult> {
26
27
  const token = transferArgs.token;
27
28
  const to = typeof transferArgs.to === "string" ? transferArgs.to : transferArgs.to.address;
28
29
  const value = transferArgs.amount;
29
- const network = transferArgs.network;
30
30
 
31
31
  if (token === "eth") {
32
32
  const hash = await walletClient.sendTransaction({
@@ -37,7 +37,8 @@ export async function transferWithViem<T extends EvmAccount>(
37
37
  return { transactionHash: hash as Hex };
38
38
  }
39
39
 
40
- const erc20Address = getErc20Address(token, network as Network);
40
+ const network = mapChainToNetwork(walletClient.chain) as Network;
41
+ const erc20Address = getErc20Address(token, network);
41
42
 
42
43
  // First approve the transfer
43
44
  await walletClient.sendTransaction({
package/client/evm/evm.ts CHANGED
@@ -2,7 +2,6 @@ import { constants, publicEncrypt } from "crypto";
2
2
 
3
3
  import { type Address, getTypesForEIP712Domain } from "viem";
4
4
 
5
- import { ImportEvmAccountPublicRSAKey } from "./constants.js";
6
5
  import {
7
6
  CreateServerAccountOptions,
8
7
  CreateSmartAccountOptions,
@@ -61,6 +60,7 @@ import {
61
60
  WaitForUserOperationReturnType,
62
61
  } from "../../actions/evm/waitForUserOperation.js";
63
62
  import { Analytics } from "../../analytics.js";
63
+ import { ImportAccountPublicRSAKey } from "../../constants.js";
64
64
  import { APIError } from "../../openapi-client/errors.js";
65
65
  import {
66
66
  CdpOpenApiClient,
@@ -173,7 +173,7 @@ export class EvmClient implements EvmClientInterface {
173
173
  * ```
174
174
  */
175
175
  async importAccount(options: ImportServerAccountOptions): Promise<ServerAccount> {
176
- const encryptionPublicKey = options.encryptionPublicKey || ImportEvmAccountPublicRSAKey;
176
+ const encryptionPublicKey = options.encryptionPublicKey || ImportAccountPublicRSAKey;
177
177
 
178
178
  const privateKeyHex = options.privateKey.startsWith("0x")
179
179
  ? options.privateKey.slice(2)
@@ -405,7 +405,7 @@ export interface ListServerAccountsOptions {
405
405
  * A smart account that only contains the owner address.
406
406
  */
407
407
  export interface ReadonlySmartAccount
408
- extends Omit<SmartAccount, "owners" | keyof SmartAccountActions | "__experimental_useNetwork"> {
408
+ extends Omit<SmartAccount, "owners" | keyof SmartAccountActions | "useNetwork"> {
409
409
  /** The owners of the smart account. */
410
410
  owners: Address[];
411
411
  }
@@ -1,8 +1,13 @@
1
+ import { constants, publicEncrypt } from "crypto";
2
+
3
+ import bs58 from "bs58";
4
+
1
5
  import {
2
6
  CreateAccountOptions,
3
7
  ExportAccountOptions,
4
8
  GetAccountOptions,
5
9
  GetOrCreateAccountOptions,
10
+ ImportAccountOptions,
6
11
  ListAccountsOptions,
7
12
  ListAccountsResult,
8
13
  RequestFaucetOptions,
@@ -18,6 +23,7 @@ import { requestFaucet } from "../../actions/solana/requestFaucet.js";
18
23
  import { signMessage } from "../../actions/solana/signMessage.js";
19
24
  import { signTransaction } from "../../actions/solana/signTransaction.js";
20
25
  import { Analytics } from "../../analytics.js";
26
+ import { ImportAccountPublicRSAKey } from "../../constants.js";
21
27
  import { APIError } from "../../openapi-client/errors.js";
22
28
  import { CdpOpenApiClient } from "../../openapi-client/index.js";
23
29
  import {
@@ -133,6 +139,89 @@ export class SolanaClient implements SolanaClientInterface {
133
139
  return formatSolanaPrivateKey(decryptedPrivateKey);
134
140
  }
135
141
 
142
+ /**
143
+ * Imports a Solana account using a private key.
144
+ * The private key will be encrypted before being stored securely.
145
+ *
146
+ * @param {ImportAccountOptions} options - Parameters for importing the Solana account.
147
+ * @param {string} options.privateKey - The private key to import (32 or 64 bytes). Can be a base58 encoded string or raw bytes.
148
+ * @param {string} [options.name] - The name of the account.
149
+ * @param {string} [options.encryptionPublicKey] - The RSA public key for encrypting the private key.
150
+ * @param {string} [options.idempotencyKey] - An idempotency key.
151
+ *
152
+ * @returns A promise that resolves to the imported account.
153
+ *
154
+ * @example **Import with private key only**
155
+ * ```ts
156
+ * const account = await cdp.solana.importAccount({
157
+ * privateKey: "3Kzjw8qSxx8bQkV7EHrVFWYiPyNLbBVxtVe1Q5h2zKZY8DdcuT2dKxyz9kU5vQrP",
158
+ * });
159
+ * ```
160
+ *
161
+ * @example **Import with name**
162
+ * ```ts
163
+ * const account = await cdp.solana.importAccount({
164
+ * privateKey: "3Kzjw8qSxx8bQkV7EHrVFWYiPyNLbBVxtVe1Q5h2zKZY8DdcuT2dKxyz9kU5vQrP",
165
+ * name: "ImportedAccount",
166
+ * });
167
+ * ```
168
+ *
169
+ * @example **Import with idempotency key**
170
+ * ```ts
171
+ * const idempotencyKey = uuidv4();
172
+ *
173
+ * const account = await cdp.solana.importAccount({
174
+ * privateKey: "3Kzjw8qSxx8bQkV7EHrVFWYiPyNLbBVxtVe1Q5h2zKZY8DdcuT2dKxyz9kU5vQrP",
175
+ * name: "ImportedAccount",
176
+ * idempotencyKey,
177
+ * });
178
+ * ```
179
+ */
180
+ async importAccount(options: ImportAccountOptions): Promise<SolanaAccount> {
181
+ let privateKeyBytes: Uint8Array = new Uint8Array();
182
+
183
+ if (typeof options.privateKey === "string") {
184
+ privateKeyBytes = bs58.decode(options.privateKey);
185
+ } else {
186
+ privateKeyBytes = options.privateKey;
187
+ }
188
+
189
+ if (privateKeyBytes.length !== 32 && privateKeyBytes.length !== 64) {
190
+ throw new Error("Invalid private key length");
191
+ }
192
+
193
+ if (privateKeyBytes.length === 64) {
194
+ privateKeyBytes = privateKeyBytes.subarray(0, 32);
195
+ }
196
+
197
+ const encryptionPublicKey = options.encryptionPublicKey || ImportAccountPublicRSAKey;
198
+
199
+ const encryptedPrivateKey = publicEncrypt(
200
+ {
201
+ key: encryptionPublicKey,
202
+ padding: constants.RSA_PKCS1_OAEP_PADDING,
203
+ oaepHash: "sha256",
204
+ },
205
+ privateKeyBytes,
206
+ );
207
+
208
+ const openApiAccount = await CdpOpenApiClient.importSolanaAccount(
209
+ {
210
+ encryptedPrivateKey: encryptedPrivateKey.toString("base64"),
211
+ name: options.name,
212
+ },
213
+ options.idempotencyKey,
214
+ );
215
+
216
+ const account = toSolanaAccount(CdpOpenApiClient, {
217
+ account: openApiAccount,
218
+ });
219
+
220
+ Analytics.wrapObjectMethodsWithErrorTracking(account);
221
+
222
+ return account;
223
+ }
224
+
136
225
  /**
137
226
  * Gets a Solana account by its address.
138
227
  *
@@ -17,9 +17,11 @@ export type SolanaClientInterface = Omit<
17
17
  | "updateSolanaAccount" // mapped to updateAccount
18
18
  | "exportSolanaAccount" // mapped to exportAccount
19
19
  | "exportSolanaAccountByName" // mapped to exportAccount
20
+ | "importSolanaAccount" // mapped to importAccount
20
21
  > & {
21
22
  createAccount: (options: CreateAccountOptions) => Promise<Account>;
22
23
  exportAccount: (options: ExportAccountOptions) => Promise<string>;
24
+ importAccount: (options: ImportAccountOptions) => Promise<SolanaAccount>;
23
25
  getAccount: (options: GetAccountOptions) => Promise<Account>;
24
26
  getOrCreateAccount: (options: GetOrCreateAccountOptions) => Promise<Account>;
25
27
  updateAccount: (options: UpdateSolanaAccountOptions) => Promise<Account>;
@@ -148,3 +150,17 @@ export interface SignTransactionOptions {
148
150
  /** The idempotency key. */
149
151
  idempotencyKey?: string;
150
152
  }
153
+
154
+ /**
155
+ * Options for importing a Solana account.
156
+ */
157
+ export interface ImportAccountOptions {
158
+ /** The public RSA key used to encrypt the private key when importing a Solana account. */
159
+ encryptionPublicKey?: string;
160
+ /** The name of the account. */
161
+ name?: string;
162
+ /** The idempotency key. */
163
+ idempotencyKey?: string;
164
+ /** The private key of the account - can be a base58 encoded string or raw bytes. */
165
+ privateKey: string | Uint8Array;
166
+ }
package/constants.ts CHANGED
@@ -2,3 +2,21 @@
2
2
  * The URL to the Coinbase CDP API error docs page.
3
3
  */
4
4
  export const ERROR_DOCS_PAGE_URL = "https://docs.cdp.coinbase.com/api-v2/docs/errors";
5
+
6
+ /**
7
+ * The public RSA key used to encrypt the private key when importing an EVM or Solana account.
8
+ */
9
+ export const ImportAccountPublicRSAKey = `-----BEGIN PUBLIC KEY-----
10
+ MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2Fxydgm/ryYk0IexQIuL
11
+ 9DKyiIk2WmS36AZ83a9Z0QX53qdveg08b05g1Qr+o+COoYOT/FDi8anRGAs7rIyS
12
+ uigrjHR6VrmFjnGrrTr3MINwC9cYQFHwET8YVGRq+BB3iFTB1kIb9XJ/vT2sk1xP
13
+ hJ6JihEwSl4DgbeVjqw59wYqrNg355oa8EdFqkmfGU2tpbM56F8iv1F+shwkGo3y
14
+ GhW/UOQ5OLauXvsqo8ranwsK+lqFblLEMlNtn1VSJeO2vMxryeKFrY2ob8VqGchC
15
+ ftPJiLWs2Du6juw4C1rOWwSMlXzZ6cNMHkxdTcEHMr3C2TEHgzjZY41whMwNTB8q
16
+ /pxXnIbH77caaviRs4R/POe8cSsznalXj85LULvFWOIHp0w+jEYSii9Rp9XtHWAH
17
+ nrK/O/SVDtT1ohp2F+Zg1mojTgKfLOyGdOUXTi95naDTuG770rSjHdL80tJBz1Fd
18
+ +1pzGTGXGHLZQLX5YZm5iuy2cebWfF09VjIoCIlDB2++tr4M+O0Z1X1ZE0J5Ackq
19
+ rOluAFalaKynyH3KMyRg+NuLmibu5OmcMjCLK3D4X1YLiN2OK8/bbpEL8JYroDwb
20
+ EXIUW5mGS06YxfSUsxHzL9Tj00+GMm/Gvl0+4/+Vn8IXVHjQOSPNEy3EnqCiH/OW
21
+ 8v0IMC32CeGrX7mGbU+MzlsCAwEAAQ==
22
+ -----END PUBLIC KEY-----`;
@@ -191,6 +191,26 @@ export const signSolanaMessage = (
191
191
  options,
192
192
  );
193
193
  };
194
+
195
+ export const importSolanaAccount = (
196
+ importSolanaAccountBody: {
197
+ name?: string;
198
+ encryptedPrivateKey: string;
199
+ idempotencyKey?: string;
200
+ },
201
+ options?: SecondParameter<typeof cdpApiClient>,
202
+ ) => {
203
+ return cdpApiClient<SolanaAccount>(
204
+ {
205
+ url: `/v2/solana/accounts/import`,
206
+ method: "POST",
207
+ headers: { "Content-Type": "application/json" },
208
+ data: importSolanaAccountBody,
209
+ },
210
+ options,
211
+ );
212
+ };
213
+
194
214
  export type ListSolanaAccountsResult = NonNullable<Awaited<ReturnType<typeof listSolanaAccounts>>>;
195
215
  export type CreateSolanaAccountResult = NonNullable<
196
216
  Awaited<ReturnType<typeof createSolanaAccount>>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coinbase/cdp-sdk",
3
- "version": "1.20.0",
3
+ "version": "1.21.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.20.0";
1
+ export const version = "1.21.0";
@@ -1,21 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ImportEvmAccountPublicRSAKey = void 0;
4
- /**
5
- * The public RSA key used to encrypt the private key when importing an EVM account.
6
- */
7
- exports.ImportEvmAccountPublicRSAKey = `-----BEGIN PUBLIC KEY-----
8
- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2Fxydgm/ryYk0IexQIuL
9
- 9DKyiIk2WmS36AZ83a9Z0QX53qdveg08b05g1Qr+o+COoYOT/FDi8anRGAs7rIyS
10
- uigrjHR6VrmFjnGrrTr3MINwC9cYQFHwET8YVGRq+BB3iFTB1kIb9XJ/vT2sk1xP
11
- hJ6JihEwSl4DgbeVjqw59wYqrNg355oa8EdFqkmfGU2tpbM56F8iv1F+shwkGo3y
12
- GhW/UOQ5OLauXvsqo8ranwsK+lqFblLEMlNtn1VSJeO2vMxryeKFrY2ob8VqGchC
13
- ftPJiLWs2Du6juw4C1rOWwSMlXzZ6cNMHkxdTcEHMr3C2TEHgzjZY41whMwNTB8q
14
- /pxXnIbH77caaviRs4R/POe8cSsznalXj85LULvFWOIHp0w+jEYSii9Rp9XtHWAH
15
- nrK/O/SVDtT1ohp2F+Zg1mojTgKfLOyGdOUXTi95naDTuG770rSjHdL80tJBz1Fd
16
- +1pzGTGXGHLZQLX5YZm5iuy2cebWfF09VjIoCIlDB2++tr4M+O0Z1X1ZE0J5Ackq
17
- rOluAFalaKynyH3KMyRg+NuLmibu5OmcMjCLK3D4X1YLiN2OK8/bbpEL8JYroDwb
18
- EXIUW5mGS06YxfSUsxHzL9Tj00+GMm/Gvl0+4/+Vn8IXVHjQOSPNEy3EnqCiH/OW
19
- 8v0IMC32CeGrX7mGbU+MzlsCAwEAAQ==
20
- -----END PUBLIC KEY-----`;
21
- //# sourceMappingURL=constants.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../client/evm/constants.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACU,QAAA,4BAA4B,GAAG;;;;;;;;;;;;;yBAanB,CAAC"}
@@ -1,18 +0,0 @@
1
- /**
2
- * The public RSA key used to encrypt the private key when importing an EVM account.
3
- */
4
- export const ImportEvmAccountPublicRSAKey = `-----BEGIN PUBLIC KEY-----
5
- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2Fxydgm/ryYk0IexQIuL
6
- 9DKyiIk2WmS36AZ83a9Z0QX53qdveg08b05g1Qr+o+COoYOT/FDi8anRGAs7rIyS
7
- uigrjHR6VrmFjnGrrTr3MINwC9cYQFHwET8YVGRq+BB3iFTB1kIb9XJ/vT2sk1xP
8
- hJ6JihEwSl4DgbeVjqw59wYqrNg355oa8EdFqkmfGU2tpbM56F8iv1F+shwkGo3y
9
- GhW/UOQ5OLauXvsqo8ranwsK+lqFblLEMlNtn1VSJeO2vMxryeKFrY2ob8VqGchC
10
- ftPJiLWs2Du6juw4C1rOWwSMlXzZ6cNMHkxdTcEHMr3C2TEHgzjZY41whMwNTB8q
11
- /pxXnIbH77caaviRs4R/POe8cSsznalXj85LULvFWOIHp0w+jEYSii9Rp9XtHWAH
12
- nrK/O/SVDtT1ohp2F+Zg1mojTgKfLOyGdOUXTi95naDTuG770rSjHdL80tJBz1Fd
13
- +1pzGTGXGHLZQLX5YZm5iuy2cebWfF09VjIoCIlDB2++tr4M+O0Z1X1ZE0J5Ackq
14
- rOluAFalaKynyH3KMyRg+NuLmibu5OmcMjCLK3D4X1YLiN2OK8/bbpEL8JYroDwb
15
- EXIUW5mGS06YxfSUsxHzL9Tj00+GMm/Gvl0+4/+Vn8IXVHjQOSPNEy3EnqCiH/OW
16
- 8v0IMC32CeGrX7mGbU+MzlsCAwEAAQ==
17
- -----END PUBLIC KEY-----`;
18
- //# sourceMappingURL=constants.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../client/evm/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG;;;;;;;;;;;;;yBAanB,CAAC"}
@@ -1,5 +0,0 @@
1
- /**
2
- * The public RSA key used to encrypt the private key when importing an EVM account.
3
- */
4
- export declare const ImportEvmAccountPublicRSAKey = "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2Fxydgm/ryYk0IexQIuL\n9DKyiIk2WmS36AZ83a9Z0QX53qdveg08b05g1Qr+o+COoYOT/FDi8anRGAs7rIyS\nuigrjHR6VrmFjnGrrTr3MINwC9cYQFHwET8YVGRq+BB3iFTB1kIb9XJ/vT2sk1xP\nhJ6JihEwSl4DgbeVjqw59wYqrNg355oa8EdFqkmfGU2tpbM56F8iv1F+shwkGo3y\nGhW/UOQ5OLauXvsqo8ranwsK+lqFblLEMlNtn1VSJeO2vMxryeKFrY2ob8VqGchC\nftPJiLWs2Du6juw4C1rOWwSMlXzZ6cNMHkxdTcEHMr3C2TEHgzjZY41whMwNTB8q\n/pxXnIbH77caaviRs4R/POe8cSsznalXj85LULvFWOIHp0w+jEYSii9Rp9XtHWAH\nnrK/O/SVDtT1ohp2F+Zg1mojTgKfLOyGdOUXTi95naDTuG770rSjHdL80tJBz1Fd\n+1pzGTGXGHLZQLX5YZm5iuy2cebWfF09VjIoCIlDB2++tr4M+O0Z1X1ZE0J5Ackq\nrOluAFalaKynyH3KMyRg+NuLmibu5OmcMjCLK3D4X1YLiN2OK8/bbpEL8JYroDwb\nEXIUW5mGS06YxfSUsxHzL9Tj00+GMm/Gvl0+4/+Vn8IXVHjQOSPNEy3EnqCiH/OW\n8v0IMC32CeGrX7mGbU+MzlsCAwEAAQ==\n-----END PUBLIC KEY-----";
5
- //# sourceMappingURL=constants.d.ts.map