@coinbase/cdp-sdk 1.7.0 → 1.9.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 (226) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +326 -28
  3. package/_cjs/accounts/evm/toEvmServerAccount.js +4 -2
  4. package/_cjs/accounts/evm/toEvmServerAccount.js.map +1 -1
  5. package/_cjs/accounts/evm/toEvmSmartAccount.js.map +1 -1
  6. package/_cjs/accounts/solana/toSolanaAccount.js +8 -0
  7. package/_cjs/accounts/solana/toSolanaAccount.js.map +1 -1
  8. package/_cjs/actions/evm/transfer/accountTransferStrategy.js +30 -63
  9. package/_cjs/actions/evm/transfer/accountTransferStrategy.js.map +1 -1
  10. package/_cjs/actions/evm/transfer/smartAccountTransferStrategy.js +39 -56
  11. package/_cjs/actions/evm/transfer/smartAccountTransferStrategy.js.map +1 -1
  12. package/_cjs/actions/evm/transfer/transfer.js +2 -39
  13. package/_cjs/actions/evm/transfer/transfer.js.map +1 -1
  14. package/_cjs/actions/evm/transfer/utils.js +0 -12
  15. package/_cjs/actions/evm/transfer/utils.js.map +1 -1
  16. package/_cjs/actions/solana/constants.js +9 -0
  17. package/_cjs/actions/solana/constants.js.map +1 -0
  18. package/_cjs/actions/solana/transfer.js +117 -0
  19. package/_cjs/actions/solana/transfer.js.map +1 -0
  20. package/_cjs/actions/solana/utils.js +66 -0
  21. package/_cjs/actions/solana/utils.js.map +1 -0
  22. package/_cjs/analytics.js +70 -8
  23. package/_cjs/analytics.js.map +1 -1
  24. package/_cjs/client/cdp.js +9 -3
  25. package/_cjs/client/cdp.js.map +1 -1
  26. package/_cjs/client/evm/evm.js +133 -15
  27. package/_cjs/client/evm/evm.js.map +1 -1
  28. package/_cjs/client/policies/index.js +6 -0
  29. package/_cjs/client/policies/index.js.map +1 -0
  30. package/_cjs/client/policies/policies.js +232 -0
  31. package/_cjs/client/policies/policies.js.map +1 -0
  32. package/_cjs/client/policies/policies.types.js +3 -0
  33. package/_cjs/client/policies/policies.types.js.map +1 -0
  34. package/_cjs/client/solana/solana.js +76 -19
  35. package/_cjs/client/solana/solana.js.map +1 -1
  36. package/_cjs/index.js +4 -1
  37. package/_cjs/index.js.map +1 -1
  38. package/_cjs/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js +35 -4
  39. package/_cjs/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js.map +1 -1
  40. package/_cjs/openapi-client/generated/evm-accounts/evm-accounts.js +27 -1
  41. package/_cjs/openapi-client/generated/evm-accounts/evm-accounts.js.map +1 -1
  42. package/_cjs/openapi-client/generated/evm-accounts/evm-accounts.msw.js +56 -1
  43. package/_cjs/openapi-client/generated/evm-accounts/evm-accounts.msw.js.map +1 -1
  44. package/_cjs/openapi-client/generated/evm-smart-accounts/evm-smart-accounts.js +3 -1
  45. package/_cjs/openapi-client/generated/evm-smart-accounts/evm-smart-accounts.js.map +1 -1
  46. package/_cjs/openapi-client/generated/index.msw.js +2 -2
  47. package/_cjs/openapi-client/generated/index.msw.js.map +1 -1
  48. package/_cjs/openapi-client/generated/policy-engine/policy-engine.msw.js +121 -36
  49. package/_cjs/openapi-client/generated/policy-engine/policy-engine.msw.js.map +1 -1
  50. package/_cjs/openapi-client/generated/solana-accounts/solana-accounts.js +14 -1
  51. package/_cjs/openapi-client/generated/solana-accounts/solana-accounts.js.map +1 -1
  52. package/_cjs/openapi-client/generated/solana-accounts/solana-accounts.msw.js +42 -1
  53. package/_cjs/openapi-client/generated/solana-accounts/solana-accounts.msw.js.map +1 -1
  54. package/_cjs/openapi-client/index.js +6 -1
  55. package/_cjs/openapi-client/index.js.map +1 -1
  56. package/_cjs/policies/schema.js +245 -0
  57. package/_cjs/policies/schema.js.map +1 -0
  58. package/_cjs/policies/types.js +3 -0
  59. package/_cjs/policies/types.js.map +1 -0
  60. package/_cjs/version.js +1 -1
  61. package/_esm/accounts/evm/toEvmServerAccount.js +4 -2
  62. package/_esm/accounts/evm/toEvmServerAccount.js.map +1 -1
  63. package/_esm/accounts/evm/toEvmSmartAccount.js.map +1 -1
  64. package/_esm/accounts/solana/toSolanaAccount.js +8 -0
  65. package/_esm/accounts/solana/toSolanaAccount.js.map +1 -1
  66. package/_esm/actions/evm/transfer/accountTransferStrategy.js +31 -64
  67. package/_esm/actions/evm/transfer/accountTransferStrategy.js.map +1 -1
  68. package/_esm/actions/evm/transfer/smartAccountTransferStrategy.js +39 -56
  69. package/_esm/actions/evm/transfer/smartAccountTransferStrategy.js.map +1 -1
  70. package/_esm/actions/evm/transfer/transfer.js +2 -39
  71. package/_esm/actions/evm/transfer/transfer.js.map +1 -1
  72. package/_esm/actions/evm/transfer/utils.js +0 -11
  73. package/_esm/actions/evm/transfer/utils.js.map +1 -1
  74. package/_esm/actions/solana/constants.js +6 -0
  75. package/_esm/actions/solana/constants.js.map +1 -0
  76. package/_esm/actions/solana/transfer.js +114 -0
  77. package/_esm/actions/solana/transfer.js.map +1 -0
  78. package/_esm/actions/solana/utils.js +61 -0
  79. package/_esm/actions/solana/utils.js.map +1 -0
  80. package/_esm/analytics.js +70 -7
  81. package/_esm/analytics.js.map +1 -1
  82. package/_esm/client/cdp.js +10 -4
  83. package/_esm/client/cdp.js.map +1 -1
  84. package/_esm/client/evm/evm.js +133 -15
  85. package/_esm/client/evm/evm.js.map +1 -1
  86. package/_esm/client/policies/index.js +2 -0
  87. package/_esm/client/policies/index.js.map +1 -0
  88. package/_esm/client/policies/policies.js +228 -0
  89. package/_esm/client/policies/policies.js.map +1 -0
  90. package/_esm/client/policies/policies.types.js +2 -0
  91. package/_esm/client/policies/policies.types.js.map +1 -0
  92. package/_esm/client/solana/solana.js +76 -19
  93. package/_esm/client/solana/solana.js.map +1 -1
  94. package/_esm/index.js +1 -0
  95. package/_esm/index.js.map +1 -1
  96. package/_esm/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js +34 -3
  97. package/_esm/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js.map +1 -1
  98. package/_esm/openapi-client/generated/evm-accounts/evm-accounts.js +24 -0
  99. package/_esm/openapi-client/generated/evm-accounts/evm-accounts.js.map +1 -1
  100. package/_esm/openapi-client/generated/evm-accounts/evm-accounts.msw.js +51 -0
  101. package/_esm/openapi-client/generated/evm-accounts/evm-accounts.msw.js.map +1 -1
  102. package/_esm/openapi-client/generated/evm-smart-accounts/evm-smart-accounts.js +3 -1
  103. package/_esm/openapi-client/generated/evm-smart-accounts/evm-smart-accounts.js.map +1 -1
  104. package/_esm/openapi-client/generated/index.msw.js +2 -2
  105. package/_esm/openapi-client/generated/index.msw.js.map +1 -1
  106. package/_esm/openapi-client/generated/policy-engine/policy-engine.msw.js +116 -35
  107. package/_esm/openapi-client/generated/policy-engine/policy-engine.msw.js.map +1 -1
  108. package/_esm/openapi-client/generated/solana-accounts/solana-accounts.js +12 -0
  109. package/_esm/openapi-client/generated/solana-accounts/solana-accounts.js.map +1 -1
  110. package/_esm/openapi-client/generated/solana-accounts/solana-accounts.msw.js +39 -0
  111. package/_esm/openapi-client/generated/solana-accounts/solana-accounts.msw.js.map +1 -1
  112. package/_esm/openapi-client/index.js +5 -0
  113. package/_esm/openapi-client/index.js.map +1 -1
  114. package/_esm/policies/schema.js +242 -0
  115. package/_esm/policies/schema.js.map +1 -0
  116. package/_esm/policies/types.js +2 -0
  117. package/_esm/policies/types.js.map +1 -0
  118. package/_esm/version.js +1 -1
  119. package/_types/accounts/evm/toEvmServerAccount.d.ts.map +1 -1
  120. package/_types/accounts/evm/toEvmSmartAccount.d.ts.map +1 -1
  121. package/_types/accounts/evm/types.d.ts +6 -3
  122. package/_types/accounts/evm/types.d.ts.map +1 -1
  123. package/_types/accounts/solana/toSolanaAccount.d.ts.map +1 -1
  124. package/_types/actions/evm/transfer/accountTransferStrategy.d.ts +2 -2
  125. package/_types/actions/evm/transfer/accountTransferStrategy.d.ts.map +1 -1
  126. package/_types/actions/evm/transfer/smartAccountTransferStrategy.d.ts +2 -2
  127. package/_types/actions/evm/transfer/smartAccountTransferStrategy.d.ts.map +1 -1
  128. package/_types/actions/evm/transfer/transfer.d.ts +6 -4
  129. package/_types/actions/evm/transfer/transfer.d.ts.map +1 -1
  130. package/_types/actions/evm/transfer/types.d.ts +8 -54
  131. package/_types/actions/evm/transfer/types.d.ts.map +1 -1
  132. package/_types/actions/evm/transfer/utils.d.ts +0 -619
  133. package/_types/actions/evm/transfer/utils.d.ts.map +1 -1
  134. package/_types/actions/evm/types.d.ts +140 -68
  135. package/_types/actions/evm/types.d.ts.map +1 -1
  136. package/_types/actions/solana/constants.d.ts +6 -0
  137. package/_types/actions/solana/constants.d.ts.map +1 -0
  138. package/_types/actions/solana/transfer.d.ts +36 -0
  139. package/_types/actions/solana/transfer.d.ts.map +1 -0
  140. package/_types/actions/solana/types.d.ts +27 -0
  141. package/_types/actions/solana/types.d.ts.map +1 -1
  142. package/_types/actions/solana/utils.d.ts +34 -0
  143. package/_types/actions/solana/utils.d.ts.map +1 -0
  144. package/_types/analytics.d.ts +14 -5
  145. package/_types/analytics.d.ts.map +1 -1
  146. package/_types/client/cdp.d.ts +3 -0
  147. package/_types/client/cdp.d.ts.map +1 -1
  148. package/_types/client/evm/evm.d.ts +89 -1
  149. package/_types/client/evm/evm.d.ts.map +1 -1
  150. package/_types/client/evm/evm.types.d.ts +33 -3
  151. package/_types/client/evm/evm.types.d.ts.map +1 -1
  152. package/_types/client/policies/index.d.ts +2 -0
  153. package/_types/client/policies/index.d.ts.map +1 -0
  154. package/_types/client/policies/policies.d.ts +216 -0
  155. package/_types/client/policies/policies.d.ts.map +1 -0
  156. package/_types/client/policies/policies.types.d.ts +96 -0
  157. package/_types/client/policies/policies.types.d.ts.map +1 -0
  158. package/_types/client/solana/solana.d.ts +43 -1
  159. package/_types/client/solana/solana.d.ts.map +1 -1
  160. package/_types/client/solana/solana.types.d.ts +14 -2
  161. package/_types/client/solana/solana.types.d.ts.map +1 -1
  162. package/_types/index.d.ts +2 -0
  163. package/_types/index.d.ts.map +1 -1
  164. package/_types/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.d.ts +176 -17
  165. package/_types/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.d.ts.map +1 -1
  166. package/_types/openapi-client/generated/evm-accounts/evm-accounts.d.ts +13 -1
  167. package/_types/openapi-client/generated/evm-accounts/evm-accounts.d.ts.map +1 -1
  168. package/_types/openapi-client/generated/evm-accounts/evm-accounts.msw.d.ts +5 -1
  169. package/_types/openapi-client/generated/evm-accounts/evm-accounts.msw.d.ts.map +1 -1
  170. package/_types/openapi-client/generated/evm-smart-accounts/evm-smart-accounts.d.ts +3 -1
  171. package/_types/openapi-client/generated/evm-smart-accounts/evm-smart-accounts.d.ts.map +1 -1
  172. package/_types/openapi-client/generated/index.msw.d.ts +2 -2
  173. package/_types/openapi-client/generated/index.msw.d.ts.map +1 -1
  174. package/_types/openapi-client/generated/policy-engine/policy-engine.msw.d.ts +5 -1
  175. package/_types/openapi-client/generated/policy-engine/policy-engine.msw.d.ts.map +1 -1
  176. package/_types/openapi-client/generated/solana-accounts/solana-accounts.d.ts +7 -1
  177. package/_types/openapi-client/generated/solana-accounts/solana-accounts.d.ts.map +1 -1
  178. package/_types/openapi-client/generated/solana-accounts/solana-accounts.msw.d.ts +2 -0
  179. package/_types/openapi-client/generated/solana-accounts/solana-accounts.msw.d.ts.map +1 -1
  180. package/_types/openapi-client/index.d.ts +18 -0
  181. package/_types/openapi-client/index.d.ts.map +1 -1
  182. package/_types/policies/schema.d.ts +1552 -0
  183. package/_types/policies/schema.d.ts.map +1 -0
  184. package/_types/policies/types.d.ts +19 -0
  185. package/_types/policies/types.d.ts.map +1 -0
  186. package/_types/types/misc.d.ts +39 -0
  187. package/_types/types/misc.d.ts.map +1 -1
  188. package/_types/version.d.ts +1 -1
  189. package/accounts/evm/toEvmServerAccount.ts +11 -7
  190. package/accounts/evm/toEvmSmartAccount.ts +1 -2
  191. package/accounts/evm/types.ts +6 -8
  192. package/accounts/solana/toSolanaAccount.ts +8 -0
  193. package/actions/evm/transfer/accountTransferStrategy.ts +38 -78
  194. package/actions/evm/transfer/smartAccountTransferStrategy.ts +43 -63
  195. package/actions/evm/transfer/transfer.ts +10 -51
  196. package/actions/evm/transfer/types.ts +9 -67
  197. package/actions/evm/transfer/utils.ts +0 -13
  198. package/actions/evm/types.ts +143 -78
  199. package/actions/solana/constants.ts +6 -0
  200. package/actions/solana/transfer.ts +219 -0
  201. package/actions/solana/types.ts +28 -0
  202. package/actions/solana/utils.ts +79 -0
  203. package/analytics.ts +86 -11
  204. package/client/cdp.ts +11 -4
  205. package/client/evm/evm.ts +159 -17
  206. package/client/evm/evm.types.ts +38 -1
  207. package/client/policies/index.ts +1 -0
  208. package/client/policies/policies.ts +246 -0
  209. package/client/policies/policies.types.ts +109 -0
  210. package/client/solana/solana.ts +94 -20
  211. package/client/solana/solana.types.ts +16 -1
  212. package/index.ts +7 -0
  213. package/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.ts +220 -18
  214. package/openapi-client/generated/evm-accounts/evm-accounts.msw.ts +102 -0
  215. package/openapi-client/generated/evm-accounts/evm-accounts.ts +43 -0
  216. package/openapi-client/generated/evm-smart-accounts/evm-smart-accounts.ts +3 -1
  217. package/openapi-client/generated/index.msw.ts +2 -2
  218. package/openapi-client/generated/policy-engine/policy-engine.msw.ts +199 -56
  219. package/openapi-client/generated/solana-accounts/solana-accounts.msw.ts +75 -0
  220. package/openapi-client/generated/solana-accounts/solana-accounts.ts +23 -0
  221. package/openapi-client/index.ts +6 -0
  222. package/package.json +4 -2
  223. package/policies/schema.ts +349 -0
  224. package/policies/types.ts +19 -0
  225. package/types/misc.ts +41 -0
  226. package/version.ts +1 -1
