@coinbase/cdp-sdk 1.15.0 → 1.16.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 (77) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +82 -20
  3. package/_cjs/accounts/evm/toEvmServerAccount.js +13 -7
  4. package/_cjs/accounts/evm/toEvmServerAccount.js.map +1 -1
  5. package/_cjs/accounts/evm/toEvmSmartAccount.js +18 -0
  6. package/_cjs/accounts/evm/toEvmSmartAccount.js.map +1 -1
  7. package/_cjs/actions/evm/signAndWrapTypedDataForSmartAccount.js +186 -0
  8. package/_cjs/actions/evm/signAndWrapTypedDataForSmartAccount.js.map +1 -0
  9. package/_cjs/actions/evm/swap/createSwapQuote.js +26 -8
  10. package/_cjs/actions/evm/swap/createSwapQuote.js.map +1 -1
  11. package/_cjs/actions/evm/swap/getSwapPrice.js +3 -2
  12. package/_cjs/actions/evm/swap/getSwapPrice.js.map +1 -1
  13. package/_cjs/actions/evm/swap/sendSwapOperation.js +153 -0
  14. package/_cjs/actions/evm/swap/sendSwapOperation.js.map +1 -0
  15. package/_cjs/actions/evm/swap/sendSwapTransaction.js +16 -2
  16. package/_cjs/actions/evm/swap/sendSwapTransaction.js.map +1 -1
  17. package/_cjs/client/evm/evm.js +13 -6
  18. package/_cjs/client/evm/evm.js.map +1 -1
  19. package/_cjs/utils/uuidV4.js +26 -0
  20. package/_cjs/utils/uuidV4.js.map +1 -0
  21. package/_cjs/version.js +1 -1
  22. package/_esm/accounts/evm/toEvmServerAccount.js +14 -8
  23. package/_esm/accounts/evm/toEvmServerAccount.js.map +1 -1
  24. package/_esm/accounts/evm/toEvmSmartAccount.js +18 -0
  25. package/_esm/accounts/evm/toEvmSmartAccount.js.map +1 -1
  26. package/_esm/actions/evm/signAndWrapTypedDataForSmartAccount.js +181 -0
  27. package/_esm/actions/evm/signAndWrapTypedDataForSmartAccount.js.map +1 -0
  28. package/_esm/actions/evm/swap/createSwapQuote.js +26 -8
  29. package/_esm/actions/evm/swap/createSwapQuote.js.map +1 -1
  30. package/_esm/actions/evm/swap/getSwapPrice.js +3 -2
  31. package/_esm/actions/evm/swap/getSwapPrice.js.map +1 -1
  32. package/_esm/actions/evm/swap/sendSwapOperation.js +150 -0
  33. package/_esm/actions/evm/swap/sendSwapOperation.js.map +1 -0
  34. package/_esm/actions/evm/swap/sendSwapTransaction.js +16 -2
  35. package/_esm/actions/evm/swap/sendSwapTransaction.js.map +1 -1
  36. package/_esm/client/evm/evm.js +14 -7
  37. package/_esm/client/evm/evm.js.map +1 -1
  38. package/_esm/utils/uuidV4.js +23 -0
  39. package/_esm/utils/uuidV4.js.map +1 -0
  40. package/_esm/version.js +1 -1
  41. package/_types/accounts/evm/toEvmServerAccount.d.ts.map +1 -1
  42. package/_types/accounts/evm/toEvmSmartAccount.d.ts.map +1 -1
  43. package/_types/accounts/evm/types.d.ts +4 -4
  44. package/_types/accounts/evm/types.d.ts.map +1 -1
  45. package/_types/actions/evm/signAndWrapTypedDataForSmartAccount.d.ts +133 -0
  46. package/_types/actions/evm/signAndWrapTypedDataForSmartAccount.d.ts.map +1 -0
  47. package/_types/actions/evm/swap/createSwapQuote.d.ts.map +1 -1
  48. package/_types/actions/evm/swap/getSwapPrice.d.ts +2 -1
  49. package/_types/actions/evm/swap/getSwapPrice.d.ts.map +1 -1
  50. package/_types/actions/evm/swap/sendSwapOperation.d.ts +64 -0
  51. package/_types/actions/evm/swap/sendSwapOperation.d.ts.map +1 -0
  52. package/_types/actions/evm/swap/sendSwapTransaction.d.ts.map +1 -1
  53. package/_types/actions/evm/swap/types.d.ts +131 -5
  54. package/_types/actions/evm/swap/types.d.ts.map +1 -1
  55. package/_types/actions/evm/types.d.ts +112 -21
  56. package/_types/actions/evm/types.d.ts.map +1 -1
  57. package/_types/client/evm/evm.d.ts.map +1 -1
  58. package/_types/client/evm/evm.types.d.ts +32 -6
  59. package/_types/client/evm/evm.types.d.ts.map +1 -1
  60. package/_types/utils/uuidV4.d.ts +10 -0
  61. package/_types/utils/uuidV4.d.ts.map +1 -0
  62. package/_types/version.d.ts +1 -1
  63. package/accounts/evm/toEvmServerAccount.ts +33 -15
  64. package/accounts/evm/toEvmSmartAccount.ts +25 -0
  65. package/accounts/evm/types.ts +14 -6
  66. package/actions/evm/signAndWrapTypedDataForSmartAccount.ts +246 -0
  67. package/actions/evm/swap/createSwapQuote.ts +42 -17
  68. package/actions/evm/swap/getSwapPrice.ts +15 -11
  69. package/actions/evm/swap/sendSwapOperation.ts +182 -0
  70. package/actions/evm/swap/sendSwapTransaction.ts +18 -2
  71. package/actions/evm/swap/types.ts +154 -5
  72. package/actions/evm/types.ts +123 -21
  73. package/client/evm/evm.ts +19 -8
  74. package/client/evm/evm.types.ts +33 -6
  75. package/package.json +1 -1
  76. package/utils/uuidV4.ts +23 -0
  77. package/version.ts +1 -1