@@ -1,5 +1,3 @@
1
- import { base, baseSepolia } from "viem/chains";
2
-
3
1
  import { Network } from "./types.js";
4
2
 
5
3
  /**
@@ -26,14 +24,3 @@ const addressMap = {
26
24
  export function getErc20Address(token: string, network: Network) {
27
25
  return addressMap[network][token] ?? token;
28
26
  }
29
-
30
- /**
31
- * Map a network to a viem chain.
32
- * TODO: Add more networks (or dynamically map viem chains).
33
- *
34
- * @param network - The network to map to a chain.
35
- * @returns The chain for the given network.
36
- */
37
- export function mapNetworkToChain(network: Network) {
38
- return network === "base" ? base : baseSepolia;
39
- }
@@ -1,63 +1,89 @@
1
1
  import { SendUserOperationOptions, SendUserOperationReturnType } from "./sendUserOperation.js";
2
2
  import { GetUserOperationOptions, UserOperation } from "../../client/evm/evm.types.js";
3
- import { EvmAccount, EvmSmartAccount } from "../../openapi-client/index.js";
3
+ import { Hex } from "../../types/misc.js";
4
4
 
5
5
  import type { ListTokenBalancesOptions, ListTokenBalancesResult } from "./listTokenBalances.js";
6
6
  import type { RequestFaucetOptions, RequestFaucetResult } from "./requestFaucet.js";
7
7
  import type { SendTransactionOptions, TransactionResult } from "./sendTransaction.js";
8
- import type {
9
- AccountTransferOptions,
10
- SmartAccountTransferOptions,
11
- TransferResult,
12
- } from "./transfer/types.js";
8
+ import type { TransferOptions } from "./transfer/types.js";
13
9
  import type {
14
10
  WaitForUserOperationOptions,
15
11
  WaitForUserOperationReturnType,
16
12
  } from "./waitForUserOperation.js";
17
13
 
18
- type Actions<T extends EvmAccount | EvmSmartAccount> = {
14
+ type Actions = {
19
15
  /**
20
- * Transfer an amount of a token from an account to another account.
16
+ * List the token balances of an account.
21
17
  *
22
- * @param options - The options for the transfer.
23
- * @param options.to - The account or 0x-prefixed address to transfer the token to.
24
- * @param options.amount - The amount of the token to transfer.
25
- * @param options.token - The token to transfer.
26
- * @param options.network - The network to transfer the token on.
18
+ * @param options - The options for the list token balances.
19
+ * @param options.network - The network to list the token balances on.
27
20
  *
28
- * @returns The result of the transfer.
21
+ * @returns The result of the list token balances.
29
22
  *
30
23
  * @example
31
24
  * ```typescript
32
- * const { status } = await sender.transfer({
33
- * to: "0x9F663335Cd6Ad02a37B633602E98866CF944124d",
34
- * amount: "0.01",
35
- * token: "usdc",
25
+ * const balances = await account.listTokenBalances({
36
26
  * network: "base-sepolia",
37
27
  * });
38
28
  * ```
29
+ */
30
+ listTokenBalances: (
31
+ options: Omit<ListTokenBalancesOptions, "address">,
32
+ ) => Promise<ListTokenBalancesResult>;
33
+
34
+ /**
35
+ * Requests funds from an EVM faucet.
36
+ *
37
+ * @param {RequestFaucetOptions} options - Parameters for requesting funds from the EVM faucet.
38
+ * @param {string} options.network - The network to request funds from.
39
+ * @param {string} options.token - The token to request funds for.
40
+ * @param {string} [options.idempotencyKey] - An idempotency key.
41
+ *
42
+ * @returns A promise that resolves to the transaction hash.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const result = await account.requestFaucet({
47
+ * network: "base-sepolia",
48
+ * token: "eth",
49
+ * });
50
+ * ```
51
+ */
52
+ requestFaucet: (options: Omit<RequestFaucetOptions, "address">) => Promise<RequestFaucetResult>;
53
+ };
54
+
55
+ export type AccountActions = Actions & {
56
+ /**
57
+ * Transfer an amount of a token from an account to another account.
58
+ *
59
+ * @param options - The options for the transfer.
60
+ * @param options.to - The account or 0x-prefixed address to transfer the token to.
61
+ * @param options.amount - The amount of the token to transfer represented as an atomic unit.
62
+ * It's common to use `parseEther` or `parseUnits` utils from viem to convert to atomic units.
63
+ * Otherwise, you can pass atomic units directly. See examples below.
64
+ * @param options.token - The token to transfer. This can be 'eth', 'usdc', or a contract address.
65
+ * @param options.network - The network to transfer the token on.
66
+ *
67
+ * @returns An object containing the transaction hash.
39
68
  *
40
69
  * @example
41
- * **Pass a bigint value**
42
70
  * ```typescript
43
- * const { status } = await sender.transfer({
71
+ * const { transactionHash } = await sender.transfer({
44
72
  * to: "0x9F663335Cd6Ad02a37B633602E98866CF944124d",
45
- * amount: 10000n, // equivalent to 0.01 usdc
73
+ * amount: 10000n, // equivalent to 0.01 USDC
46
74
  * token: "usdc",
47
75
  * network: "base-sepolia",
48
76
  * });
49
77
  * ```
50
78
  *
51
79
  * @example
52
- * **Transfer from a smart account**
80
+ * **Using parseUnits to specify USDC amount**
53
81
  * ```typescript
54
- * const sender = await cdp.evm.createSmartAccount({
55
- * owner: await cdp.evm.createAccount({ name: "Owner" }),
56
- * });
82
+ * import { parseUnits } from "viem";
57
83
  *
58
- * const { status } = await sender.transfer({
84
+ * const { transactionHash } = await sender.transfer({
59
85
  * to: "0x9F663335Cd6Ad02a37B633602E98866CF944124d",
60
- * amount: "0.01",
86
+ * amount: parseUnits("0.01", 6), // USDC uses 6 decimal places
61
87
  * token: "usdc",
62
88
  * network: "base-sepolia",
63
89
  * });
@@ -66,9 +92,11 @@ type Actions<T extends EvmAccount | EvmSmartAccount> = {
66
92
  * @example
67
93
  * **Transfer ETH**
68
94
  * ```typescript
69
- * const { status } = await sender.transfer({
95
+ * import { parseEther } from "viem";
96
+ *
97
+ * const { transactionHash } = await sender.transfer({
70
98
  * to: "0x9F663335Cd6Ad02a37B633602E98866CF944124d",
71
- * amount: "0.000001",
99
+ * amount: parseEther("0.000001"),
72
100
  * token: "eth",
73
101
  * network: "base-sepolia",
74
102
  * });
@@ -77,9 +105,11 @@ type Actions<T extends EvmAccount | EvmSmartAccount> = {
77
105
  * @example
78
106
  * **Using a contract address**
79
107
  * ```typescript
80
- * const { status } = await sender.transfer({
108
+ * import { parseEther } from "viem";
109
+ *
110
+ * const { transactionHash } = await sender.transfer({
81
111
  * to: "0x9F663335Cd6Ad02a37B633602E98866CF944124d",
82
- * amount: "0.000001",
112
+ * amount: parseEther("0.000001"),
83
113
  * token: "0x4200000000000000000000000000000000000006", // WETH on Base Sepolia
84
114
  * network: "base-sepolia",
85
115
  * });
@@ -91,59 +121,16 @@ type Actions<T extends EvmAccount | EvmSmartAccount> = {
91
121
  * const sender = await cdp.evm.createAccount({ name: "Sender" });
92
122
  * const receiver = await cdp.evm.createAccount({ name: "Receiver" });
93
123
  *
94
- * const { status } = await sender.transfer({
124
+ * const { transactionHash } = await sender.transfer({
95
125
  * to: receiver,
96
- * amount: "0.01",
126
+ * amount: 10000n, // equivalent to 0.01 USDC
97
127
  * token: "usdc",
98
128
  * network: "base-sepolia",
99
129
  * });
100
130
  * ```
101
131
  */
102
- transfer: (
103
- options: T extends EvmSmartAccount ? SmartAccountTransferOptions : AccountTransferOptions,
104
- ) => Promise<TransferResult>;
105
-
106
- /**
107
- * List the token balances of an account.
108
- *
109
- * @param options - The options for the list token balances.
110
- * @param options.network - The network to list the token balances on.
111
- *
112
- * @returns The result of the list token balances.
113
- *
114
- * @example
115
- * ```typescript
116
- * const balances = await account.listTokenBalances({
117
- * network: "base-sepolia",
118
- * });
119
- * ```
120
- */
121
- listTokenBalances: (
122
- options: Omit<ListTokenBalancesOptions, "address">,
123
- ) => Promise<ListTokenBalancesResult>;
124
-
125
- /**
126
- * Requests funds from an EVM faucet.
127
- *
128
- * @param {RequestFaucetOptions} options - Parameters for requesting funds from the EVM faucet.
129
- * @param {string} options.network - The network to request funds from.
130
- * @param {string} options.token - The token to request funds for.
131
- * @param {string} [options.idempotencyKey] - An idempotency key.
132
- *
133
- * @returns A promise that resolves to the transaction hash.
134
- *
135
- * @example
136
- * ```ts
137
- * const result = await account.requestFaucet({
138
- * network: "base-sepolia",
139
- * token: "eth",
140
- * });
141
- * ```
142
- */
143
- requestFaucet: (options: Omit<RequestFaucetOptions, "address">) => Promise<RequestFaucetResult>;
144
- };
132
+ transfer: (options: TransferOptions) => Promise<{ transactionHash: Hex }>;
145
133
 
146
- export type AccountActions = Actions<EvmAccount> & {
147
134
  /**
148
135
  * Signs an EVM transaction and sends it to the specified network using the Coinbase API.
149
136
  * This method handles nonce management and gas estimation automatically.
@@ -191,7 +178,85 @@ export type AccountActions = Actions<EvmAccount> & {
191
178
  sendTransaction: (options: Omit<SendTransactionOptions, "address">) => Promise<TransactionResult>;
192
179
  };
193
180
 
194
- export type SmartAccountActions = Actions<EvmSmartAccount> & {
181
+ export type SmartAccountActions = Actions & {
182
+ /**
183
+ * Transfer an amount of a token from an account to another account.
184
+ *
185
+ * @param options - The options for the transfer.
186
+ * @param options.to - The account or 0x-prefixed address to transfer the token to.
187
+ * @param options.amount - The amount of the token to transfer represented as an atomic unit.
188
+ * It's common to use `parseEther` or `parseUnits` utils from viem to convert to atomic units.
189
+ * Otherwise, you can pass atomic units directly. See examples below.
190
+ * @param options.token - The token to transfer. This can be 'eth', 'usdc', or a contract address.
191
+ * @param options.network - The network to transfer the token on.
192
+ *
193
+ * @returns The user operation result.
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * const { userOpHash } = await sender.transfer({
198
+ * to: "0x9F663335Cd6Ad02a37B633602E98866CF944124d",
199
+ * amount: 10000n, // equivalent to 0.01 USDC
200
+ * token: "usdc",
201
+ * network: "base-sepolia",
202
+ * });
203
+ * ```
204
+ *
205
+ * @example
206
+ * **Using parseUnits to specify USDC amount**
207
+ * ```typescript
208
+ * import { parseUnits } from "viem";
209
+ *
210
+ * const { userOpHash } = await sender.transfer({
211
+ * to: "0x9F663335Cd6Ad02a37B633602E98866CF944124d",
212
+ * amount: parseUnits("0.01", 6), // USDC uses 6 decimal places
213
+ * token: "usdc",
214
+ * network: "base-sepolia",
215
+ * });
216
+ * ```
217
+ *
218
+ * @example
219
+ * **Transfer ETH**
220
+ * ```typescript
221
+ * import { parseEther } from "viem";
222
+ *
223
+ * const { userOpHash } = await sender.transfer({
224
+ * to: "0x9F663335Cd6Ad02a37B633602E98866CF944124d",
225
+ * amount: parseEther("0.000001"),
226
+ * token: "eth",
227
+ * network: "base-sepolia",
228
+ * });
229
+ * ```
230
+ *
231
+ * @example
232
+ * **Using a contract address**
233
+ * ```typescript
234
+ * import { parseEther } from "viem";
235
+ *
236
+ * const { userOpHash } = await sender.transfer({
237
+ * to: "0x9F663335Cd6Ad02a37B633602E98866CF944124d",
238
+ * amount: parseEther("0.000001"),
239
+ * token: "0x4200000000000000000000000000000000000006", // WETH on Base Sepolia
240
+ * network: "base-sepolia",
241
+ * });
242
+ * ```
243
+ *
244
+ * @example
245
+ * **Transfer to another account**
246
+ * ```typescript
247
+ * const sender = await cdp.evm.createAccount({ name: "Sender" });
248
+ * const receiver = await cdp.evm.createAccount({ name: "Receiver" });
249
+ *
250
+ * const { userOpHash } = await sender.transfer({
251
+ * to: receiver,
252
+ * amount: 10000n, // equivalent to 0.01 USDC
253
+ * token: "usdc",
254
+ * network: "base-sepolia",
255
+ * });
256
+ * ```
257
+ */
258
+ transfer: (options: TransferOptions) => Promise<SendUserOperationReturnType>;
259
+
195
260
  /**
196
261
  * Sends a user operation.
197
262
  *
@@ -0,0 +1,6 @@
1
+ export const GENESIS_HASH_MAINNET = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d";
2
+ export const GENESIS_HASH_DEVNET = "EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG";
3
+ export const GENESIS_HASH_TESTNET = "4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY";
4
+
5
+ export const USDC_MAINNET_MINT_ADDRESS = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
6
+ export const USDC_DEVNET_MINT_ADDRESS = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU";
@@ -0,0 +1,219 @@
1
+ import {
2
+ getMint,
3
+ getAssociatedTokenAddress,
4
+ getAccount,
5
+ createAssociatedTokenAccountInstruction,
6
+ createTransferCheckedInstruction,
7
+ } from "@solana/spl-token";
8
+ import {
9
+ Connection,
10
+ MessageV0,
11
+ PublicKey,
12
+ SystemProgram,
13
+ TransactionInstruction,
14
+ TransactionMessage,
15
+ VersionedTransaction,
16
+ } from "@solana/web3.js";
17
+
18
+ import {
19
+ getConnectedNetwork,
20
+ getOrCreateConnection,
21
+ getUsdcMintAddress,
22
+ type Network,
23
+ } from "./utils.js";
24
+
25
+ import type { SignatureResult } from "../../client/solana/solana.types.js";
26
+ import type { CdpOpenApiClientType } from "../../openapi-client/index.js";
27
+
28
+ export interface TransferOptions {
29
+ /**
30
+ * The base58 encoded Solana address of the source account.
31
+ */
32
+ from: string;
33
+ /**
34
+ * The base58 encoded Solana address of the destination account.
35
+ */
36
+ to: string;
37
+ /**
38
+ * The amount to transfer, represented as an atomic unit of the token.
39
+ */
40
+ amount: bigint;
41
+ /**
42
+ * The token to transfer, or mint address of the SPL token to transfer.
43
+ */
44
+ token: "sol" | "usdc" | string;
45
+ /**
46
+ * The network to use which will be used to create a Connection, otherwise a Connection can be provided.
47
+ */
48
+ network: Network | Connection;
49
+ }
50
+
51
+ /**
52
+ * Transfers SOL or SPL tokens between accounts
53
+ *
54
+ * @param apiClient - The API client to use
55
+ * @param options - The transfer options
56
+ *
57
+ * @returns The transfer result
58
+ */
59
+ export async function transfer(
60
+ apiClient: CdpOpenApiClientType,
61
+ options: TransferOptions,
62
+ ): Promise<SignatureResult> {
63
+ const connection = getOrCreateConnection({ networkOrConnection: options.network });
64
+
65
+ const tx =
66
+ options.token === "sol"
67
+ ? await getNativeTransfer({
68
+ connection,
69
+ from: options.from,
70
+ to: options.to,
71
+ amount: options.amount,
72
+ })
73
+ : await getSplTransfer({
74
+ connection,
75
+ from: options.from,
76
+ to: options.to,
77
+ mintAddress:
78
+ options.token === "usdc"
79
+ ? getUsdcMintAddress(await getConnectedNetwork(connection))
80
+ : options.token,
81
+ amount: options.amount,
82
+ });
83
+
84
+ const serializedTx = Buffer.from(tx.serialize()).toString("base64");
85
+
86
+ const signedTxResponse = await apiClient.signSolanaTransaction(options.from, {
87
+ transaction: serializedTx,
88
+ });
89
+
90
+ const decodedSignedTx = Buffer.from(signedTxResponse.signedTransaction, "base64");
91
+
92
+ const signature = await connection.sendRawTransaction(decodedSignedTx, {
93
+ skipPreflight: false,
94
+ maxRetries: 3,
95
+ });
96
+
97
+ return { signature };
98
+ }
99
+
100
+ type GetNativeTransferOptions = Omit<TransferOptions, "token" | "network"> & {
101
+ /**
102
+ * The connection to the Solana network
103
+ */
104
+ connection: Connection;
105
+ };
106
+
107
+ /**
108
+ * Gets the instructions for a native SOL transfer
109
+ *
110
+ * @param options - The options for the native SOL transfer
111
+ *
112
+ * @param options.connection - The Solana connection
113
+ * @param options.from - The source address
114
+ * @param options.to - The destination address
115
+ * @param options.amount - The amount to transfer
116
+ *
117
+ * @returns The native SOL transfer transaction
118
+ */
119
+ async function getNativeTransfer({
120
+ connection,
121
+ from,
122
+ to,
123
+ amount,
124
+ }: GetNativeTransferOptions): Promise<VersionedTransaction> {
125
+ const { blockhash } = await connection.getLatestBlockhash();
126
+
127
+ const instructions = [
128
+ SystemProgram.transfer({
129
+ fromPubkey: new PublicKey(from),
130
+ toPubkey: new PublicKey(to),
131
+ lamports: amount,
132
+ }),
133
+ ];
134
+
135
+ const messageV0 = new TransactionMessage({
136
+ payerKey: new PublicKey(from),
137
+ recentBlockhash: blockhash,
138
+ instructions,
139
+ }).compileToV0Message();
140
+
141
+ return new VersionedTransaction(messageV0);
142
+ }
143
+
144
+ type GetSplTransferOptions = GetNativeTransferOptions & {
145
+ /**
146
+ * The mint address of the token
147
+ */
148
+ mintAddress: string;
149
+ };
150
+
151
+ /**
152
+ * Gets the instructions for a SPL token transfer
153
+ *
154
+ * @param options - The options for the SPL token transfer
155
+ *
156
+ * @param options.connection - The Solana connection
157
+ * @param options.from - The source address
158
+ * @param options.to - The destination address
159
+ * @param options.mintAddress - The mint address of the token
160
+ * @param options.amount - The amount to transfer
161
+ *
162
+ * @returns The SPL token transfer transaction
163
+ */
164
+ async function getSplTransfer({
165
+ connection,
166
+ from,
167
+ to,
168
+ mintAddress,
169
+ amount,
170
+ }: GetSplTransferOptions): Promise<VersionedTransaction> {
171
+ const fromPubkey = new PublicKey(from);
172
+ const toPubkey = new PublicKey(to);
173
+ const mintPubkey = new PublicKey(mintAddress);
174
+
175
+ let mintInfo: Awaited<ReturnType<typeof getMint>>;
176
+ try {
177
+ mintInfo = await getMint(connection, mintPubkey);
178
+ } catch (error) {
179
+ throw new Error(`Failed to fetch mint info for mint address ${mintAddress}. Error: ${error}`);
180
+ }
181
+
182
+ const sourceAta = await getAssociatedTokenAddress(mintPubkey, fromPubkey);
183
+ const destinationAta = await getAssociatedTokenAddress(mintPubkey, toPubkey);
184
+
185
+ const instructions: TransactionInstruction[] = [];
186
+
187
+ const sourceAccount = await getAccount(connection, sourceAta);
188
+ if (sourceAccount.amount < amount) {
189
+ throw new Error(`Insufficient token balance. Have ${sourceAccount.amount}, need ${amount}`);
190
+ }
191
+
192
+ // Check if destination account exists, if not create it
193
+ try {
194
+ await getAccount(connection, destinationAta);
195
+ } catch {
196
+ instructions.push(
197
+ createAssociatedTokenAccountInstruction(fromPubkey, destinationAta, toPubkey, mintPubkey),
198
+ );
199
+ }
200
+
201
+ instructions.push(
202
+ createTransferCheckedInstruction(
203
+ sourceAta,
204
+ mintPubkey,
205
+ destinationAta,
206
+ fromPubkey,
207
+ amount,
208
+ mintInfo.decimals,
209
+ ),
210
+ );
211
+
212
+ return new VersionedTransaction(
213
+ MessageV0.compile({
214
+ payerKey: fromPubkey,
215
+ instructions: instructions,
216
+ recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
217
+ }),
218
+ );
219
+ }
@@ -1,3 +1,4 @@
1
+ import { TransferOptions } from "./transfer.js";
1
2
  import {
2
3
  RequestFaucetOptions,
3
4
  SignatureResult,
@@ -84,4 +85,31 @@ export type AccountActions = {
84
85
  * ```
85
86
  */
86
87
  signTransaction: (options: Omit<SignTransactionOptions, "address">) => Promise<SignatureResult>;
88
+
89
+ /**
90
+ * Transfers SOL or SPL tokens between accounts
91
+ *
92
+ * @param {TransferOptions} options - Parameters for the transfer.
93
+ * @param {string} options.to - The base58 encoded Solana address of the destination account.
94
+ * @param {sol|usdc|string} options.token - The token to transfer ("sol" or "usdc"), or mint address of the SPL token to transfer.
95
+ * @param {bigint} options.amount - The amount to transfer in atomic units of the token. For example, 0.01 * LAMPORTS_PER_SOL would transfer 0.01 SOL.
96
+ * @param {string | Connection} options.network - The network identifier to use, or a Solana Connection object.
97
+ *
98
+ * @returns A promise that resolves to the transaction signature, which can be used to wait for the transaction result.
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * import { LAMPORTS_PER_SOL } from "@solana/web3.js";
103
+ *
104
+ * const account = await cdp.solana.getAccount({ name: "Account" });
105
+ *
106
+ * const { signature } = await account.transfer({
107
+ * token: "sol",
108
+ * amount: 5 * LAMPORTS_PER_SOL,
109
+ * to: "3KzDtddx4i53FBkvCzuDmRbaMozTZoJBb1TToWhz3JfE",
110
+ * network: "devnet",
111
+ * });
112
+ * ```
113
+ */
114
+ transfer: (options: Omit<TransferOptions, "from">) => Promise<SignatureResult>;
87
115
  };
@@ -0,0 +1,79 @@
1
+ import { Connection } from "@solana/web3.js";
2
+
3
+ import {
4
+ GENESIS_HASH_MAINNET,
5
+ GENESIS_HASH_TESTNET,
6
+ GENESIS_HASH_DEVNET,
7
+ USDC_MAINNET_MINT_ADDRESS,
8
+ USDC_DEVNET_MINT_ADDRESS,
9
+ } from "./constants.js";
10
+
11
+ export type Network = "mainnet" | "devnet" | "testnet";
12
+
13
+ type GetOrCreateConnectionOptions = {
14
+ networkOrConnection: Network | Connection;
15
+ };
16
+
17
+ /**
18
+ * Get a connection to the Solana network
19
+ *
20
+ * @param options - The options for the connection
21
+ *
22
+ * @param options.networkOrConnection - The network to use or a connection
23
+ *
24
+ * @returns The connection
25
+ */
26
+ export function getOrCreateConnection({
27
+ networkOrConnection,
28
+ }: GetOrCreateConnectionOptions): Connection {
29
+ if (typeof networkOrConnection !== "string") {
30
+ return networkOrConnection;
31
+ }
32
+
33
+ return new Connection(
34
+ networkOrConnection === "mainnet"
35
+ ? "https://api.mainnet-beta.solana.com"
36
+ : networkOrConnection === "devnet"
37
+ ? "https://api.devnet.solana.com"
38
+ : "https://api.testnet.solana.com",
39
+ );
40
+ }
41
+
42
+ /**
43
+ * Get the network of the connected Solana node
44
+ *
45
+ * @param connection - The connection to the Solana network
46
+ * @throws {Error} If the network is not mainnet, devnet, or testnet
47
+ *
48
+ * @returns The network of the connected Solana node
49
+ */
50
+ export async function getConnectedNetwork(connection: Connection): Promise<Network> {
51
+ const genesisHash = await connection.getGenesisHash();
52
+
53
+ if (genesisHash === GENESIS_HASH_MAINNET) {
54
+ return "mainnet";
55
+ } else if (genesisHash === GENESIS_HASH_DEVNET) {
56
+ return "devnet";
57
+ } else if (genesisHash === GENESIS_HASH_TESTNET) {
58
+ return "testnet";
59
+ }
60
+
61
+ throw new Error("Unknown network");
62
+ }
63
+
64
+ /**
65
+ * Get the USDC mint address for the given connection
66
+ *
67
+ * @param network - The network to use
68
+ *
69
+ * @returns The USDC mint address
70
+ */
71
+ export function getUsdcMintAddress(network: Network): string {
72
+ if (network === "mainnet") {
73
+ return USDC_MAINNET_MINT_ADDRESS;
74
+ } else if (network === "devnet") {
75
+ return USDC_DEVNET_MINT_ADDRESS;
76
+ } else {
77
+ throw new Error("Testnet is not supported for USDC");
78
+ }
79
+ }