@@ -0,0 +1,182 @@
1
+ import { concat, numberToHex, size } from "viem";
2
+
3
+ import { createSwapQuote } from "./createSwapQuote.js";
4
+ import { createDeterministicUuidV4 } from "../../../utils/uuidV4.js";
5
+ import { sendUserOperation } from "../sendUserOperation.js";
6
+ import { signAndWrapTypedDataForSmartAccount } from "../signAndWrapTypedDataForSmartAccount.js";
7
+
8
+ import type { SendSwapOperationOptions, SendSwapOperationResult } from "./types.js";
9
+ import type { EvmSmartAccount } from "../../../accounts/evm/types.js";
10
+ import type {
11
+ CreateSwapQuoteResult,
12
+ CreateSwapQuoteOptions,
13
+ SwapUnavailableResult,
14
+ } from "../../../client/evm/evm.types.js";
15
+ import type {
16
+ CdpOpenApiClientType,
17
+ EvmUserOperationNetwork,
18
+ } from "../../../openapi-client/index.js";
19
+ import type { Hex } from "../../../types/misc.js";
20
+
21
+ /**
22
+ * Sends a swap operation to the blockchain via a smart account user operation.
23
+ * Handles any permit2 signatures required for the swap.
24
+ *
25
+ * If you encounter token allowance issues, you'll need to perform a token approval transaction first to allow
26
+ * the Permit2 contract to spend the appropriate amount of your fromToken.
27
+ * See examples for code on handling token approvals.
28
+ *
29
+ * @param {CdpOpenApiClientType} client - The client to use for sending the swap operation.
30
+ * @param {SendSwapOperationOptions} options - The options for the swap submission.
31
+ *
32
+ * @returns {Promise<SendSwapOperationResult>} A promise that resolves to the user operation result.
33
+ *
34
+ * @throws {Error} If liquidity is not available for the swap.
35
+ * @throws {Error} If there are insufficient token allowances. In this case, you need to approve the
36
+ * Permit2 contract to spend your tokens before attempting the swap. The error message
37
+ * will include the current allowance and the spender address that needs approval.
38
+ * @throws {Error} If no transaction data is found in the swap result.
39
+ *
40
+ * @example **Sending a swap with pre-created swap quote object**
41
+ * ```ts
42
+ * // First create a swap quote
43
+ * const swapQuote = await cdp.evm.createSwapQuote({
44
+ * network: "base",
45
+ * toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
46
+ * fromToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
47
+ * fromAmount: BigInt("1000000000000000000"), // 1 WETH in wei
48
+ * taker: smartAccount.address
49
+ * });
50
+ *
51
+ * // Check if liquidity is available
52
+ * if (!swapQuote.liquidityAvailable) {
53
+ * console.error("Insufficient liquidity for swap");
54
+ * return;
55
+ * }
56
+ *
57
+ * // Send the swap operation
58
+ * const result = await sendSwapOperation(client, {
59
+ * smartAccount: smartAccount,
60
+ * swapQuote: swapQuote
61
+ * });
62
+ *
63
+ * console.log(`Swap operation sent with user op hash: ${result.userOpHash}`);
64
+ * ```
65
+ *
66
+ * @example **Sending a swap with inline options (all-in-one)**
67
+ * ```ts
68
+ * // Send swap operation in one call
69
+ * const result = await sendSwapOperation(client, {
70
+ * smartAccount: smartAccount,
71
+ * network: "base",
72
+ * toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
73
+ * fromToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
74
+ * fromAmount: BigInt("1000000000000000000"), // 1 WETH in wei
75
+ * taker: smartAccount.address
76
+ * });
77
+ *
78
+ * console.log(`Swap operation sent with user op hash: ${result.userOpHash}`);
79
+ * ```
80
+ */
81
+ export async function sendSwapOperation(
82
+ client: CdpOpenApiClientType,
83
+ options: SendSwapOperationOptions,
84
+ ): Promise<SendSwapOperationResult> {
85
+ const { smartAccount, paymasterUrl, idempotencyKey } = options;
86
+
87
+ let swapResult: CreateSwapQuoteResult | SwapUnavailableResult;
88
+
89
+ // Determine if we need to create the swap quote or use the provided one
90
+ if ("swapQuote" in options) {
91
+ // Use the provided swap quote
92
+ swapResult = options.swapQuote;
93
+ } else {
94
+ // Create the swap quote using the provided options (inline options)
95
+ /**
96
+ * Deterministically derive a new idempotency key from the provided idempotency key for swap quote creation to avoid key reuse.
97
+ */
98
+ const swapQuoteIdempotencyKey = idempotencyKey
99
+ ? createDeterministicUuidV4(idempotencyKey, "createSwapQuote")
100
+ : undefined;
101
+
102
+ swapResult = await createSwapQuote(client, {
103
+ network: options.network as CreateSwapQuoteOptions["network"],
104
+ toToken: options.toToken,
105
+ fromToken: options.fromToken,
106
+ fromAmount: options.fromAmount,
107
+ taker: options.taker,
108
+ signerAddress: options.signerAddress,
109
+ gasPrice: options.gasPrice,
110
+ slippageBps: options.slippageBps,
111
+ idempotencyKey: swapQuoteIdempotencyKey,
112
+ });
113
+ }
114
+
115
+ // Check if liquidity is available
116
+ if (!swapResult.liquidityAvailable) {
117
+ throw new Error("Insufficient liquidity for swap");
118
+ }
119
+
120
+ // At this point, we know that swapResult is CreateSwapQuoteResult
121
+ const swap = swapResult as CreateSwapQuoteResult;
122
+
123
+ // Check for allowance issues
124
+ if (swap.issues?.allowance) {
125
+ const { currentAllowance, spender } = swap.issues.allowance;
126
+ throw new Error(
127
+ `Insufficient token allowance for swap. Current allowance: ${currentAllowance}. ` +
128
+ `Please approve the Permit2 contract (${spender}) to spend your tokens.`,
129
+ );
130
+ }
131
+
132
+ // If the transaction doesn't exist, throw an error
133
+ if (!swap.transaction) {
134
+ throw new Error("No transaction data found in the swap");
135
+ }
136
+
137
+ // Get the transaction data and modify it if needed for Permit2
138
+ let txData = swap.transaction.data as Hex;
139
+
140
+ if (swap.permit2?.eip712) {
141
+ // Create the permit2 idempotency key
142
+ const permit2IdempotencyKey = idempotencyKey
143
+ ? createDeterministicUuidV4(idempotencyKey, "permit2")
144
+ : undefined;
145
+
146
+ // Sign and wrap the permit2 typed data according to the Coinbase Smart Wallet contract requirements for EIP-712 signatures
147
+ const { signature: wrappedSignature } = await signAndWrapTypedDataForSmartAccount(client, {
148
+ smartAccount,
149
+ chainId: BigInt(swap.permit2.eip712.domain.chainId || 1),
150
+ typedData: swap.permit2.eip712,
151
+ ownerIndex: 0n,
152
+ idempotencyKey: permit2IdempotencyKey,
153
+ });
154
+
155
+ // Calculate the Permit2 signature length as a 32-byte hex value
156
+ const permit2SignatureLengthInHex = numberToHex(size(wrappedSignature), {
157
+ signed: false,
158
+ size: 32,
159
+ });
160
+
161
+ // Append the Permit2 signature length and signature to the transaction data
162
+ txData = concat([txData, permit2SignatureLengthInHex, wrappedSignature]);
163
+ }
164
+
165
+ // Send the swap as a user operation
166
+ const result = await sendUserOperation(client, {
167
+ smartAccount: smartAccount as EvmSmartAccount,
168
+ network: swap.network as EvmUserOperationNetwork,
169
+ paymasterUrl,
170
+ idempotencyKey,
171
+ calls: [
172
+ {
173
+ to: swap.transaction.to,
174
+ data: txData,
175
+ // Only include value if it exists
176
+ ...(swap.transaction.value ? { value: BigInt(swap.transaction.value) } : {}),
177
+ },
178
+ ],
179
+ });
180
+
181
+ return result;
182
+ }
@@ -1,6 +1,7 @@
1
1
  import { concat, numberToHex, size } from "viem";
2
2
 
3
3
  import { createSwapQuote } from "./createSwapQuote.js";
4
+ import { createDeterministicUuidV4 } from "../../../utils/uuidV4.js";
4
5
  import { sendTransaction } from "../sendTransaction.js";
5
6
 
6
7
  import type { SendSwapTransactionOptions, SendSwapTransactionResult } from "./types.js";
@@ -90,6 +91,13 @@ export async function sendSwapTransaction(
90
91
  swapResult = options.swapQuote;
91
92
  } else {
92
93
  // Create the swap quote using the provided options (InlineSendSwapTransactionOptions)
94
+ /**
95
+ * Deterministically derive a new idempotency key from the provided idempotency key for swap quote creation to avoid key reuse.
96
+ */
97
+ const swapQuoteIdempotencyKey = idempotencyKey
98
+ ? createDeterministicUuidV4(idempotencyKey, "createSwapQuote")
99
+ : undefined;
100
+
93
101
  swapResult = await createSwapQuote(client, {
94
102
  network: options.network as CreateSwapQuoteOptions["network"],
95
103
  toToken: options.toToken,
@@ -99,6 +107,7 @@ export async function sendSwapTransaction(
99
107
  signerAddress: options.signerAddress,
100
108
  gasPrice: options.gasPrice,
101
109
  slippageBps: options.slippageBps,
110
+ idempotencyKey: swapQuoteIdempotencyKey,
102
111
  });
103
112
  }
104
113
 
@@ -128,7 +137,14 @@ export async function sendSwapTransaction(
128
137
  let txData = swap.transaction.data as Hex;
129
138
 
130
139
  if (swap.permit2?.eip712) {
131
- // Sign the Permit2 EIP-712 message
140
+ /**
141
+ * Sign the Permit2 EIP-712 message.
142
+ * Deterministically derive a new idempotency key from the provided idempotency key for permit2 signing to avoid key reuse.
143
+ */
144
+ const permit2IdempotencyKey = idempotencyKey
145
+ ? createDeterministicUuidV4(idempotencyKey, "permit2")
146
+ : undefined;
147
+
132
148
  const signature = await client.signEvmTypedData(
133
149
  address,
134
150
  {
@@ -137,7 +153,7 @@ export async function sendSwapTransaction(
137
153
  primaryType: swap.permit2.eip712.primaryType,
138
154
  message: swap.permit2.eip712.message,
139
155
  },
140
- idempotencyKey,
156
+ permit2IdempotencyKey,
141
157
  );
142
158
 
143
159
  // Calculate the signature length as a 32-byte hex value
@@ -1,9 +1,14 @@
1
+ import type { EvmSmartAccount } from "../../../accounts/evm/types.js";
1
2
  import type {
2
3
  CreateSwapQuoteOptions,
3
4
  CreateSwapQuoteResult,
4
5
  SwapUnavailableResult,
5
6
  } from "../../../client/evm/evm.types.js";
6
- import type { SendEvmTransactionBodyNetwork } from "../../../openapi-client/index.js";
7
+ import type {
8
+ SendEvmTransactionBodyNetwork,
9
+ EvmUserOperationNetwork,
10
+ EvmUserOperationStatus,
11
+ } from "../../../openapi-client/index.js";
7
12
  import type { Address, Hex } from "../../../types/misc.js";
8
13
 
9
14
  /**
@@ -76,12 +81,12 @@ export interface SendSwapTransactionResult {
76
81
  /**
77
82
  * Options for creating a swap quote (account-level).
78
83
  */
79
- export type QuoteSwapOptions = Omit<CreateSwapQuoteOptions, "taker">;
84
+ export type AccountQuoteSwapOptions = Omit<CreateSwapQuoteOptions, "taker">;
80
85
 
81
86
  /**
82
87
  * Result of creating a swap quote (account-level).
83
88
  */
84
- export type QuoteSwapResult = CreateSwapQuoteResult | SwapUnavailableResult;
89
+ export type AccountQuoteSwapResult = CreateSwapQuoteResult | SwapUnavailableResult;
85
90
 
86
91
  /**
87
92
  * Options when providing an already created swap quote (account-level).
@@ -129,9 +134,153 @@ interface AccountInlineSwapOptions {
129
134
  * Options for executing a token swap (account-level).
130
135
  * The taker is automatically set to the account's address.
131
136
  */
132
- export type SwapOptions = AccountQuoteBasedSwapOptions | AccountInlineSwapOptions;
137
+ export type AccountSwapOptions = AccountQuoteBasedSwapOptions | AccountInlineSwapOptions;
133
138
 
134
139
  /**
135
140
  * Result of executing a token swap (account-level).
136
141
  */
137
- export type SwapResult = SendSwapTransactionResult;
142
+ export type AccountSwapResult = SendSwapTransactionResult;
143
+
144
+ /**
145
+ * Options for creating a swap quote (smart account-level).
146
+ */
147
+ export type SmartAccountQuoteSwapOptions = Omit<CreateSwapQuoteOptions, "taker">;
148
+
149
+ /**
150
+ * Result of creating a swap quote (smart account-level).
151
+ */
152
+ export type SmartAccountQuoteSwapResult = CreateSwapQuoteResult | SwapUnavailableResult;
153
+
154
+ /**
155
+ * Options when providing an already created swap quote (smart account-level).
156
+ */
157
+ interface SmartAccountQuoteBasedSwapOptions {
158
+ /**
159
+ * The swap quote returned by the createSwapQuote method.
160
+ */
161
+ swapQuote: CreateSwapQuoteResult;
162
+
163
+ /**
164
+ * Optional URL of the paymaster service to use for gas sponsorship.
165
+ */
166
+ paymasterUrl?: string;
167
+
168
+ /**
169
+ * Optional idempotency key for the request.
170
+ */
171
+ idempotencyKey?: string;
172
+ }
173
+
174
+ /**
175
+ * Options when creating a swap quote inline (smart account-level).
176
+ */
177
+ interface SmartAccountInlineSwapOptions {
178
+ /**
179
+ * The network to execute the swap on (e.g., "ethereum", "base").
180
+ */
181
+ network: SendEvmTransactionBodyNetwork;
182
+ /** The token to receive (destination token). */
183
+ toToken: Address;
184
+ /** The token to send (source token). */
185
+ fromToken: Address;
186
+ /** The amount to send in atomic units of the token. */
187
+ fromAmount: bigint;
188
+ /** The signer address (only needed if taker is a smart contract). */
189
+ signerAddress?: Address;
190
+ /** The gas price in Wei. */
191
+ gasPrice?: bigint;
192
+ /** The slippage tolerance in basis points (0-10000). */
193
+ slippageBps?: number;
194
+
195
+ /**
196
+ * Optional URL of the paymaster service to use for gas sponsorship.
197
+ */
198
+ paymasterUrl?: string;
199
+
200
+ /**
201
+ * Optional idempotency key for the request.
202
+ */
203
+ idempotencyKey?: string;
204
+ }
205
+
206
+ /**
207
+ * Options for executing a token swap (smart account-level).
208
+ * The taker is automatically set to the smart account's address.
209
+ */
210
+ export type SmartAccountSwapOptions =
211
+ | SmartAccountQuoteBasedSwapOptions
212
+ | SmartAccountInlineSwapOptions;
213
+
214
+ /**
215
+ * Result of executing a token swap (smart account-level).
216
+ */
217
+ export type SmartAccountSwapResult = {
218
+ /** The address of the smart wallet. */
219
+ smartAccountAddress: Address;
220
+ /** The status of the user operation. */
221
+ status: string;
222
+ /** The hash of the user operation. */
223
+ userOpHash: Hex;
224
+ };
225
+
226
+ /**
227
+ * Base options for sending a swap operation via smart account.
228
+ */
229
+ interface BaseSendSwapOperationOptions {
230
+ /** The smart account that will execute the swap. */
231
+ smartAccount: EvmSmartAccount;
232
+ /** Optional URL of the paymaster service to use for gas sponsorship. */
233
+ paymasterUrl?: string;
234
+ /** Optional idempotency key for the request. */
235
+ idempotencyKey?: string;
236
+ }
237
+
238
+ /**
239
+ * Options when providing an already created swap quote (for sendSwapOperation).
240
+ */
241
+ interface QuoteBasedSendSwapOperationOptions extends BaseSendSwapOperationOptions {
242
+ /** The swap quote returned by the createSwapQuote method. */
243
+ swapQuote: CreateSwapQuoteResult;
244
+ }
245
+
246
+ /**
247
+ * Options when creating a swap quote inline (for sendSwapOperation).
248
+ */
249
+ interface InlineSendSwapOperationOptions extends BaseSendSwapOperationOptions {
250
+ /** The network to execute the swap on. */
251
+ network: EvmUserOperationNetwork;
252
+ /** The token to receive (destination token). */
253
+ toToken: Address;
254
+ /** The token to send (source token). */
255
+ fromToken: Address;
256
+ /** The amount to send in atomic units of the token. */
257
+ fromAmount: bigint;
258
+ /** The address that will perform the swap. */
259
+ taker: Address;
260
+ /** The signer address (required since taker is a smart contract). */
261
+ signerAddress: Address;
262
+ /** The gas price in Wei. */
263
+ gasPrice?: bigint;
264
+ /** The slippage tolerance in basis points (0-10000). */
265
+ slippageBps?: number;
266
+ }
267
+
268
+ /**
269
+ * Options for sending a swap operation via smart account.
270
+ * Either provide a pre-created swap quote result or inline swap parameters.
271
+ */
272
+ export type SendSwapOperationOptions =
273
+ | QuoteBasedSendSwapOperationOptions
274
+ | InlineSendSwapOperationOptions;
275
+
276
+ /**
277
+ * Result of sending a swap operation via smart account.
278
+ */
279
+ export type SendSwapOperationResult = {
280
+ /** The address of the smart wallet. */
281
+ smartAccountAddress: Address;
282
+ /** The status of the user operation. */
283
+ status: typeof EvmUserOperationStatus.broadcast;
284
+ /** The hash of the user operation. */
285
+ userOpHash: Hex;
286
+ };
@@ -13,7 +13,16 @@ import { Hex } from "../../types/misc.js";
13
13
  import type { ListTokenBalancesOptions, ListTokenBalancesResult } from "./listTokenBalances.js";
14
14
  import type { RequestFaucetOptions, RequestFaucetResult } from "./requestFaucet.js";
15
15
  import type { SendTransactionOptions, TransactionResult } from "./sendTransaction.js";
16
- import type { SwapOptions, SwapResult, QuoteSwapOptions, QuoteSwapResult } from "./swap/types.js";
16
+ import type {
17
+ AccountSwapOptions,
18
+ AccountSwapResult,
19
+ AccountQuoteSwapOptions,
20
+ AccountQuoteSwapResult,
21
+ SmartAccountSwapOptions,
22
+ SmartAccountSwapResult,
23
+ SmartAccountQuoteSwapOptions,
24
+ SmartAccountQuoteSwapResult,
25
+ } from "./swap/types.js";
17
26
  import type { TransferOptions } from "./transfer/types.js";
18
27
  import type {
19
28
  WaitForUserOperationOptions,
@@ -256,11 +265,11 @@ export type AccountActions = Actions & {
256
265
  * This is useful when you need to get swap details before executing the swap.
257
266
  * The taker is automatically set to the account's address.
258
267
  *
259
- * @param {QuoteSwapOptions} options - Configuration options for creating the swap quote.
268
+ * @param {AccountQuoteSwapOptions} options - Configuration options for creating the swap quote.
260
269
  * @param {string} options.network - The network to create the quote on
261
- * @param {string} options.fromToken - The token address to sell
262
- * @param {string} options.toToken - The token address to buy
263
- * @param {bigint} options.fromAmount - The amount of fromToken to sell
270
+ * @param {string} options.fromToken - The token address to send
271
+ * @param {string} options.toToken - The token address to receive
272
+ * @param {bigint} options.fromAmount - The amount of fromToken to send
264
273
  * @param {string} [options.signerAddress] - The signer address (only needed if taker is a smart contract)
265
274
  * @param {bigint} [options.gasPrice] - The gas price in Wei
266
275
  * @param {number} [options.slippageBps] - The slippage tolerance in basis points (0-10000)
@@ -281,30 +290,33 @@ export type AccountActions = Actions & {
281
290
  * }
282
291
  * ```
283
292
  */
284
- quoteSwap: (options: QuoteSwapOptions) => Promise<QuoteSwapResult>;
293
+ quoteSwap: (options: AccountQuoteSwapOptions) => Promise<AccountQuoteSwapResult>;
285
294
 
286
295
  /**
287
296
  * Executes a token swap on the specified network.
288
297
  * This method handles all the steps required for a swap, including Permit2 signatures if needed.
298
+ * The taker is automatically set to the account's address.
289
299
  *
290
- * @param {SwapOptions} options - Configuration options for the swap.
291
- * @param {string} [options.network] - The network to execute the swap on
292
- * @param {CreateSwapQuoteResult} [options.swapQuote] - The swap quote returned by the createSwapQuote method.
293
- * @param {CreateSwapQuoteOptions} [options.swapOptions] - Options to create a swap quote. The function will call createSwapQuote internally.
294
- * @param {string} [options.idempotencyKey] - Optional idempotency key for the request.
300
+ * @param {AccountSwapOptions} options - Configuration options for the swap.
301
+ * @param {string} [options.network] - The network to execute the swap on (required for inline swaps)
302
+ * @param {CreateSwapQuoteResult} [options.swapQuote] - The swap quote returned by the createSwapQuote method
303
+ * @param {string} [options.fromToken] - The token address to send (required for inline swaps)
304
+ * @param {string} [options.toToken] - The token address to receive (required for inline swaps)
305
+ * @param {bigint} [options.fromAmount] - The amount of fromToken to send (required for inline swaps)
306
+ * @param {string} [options.idempotencyKey] - Optional idempotency key for the request
295
307
  *
296
308
  * @returns A promise that resolves to the transaction hash.
297
309
  *
298
- * @throws {Error} If liquidity is not available when using swapOptions.
310
+ * @throws {Error} If liquidity is not available when using inline options.
299
311
  *
300
312
  * @example **Using a pre-created swap quote**
301
313
  * ```ts
302
314
  * // First create a swap quote
303
315
  * const swapQuote = await cdp.evm.createSwapQuote({
304
316
  * network: "base",
305
- * buyToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
306
- * sellToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
307
- * sellAmount: BigInt("1000000000000000000"), // 1 WETH in wei
317
+ * toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
318
+ * fromToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
319
+ * fromAmount: BigInt("1000000000000000000"), // 1 WETH in wei
308
320
  * taker: account.address
309
321
  * });
310
322
  *
@@ -322,21 +334,20 @@ export type AccountActions = Actions & {
322
334
  * console.log(`Swap executed with transaction hash: ${transactionHash}`);
323
335
  * ```
324
336
  *
325
- * @example **Using swap options (all-in-one)**
337
+ * @example **Using inline options (all-in-one)**
326
338
  * ```ts
327
339
  * // Create and execute swap in one call
328
340
  * const { transactionHash } = await account.swap({
329
341
  * network: "base",
330
- * buyToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
331
- * sellToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
332
- * sellAmount: BigInt("1000000000000000000"), // 1 WETH in wei
333
- * taker: account.address
342
+ * toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
343
+ * fromToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
344
+ * fromAmount: BigInt("1000000000000000000"), // 1 WETH in wei
334
345
  * });
335
346
  *
336
347
  * console.log(`Swap executed with transaction hash: ${transactionHash}`);
337
348
  * ```
338
349
  */
339
- swap: (options: SwapOptions) => Promise<SwapResult>;
350
+ swap: (options: AccountSwapOptions) => Promise<AccountSwapResult>;
340
351
  };
341
352
 
342
353
  export type SmartAccountActions = Actions & {
@@ -499,4 +510,95 @@ export type SmartAccountActions = Actions & {
499
510
  getUserOperation: (
500
511
  options: Omit<GetUserOperationOptions, "smartAccount">,
501
512
  ) => Promise<UserOperation>;
513
+
514
+ /**
515
+ * Creates a swap quote without executing the transaction.
516
+ * This is useful when you need to get swap details before executing the swap.
517
+ * The taker is automatically set to the smart account's address.
518
+ *
519
+ * @param {SmartAccountQuoteSwapOptions} options - Configuration options for creating the swap quote.
520
+ * @param {string} options.network - The network to create the quote on
521
+ * @param {string} options.fromToken - The token address to send
522
+ * @param {string} options.toToken - The token address to receive
523
+ * @param {bigint} options.fromAmount - The amount of fromToken to send
524
+ * @param {string} [options.signerAddress] - The signer address (only needed if taker is a smart contract)
525
+ * @param {bigint} [options.gasPrice] - The gas price in Wei
526
+ * @param {number} [options.slippageBps] - The slippage tolerance in basis points (0-10000)
527
+ *
528
+ * @returns A promise that resolves to the swap quote or a response indicating that liquidity is unavailable.
529
+ *
530
+ * @example
531
+ * ```ts
532
+ * const swapQuote = await smartAccount.quoteSwap({
533
+ * network: "base",
534
+ * fromToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
535
+ * toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
536
+ * fromAmount: BigInt("1000000000000000000"), // 1 WETH in wei
537
+ * });
538
+ *
539
+ * if (swapQuote.liquidityAvailable) {
540
+ * console.log(`Can swap for ${swapQuote.toAmount} USDC`);
541
+ * }
542
+ * ```
543
+ */
544
+ quoteSwap: (options: SmartAccountQuoteSwapOptions) => Promise<SmartAccountQuoteSwapResult>;
545
+
546
+ /**
547
+ * Executes a token swap on the specified network via a user operation.
548
+ * This method handles all the steps required for a swap, including Permit2 signatures if needed.
549
+ * The taker is automatically set to the smart account's address.
550
+ *
551
+ * @param {SmartAccountSwapOptions} options - Configuration options for the swap.
552
+ * @param {string} [options.network] - The network to execute the swap on (required for inline swaps)
553
+ * @param {CreateSwapQuoteResult} [options.swapQuote] - The swap quote returned by the createSwapQuote method
554
+ * @param {string} [options.fromToken] - The token address to send (required for inline swaps)
555
+ * @param {string} [options.toToken] - The token address to receive (required for inline swaps)
556
+ * @param {bigint} [options.fromAmount] - The amount of fromToken to send (required for inline swaps)
557
+ * @param {string} [options.paymasterUrl] - Optional paymaster URL for gas sponsorship
558
+ * @param {string} [options.idempotencyKey] - Optional idempotency key for the request
559
+ *
560
+ * @returns A promise that resolves to the user operation result.
561
+ *
562
+ * @throws {Error} If liquidity is not available when using inline options.
563
+ *
564
+ * @example **Using a pre-created swap quote**
565
+ * ```ts
566
+ * // First create a swap quote
567
+ * const swapQuote = await cdp.evm.createSwapQuote({
568
+ * network: "base",
569
+ * toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
570
+ * fromToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
571
+ * fromAmount: BigInt("1000000000000000000"), // 1 WETH in wei
572
+ * taker: smartAccount.address,
573
+ * signerAddress: smartAccount.owners[0].address
574
+ * });
575
+ *
576
+ * // Check if liquidity is available
577
+ * if (!swapQuote.liquidityAvailable) {
578
+ * console.error("Insufficient liquidity for swap");
579
+ * return;
580
+ * }
581
+ *
582
+ * // Execute the swap
583
+ * const { userOpHash } = await smartAccount.swap({
584
+ * swapQuote: swapQuote
585
+ * });
586
+ *
587
+ * console.log(`Swap executed with user op hash: ${userOpHash}`);
588
+ * ```
589
+ *
590
+ * @example **Using inline options (all-in-one)**
591
+ * ```ts
592
+ * // Create and execute swap in one call
593
+ * const { userOpHash } = await smartAccount.swap({
594
+ * network: "base",
595
+ * toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
596
+ * fromToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
597
+ * fromAmount: BigInt("1000000000000000000"), // 1 WETH in wei
598
+ * });
599
+ *
600
+ * console.log(`Swap executed with user op hash: ${userOpHash}`);
601
+ * ```
602
+ */
603
+ swap: (options: SmartAccountSwapOptions) => Promise<SmartAccountSwapResult>;
502
604
  };
package/client/evm/evm.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { constants, publicEncrypt } from "crypto";
2
2
 
3
- import { Address } from "viem";
3
+ import { type Address, getTypesForEIP712Domain } from "viem";
4
4
 
5
5
  import { ImportEvmAccountPublicRSAKey } from "./constants.js";
6
6
  import {
@@ -62,7 +62,10 @@ import {
62
62
  } from "../../actions/evm/waitForUserOperation.js";
63
63
  import { Analytics } from "../../analytics.js";
64
64
  import { APIError } from "../../openapi-client/errors.js";
65
- import { CdpOpenApiClient } from "../../openapi-client/index.js";
65
+ import {
66
+ CdpOpenApiClient,
67
+ EIP712Message as OpenAPIEIP712Message,
68
+ } from "../../openapi-client/index.js";
66
69
  import { Hex } from "../../types/misc.js";
67
70
  import { decryptWithPrivateKey, generateExportEncryptionKeyPair } from "../../utils/export.js";
68
71
 
@@ -978,14 +981,22 @@ export class EvmClient implements EvmClientInterface {
978
981
  * ```
979
982
  */
980
983
  async signTypedData(options: SignTypedDataOptions): Promise<SignatureResult> {
984
+ const { domain, message, primaryType } = options;
985
+ const types = {
986
+ EIP712Domain: getTypesForEIP712Domain({ domain }),
987
+ ...options.types,
988
+ };
989
+
990
+ const openApiMessage: OpenAPIEIP712Message = {
991
+ domain,
992
+ types,
993
+ primaryType,
994
+ message,
995
+ };
996
+
981
997
  const signature = await CdpOpenApiClient.signEvmTypedData(
982
998
  options.address,
983
- {
984
- domain: options.domain,
985
- types: options.types,
986
- primaryType: options.primaryType,
987
- message: options.message,
988
- },
999
+ openApiMessage,
989
1000
  options.idempotencyKey,
990
1001
  );
991
1002