@coinbase/cdp-sdk 1.10.0 → 1.12.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.
- package/CHANGELOG.md +14 -0
- package/README.md +137 -0
- package/_cjs/accounts/evm/toEvmServerAccount.js +32 -0
- package/_cjs/accounts/evm/toEvmServerAccount.js.map +1 -1
- package/_cjs/accounts/evm/toEvmSmartAccount.js +18 -0
- package/_cjs/accounts/evm/toEvmSmartAccount.js.map +1 -1
- package/_cjs/actions/evm/fund/Quote.js +63 -0
- package/_cjs/actions/evm/fund/Quote.js.map +1 -0
- package/_cjs/actions/evm/fund/fund.js +49 -0
- package/_cjs/actions/evm/fund/fund.js.map +1 -0
- package/_cjs/actions/evm/fund/quoteFund.js +46 -0
- package/_cjs/actions/evm/fund/quoteFund.js.map +1 -0
- package/_cjs/actions/evm/fund/types.js +3 -0
- package/_cjs/actions/evm/fund/types.js.map +1 -0
- package/_cjs/actions/evm/fund/waitForFundOperationReceipt.js +64 -0
- package/_cjs/actions/evm/fund/waitForFundOperationReceipt.js.map +1 -0
- package/_cjs/actions/evm/swap/createSwapQuote.js +126 -0
- package/_cjs/actions/evm/swap/createSwapQuote.js.map +1 -0
- package/_cjs/actions/evm/swap/getSwapPrice.js +86 -0
- package/_cjs/actions/evm/swap/getSwapPrice.js.map +1 -0
- package/_cjs/actions/evm/swap/sendSwapTransaction.js +141 -0
- package/_cjs/actions/evm/swap/sendSwapTransaction.js.map +1 -0
- package/_cjs/actions/evm/swap/types.js +3 -0
- package/_cjs/actions/evm/swap/types.js.map +1 -0
- package/_cjs/client/evm/evm.js +47 -1
- package/_cjs/client/evm/evm.js.map +1 -1
- package/_cjs/client/solana/solana.js +4 -1
- package/_cjs/client/solana/solana.js.map +1 -1
- package/_cjs/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js +45 -1
- package/_cjs/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js.map +1 -1
- package/_cjs/openapi-client/generated/evm-swaps/evm-swaps.js +26 -0
- package/_cjs/openapi-client/generated/evm-swaps/evm-swaps.js.map +1 -0
- package/_cjs/openapi-client/generated/evm-swaps/evm-swaps.msw.js +179 -0
- package/_cjs/openapi-client/generated/evm-swaps/evm-swaps.msw.js.map +1 -0
- package/_cjs/openapi-client/generated/index.msw.js +5 -3
- package/_cjs/openapi-client/generated/index.msw.js.map +1 -1
- package/_cjs/openapi-client/generated/payments-alpha/payments-alpha.js +50 -0
- package/_cjs/openapi-client/generated/payments-alpha/payments-alpha.js.map +1 -0
- package/_cjs/openapi-client/generated/payments-alpha/payments-alpha.msw.js +270 -0
- package/_cjs/openapi-client/generated/payments-alpha/payments-alpha.msw.js.map +1 -0
- package/_cjs/openapi-client/index.js +7 -0
- package/_cjs/openapi-client/index.js.map +1 -1
- package/_cjs/version.js +1 -1
- package/_esm/accounts/evm/toEvmServerAccount.js +32 -0
- package/_esm/accounts/evm/toEvmServerAccount.js.map +1 -1
- package/_esm/accounts/evm/toEvmSmartAccount.js +18 -0
- package/_esm/accounts/evm/toEvmSmartAccount.js.map +1 -1
- package/_esm/actions/evm/fund/Quote.js +59 -0
- package/_esm/actions/evm/fund/Quote.js.map +1 -0
- package/_esm/actions/evm/fund/fund.js +46 -0
- package/_esm/actions/evm/fund/fund.js.map +1 -0
- package/_esm/actions/evm/fund/quoteFund.js +43 -0
- package/_esm/actions/evm/fund/quoteFund.js.map +1 -0
- package/_esm/actions/evm/fund/types.js +2 -0
- package/_esm/actions/evm/fund/types.js.map +1 -0
- package/_esm/actions/evm/fund/waitForFundOperationReceipt.js +61 -0
- package/_esm/actions/evm/fund/waitForFundOperationReceipt.js.map +1 -0
- package/_esm/actions/evm/swap/createSwapQuote.js +123 -0
- package/_esm/actions/evm/swap/createSwapQuote.js.map +1 -0
- package/_esm/actions/evm/swap/getSwapPrice.js +83 -0
- package/_esm/actions/evm/swap/getSwapPrice.js.map +1 -0
- package/_esm/actions/evm/swap/sendSwapTransaction.js +138 -0
- package/_esm/actions/evm/swap/sendSwapTransaction.js.map +1 -0
- package/_esm/actions/evm/swap/types.js +2 -0
- package/_esm/actions/evm/swap/types.js.map +1 -0
- package/_esm/client/evm/evm.js +47 -1
- package/_esm/client/evm/evm.js.map +1 -1
- package/_esm/client/solana/solana.js +4 -1
- package/_esm/client/solana/solana.js.map +1 -1
- package/_esm/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js +44 -0
- package/_esm/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.js.map +1 -1
- package/_esm/openapi-client/generated/evm-swaps/evm-swaps.js +21 -0
- package/_esm/openapi-client/generated/evm-swaps/evm-swaps.js.map +1 -0
- package/_esm/openapi-client/generated/evm-swaps/evm-swaps.msw.js +167 -0
- package/_esm/openapi-client/generated/evm-swaps/evm-swaps.msw.js.map +1 -0
- package/_esm/openapi-client/generated/index.msw.js +5 -3
- package/_esm/openapi-client/generated/index.msw.js.map +1 -1
- package/_esm/openapi-client/generated/payments-alpha/payments-alpha.js +42 -0
- package/_esm/openapi-client/generated/payments-alpha/payments-alpha.js.map +1 -0
- package/_esm/openapi-client/generated/payments-alpha/payments-alpha.msw.js +250 -0
- package/_esm/openapi-client/generated/payments-alpha/payments-alpha.msw.js.map +1 -0
- package/_esm/openapi-client/index.js +7 -0
- package/_esm/openapi-client/index.js.map +1 -1
- package/_esm/version.js +1 -1
- package/_types/accounts/evm/toEvmServerAccount.d.ts.map +1 -1
- package/_types/accounts/evm/toEvmSmartAccount.d.ts.map +1 -1
- package/_types/accounts/evm/types.d.ts +1 -2
- package/_types/accounts/evm/types.d.ts.map +1 -1
- package/_types/actions/evm/fund/Quote.d.ts +51 -0
- package/_types/actions/evm/fund/Quote.d.ts.map +1 -0
- package/_types/actions/evm/fund/fund.d.ts +25 -0
- package/_types/actions/evm/fund/fund.d.ts.map +1 -0
- package/_types/actions/evm/fund/quoteFund.d.ts +25 -0
- package/_types/actions/evm/fund/quoteFund.d.ts.map +1 -0
- package/_types/actions/evm/fund/types.d.ts +16 -0
- package/_types/actions/evm/fund/types.d.ts.map +1 -0
- package/_types/actions/evm/fund/waitForFundOperationReceipt.d.ts +68 -0
- package/_types/actions/evm/fund/waitForFundOperationReceipt.d.ts.map +1 -0
- package/_types/actions/evm/swap/createSwapQuote.d.ts +23 -0
- package/_types/actions/evm/swap/createSwapQuote.d.ts.map +1 -0
- package/_types/actions/evm/swap/getSwapPrice.d.ts +23 -0
- package/_types/actions/evm/swap/getSwapPrice.d.ts.map +1 -0
- package/_types/actions/evm/swap/sendSwapTransaction.d.ts +64 -0
- package/_types/actions/evm/swap/sendSwapTransaction.d.ts.map +1 -0
- package/_types/actions/evm/swap/types.d.ts +80 -0
- package/_types/actions/evm/swap/types.d.ts.map +1 -0
- package/_types/actions/evm/types.d.ts +151 -0
- package/_types/actions/evm/types.d.ts.map +1 -1
- package/_types/client/evm/evm.d.ts +39 -1
- package/_types/client/evm/evm.d.ts.map +1 -1
- package/_types/client/evm/evm.types.d.ts +209 -3
- package/_types/client/evm/evm.types.d.ts.map +1 -1
- package/_types/client/solana/solana.d.ts.map +1 -1
- package/_types/client/solana/solana.types.d.ts +2 -0
- package/_types/client/solana/solana.types.d.ts.map +1 -1
- package/_types/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.d.ts +547 -3
- package/_types/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.d.ts.map +1 -1
- package/_types/openapi-client/generated/evm-swaps/evm-swaps.d.ts +24 -0
- package/_types/openapi-client/generated/evm-swaps/evm-swaps.d.ts.map +1 -0
- package/_types/openapi-client/generated/evm-swaps/evm-swaps.msw.d.ts +12 -0
- package/_types/openapi-client/generated/evm-swaps/evm-swaps.msw.d.ts.map +1 -0
- package/_types/openapi-client/generated/index.msw.d.ts +5 -3
- package/_types/openapi-client/generated/index.msw.d.ts.map +1 -1
- package/_types/openapi-client/generated/payments-alpha/payments-alpha.d.ts +42 -0
- package/_types/openapi-client/generated/payments-alpha/payments-alpha.d.ts.map +1 -0
- package/_types/openapi-client/generated/payments-alpha/payments-alpha.msw.d.ts +20 -0
- package/_types/openapi-client/generated/payments-alpha/payments-alpha.msw.d.ts.map +1 -0
- package/_types/openapi-client/index.d.ts +11 -0
- package/_types/openapi-client/index.d.ts.map +1 -1
- package/_types/types/misc.d.ts +2 -2
- package/_types/types/misc.d.ts.map +1 -1
- package/_types/version.d.ts +1 -1
- package/accounts/evm/toEvmServerAccount.ts +47 -0
- package/accounts/evm/toEvmSmartAccount.ts +26 -0
- package/accounts/evm/types.ts +1 -2
- package/actions/evm/fund/Quote.ts +83 -0
- package/actions/evm/fund/fund.ts +76 -0
- package/actions/evm/fund/quoteFund.ts +81 -0
- package/actions/evm/fund/types.ts +16 -0
- package/actions/evm/fund/waitForFundOperationReceipt.ts +118 -0
- package/actions/evm/swap/createSwapQuote.ts +148 -0
- package/actions/evm/swap/getSwapPrice.ts +95 -0
- package/actions/evm/swap/sendSwapTransaction.ts +173 -0
- package/actions/evm/swap/types.ts +94 -0
- package/actions/evm/types.ts +161 -0
- package/client/evm/evm.ts +59 -1
- package/client/evm/evm.types.ts +227 -1
- package/client/solana/solana.ts +4 -1
- package/client/solana/solana.types.ts +2 -0
- package/openapi-client/generated/coinbaseDeveloperPlatformAPIs.schemas.ts +617 -3
- package/openapi-client/generated/evm-swaps/evm-swaps.msw.ts +217 -0
- package/openapi-client/generated/evm-swaps/evm-swaps.ts +51 -0
- package/openapi-client/generated/index.msw.ts +5 -3
- package/openapi-client/generated/payments-alpha/payments-alpha.msw.ts +369 -0
- package/openapi-client/generated/payments-alpha/payments-alpha.ts +96 -0
- package/openapi-client/index.ts +7 -0
- package/package.json +1 -1
- package/types/misc.ts +2 -2
- package/version.ts +1 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { CdpOpenApiClientType, Transfer, TransferStatus } from "../../../openapi-client/index.js";
|
|
2
|
+
import { wait, WaitOptions } from "../../../utils/wait.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Options for waiting for a fund operation.
|
|
6
|
+
*/
|
|
7
|
+
export type WaitForFundOperationOptions = {
|
|
8
|
+
/** The ID of the transfer to wait for. */
|
|
9
|
+
transferId: string;
|
|
10
|
+
/** Optional options for the wait operation. */
|
|
11
|
+
waitOptions?: WaitOptions;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Represents a failed fund operation.
|
|
16
|
+
*/
|
|
17
|
+
export type FailedFundOperation = {
|
|
18
|
+
/** The ID of the transfer. */
|
|
19
|
+
id: string;
|
|
20
|
+
/** The network that the transfer was created on. */
|
|
21
|
+
network: string;
|
|
22
|
+
/** The target amount that will be received. */
|
|
23
|
+
targetAmount: string;
|
|
24
|
+
/** The currency that will be received. */
|
|
25
|
+
targetCurrency: string;
|
|
26
|
+
/** The status of the transfer. */
|
|
27
|
+
status: typeof TransferStatus.failed;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Represents a completed fund operation.
|
|
32
|
+
*/
|
|
33
|
+
export type CompletedFundOperation = {
|
|
34
|
+
/** The ID of the transfer. */
|
|
35
|
+
id: string;
|
|
36
|
+
/** The network that the transfer was created on. */
|
|
37
|
+
network: string;
|
|
38
|
+
/** The target amount that will be received. */
|
|
39
|
+
targetAmount: string;
|
|
40
|
+
/** The currency that will be received. */
|
|
41
|
+
targetCurrency: string;
|
|
42
|
+
/** The status of the transfer. */
|
|
43
|
+
status: typeof TransferStatus.completed;
|
|
44
|
+
/** The transaction hash of the transfer. */
|
|
45
|
+
transactionHash: string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Represents the return type of the waitForFundOperation function.
|
|
50
|
+
*/
|
|
51
|
+
export type WaitForFundOperationResult = FailedFundOperation | CompletedFundOperation;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Waits for a fund operation to complete or fail.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* import { waitForFundOperation } from "@coinbase/cdp-sdk";
|
|
59
|
+
*
|
|
60
|
+
* const result = await waitForFundOperation(client, {
|
|
61
|
+
* transferId: "0x1234567890123456789012345678901234567890",
|
|
62
|
+
* waitOptions: {
|
|
63
|
+
* timeoutSeconds: 30,
|
|
64
|
+
* },
|
|
65
|
+
* });
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @param {CdpOpenApiClientType} client - The client to use to wait for the fund operation.
|
|
69
|
+
* @param {WaitForFundOperationOptions} options - The options for the wait operation.
|
|
70
|
+
* @returns {Promise<WaitForFundOperationResult>} The result of the fund operation.
|
|
71
|
+
*/
|
|
72
|
+
export async function waitForFundOperationReceipt(
|
|
73
|
+
client: CdpOpenApiClientType,
|
|
74
|
+
options: WaitForFundOperationOptions,
|
|
75
|
+
): Promise<WaitForFundOperationResult> {
|
|
76
|
+
const { transferId } = options;
|
|
77
|
+
|
|
78
|
+
const reload = async () => {
|
|
79
|
+
const response = await client.getPaymentTransfer(transferId);
|
|
80
|
+
return response;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const transform = (operation: Transfer): WaitForFundOperationResult => {
|
|
84
|
+
if (operation.status === TransferStatus.failed) {
|
|
85
|
+
return {
|
|
86
|
+
id: operation.id,
|
|
87
|
+
network: operation.target.network,
|
|
88
|
+
targetAmount: operation.targetAmount,
|
|
89
|
+
targetCurrency: operation.targetCurrency,
|
|
90
|
+
status: operation.status,
|
|
91
|
+
} satisfies FailedFundOperation;
|
|
92
|
+
} else if (operation.status === TransferStatus.completed) {
|
|
93
|
+
return {
|
|
94
|
+
id: operation.id,
|
|
95
|
+
network: operation.target.network,
|
|
96
|
+
targetAmount: operation.targetAmount,
|
|
97
|
+
targetCurrency: operation.targetCurrency,
|
|
98
|
+
status: operation.status,
|
|
99
|
+
transactionHash: operation.transactionHash!,
|
|
100
|
+
} satisfies CompletedFundOperation;
|
|
101
|
+
} else {
|
|
102
|
+
throw new Error("Transfer is not terminal");
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const waitOptions = options.waitOptions || {
|
|
107
|
+
timeoutSeconds: 900,
|
|
108
|
+
intervalSeconds: 1,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
return await wait(reload, isTerminal, transform, waitOptions);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const isTerminal = (operation: Transfer): boolean => {
|
|
115
|
+
return (
|
|
116
|
+
operation.status === TransferStatus.completed || operation.status === TransferStatus.failed
|
|
117
|
+
);
|
|
118
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { sendSwapTransaction } from "./sendSwapTransaction.js";
|
|
2
|
+
import {
|
|
3
|
+
CreateSwapQuoteOptions,
|
|
4
|
+
CreateSwapQuoteResult,
|
|
5
|
+
ExecuteSwapQuoteOptions,
|
|
6
|
+
ExecuteSwapQuoteResult,
|
|
7
|
+
SwapUnavailableResult,
|
|
8
|
+
} from "../../../client/evm/evm.types.js";
|
|
9
|
+
import {
|
|
10
|
+
CdpOpenApiClientType,
|
|
11
|
+
CreateSwapQuoteResponse,
|
|
12
|
+
type SendEvmTransactionBodyNetwork,
|
|
13
|
+
} from "../../../openapi-client/index.js";
|
|
14
|
+
import { Address, Hex } from "../../../types/misc.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a quote for a swap between two tokens on an EVM network.
|
|
18
|
+
*
|
|
19
|
+
* @param {CdpOpenApiClientType} client - The client to use to create the swap quote.
|
|
20
|
+
* @param {CreateSwapQuoteOptions} options - The options for creating a swap quote.
|
|
21
|
+
*
|
|
22
|
+
* @returns {Promise<CreateSwapQuoteResult | SwapUnavailableResult>} A promise that resolves to the swap quote result or a response indicating that liquidity is unavailable.
|
|
23
|
+
*
|
|
24
|
+
* @example **Creating a swap quote**
|
|
25
|
+
* ```ts
|
|
26
|
+
* const swapQuote = await createSwapQuote(client, {
|
|
27
|
+
* network: "ethereum",
|
|
28
|
+
* toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
|
29
|
+
* fromToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
|
|
30
|
+
* fromAmount: BigInt("1000000000000000000"), // 1 WETH in wei
|
|
31
|
+
* taker: "0x1234567890123456789012345678901234567890"
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export async function createSwapQuote(
|
|
36
|
+
client: CdpOpenApiClientType,
|
|
37
|
+
options: CreateSwapQuoteOptions,
|
|
38
|
+
): Promise<CreateSwapQuoteResult | SwapUnavailableResult> {
|
|
39
|
+
// Validate required parameters
|
|
40
|
+
if (!options.taker) {
|
|
41
|
+
throw new Error("taker is required for createSwapQuote");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Store validated taker for type safety
|
|
45
|
+
const taker = options.taker as Address;
|
|
46
|
+
|
|
47
|
+
// Call the createEvmSwapQuote function directly with the client's configured API
|
|
48
|
+
const response = await client.createEvmSwapQuote({
|
|
49
|
+
network: options.network,
|
|
50
|
+
toToken: options.toToken,
|
|
51
|
+
fromToken: options.fromToken,
|
|
52
|
+
fromAmount: options.fromAmount.toString(),
|
|
53
|
+
taker: taker,
|
|
54
|
+
signerAddress: options.signerAddress,
|
|
55
|
+
gasPrice: options.gasPrice?.toString(),
|
|
56
|
+
slippageBps: options.slippageBps,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Check if liquidity is unavailable
|
|
60
|
+
if (!response.liquidityAvailable) {
|
|
61
|
+
// Return the SwapUnavailableResult
|
|
62
|
+
return {
|
|
63
|
+
liquidityAvailable: false,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// At this point we know it's a CreateSwapQuoteResponse with liquidityAvailable as true
|
|
68
|
+
const swapResponse = response as CreateSwapQuoteResponse;
|
|
69
|
+
const result: CreateSwapQuoteResult = {
|
|
70
|
+
liquidityAvailable: true,
|
|
71
|
+
network: options.network,
|
|
72
|
+
toToken: swapResponse.toToken as Address,
|
|
73
|
+
fromToken: swapResponse.fromToken as Address,
|
|
74
|
+
fromAmount: BigInt(swapResponse.fromAmount),
|
|
75
|
+
toAmount: BigInt(swapResponse.toAmount),
|
|
76
|
+
minToAmount: BigInt(swapResponse.minToAmount),
|
|
77
|
+
blockNumber: BigInt(swapResponse.blockNumber),
|
|
78
|
+
fees: {
|
|
79
|
+
gasFee: swapResponse.fees.gasFee
|
|
80
|
+
? {
|
|
81
|
+
amount: BigInt(swapResponse.fees.gasFee.amount),
|
|
82
|
+
token: swapResponse.fees.gasFee.token as Address,
|
|
83
|
+
}
|
|
84
|
+
: undefined,
|
|
85
|
+
protocolFee: swapResponse.fees.protocolFee
|
|
86
|
+
? {
|
|
87
|
+
amount: BigInt(swapResponse.fees.protocolFee.amount),
|
|
88
|
+
token: swapResponse.fees.protocolFee.token as Address,
|
|
89
|
+
}
|
|
90
|
+
: undefined,
|
|
91
|
+
},
|
|
92
|
+
issues: {
|
|
93
|
+
allowance: swapResponse.issues.allowance
|
|
94
|
+
? {
|
|
95
|
+
currentAllowance: BigInt(swapResponse.issues.allowance.currentAllowance),
|
|
96
|
+
spender: swapResponse.issues.allowance.spender as Address,
|
|
97
|
+
}
|
|
98
|
+
: undefined,
|
|
99
|
+
balance: swapResponse.issues.balance
|
|
100
|
+
? {
|
|
101
|
+
token: swapResponse.issues.balance.token as Address,
|
|
102
|
+
currentBalance: BigInt(swapResponse.issues.balance.currentBalance),
|
|
103
|
+
requiredBalance: BigInt(swapResponse.issues.balance.requiredBalance),
|
|
104
|
+
}
|
|
105
|
+
: undefined,
|
|
106
|
+
simulationIncomplete: swapResponse.issues.simulationIncomplete,
|
|
107
|
+
},
|
|
108
|
+
transaction: swapResponse.transaction
|
|
109
|
+
? {
|
|
110
|
+
to: swapResponse.transaction.to as Address,
|
|
111
|
+
data: swapResponse.transaction.data as Hex,
|
|
112
|
+
value: BigInt(swapResponse.transaction.value),
|
|
113
|
+
gas: BigInt(swapResponse.transaction.gas),
|
|
114
|
+
gasPrice: BigInt(swapResponse.transaction.gasPrice),
|
|
115
|
+
}
|
|
116
|
+
: undefined,
|
|
117
|
+
permit2: swapResponse.permit2
|
|
118
|
+
? {
|
|
119
|
+
eip712: {
|
|
120
|
+
domain: {
|
|
121
|
+
...swapResponse.permit2.eip712.domain,
|
|
122
|
+
verifyingContract: swapResponse.permit2.eip712.domain.verifyingContract as
|
|
123
|
+
| Address
|
|
124
|
+
| undefined,
|
|
125
|
+
salt: swapResponse.permit2.eip712.domain.salt as Hex | undefined,
|
|
126
|
+
},
|
|
127
|
+
types: swapResponse.permit2.eip712.types,
|
|
128
|
+
primaryType: swapResponse.permit2.eip712.primaryType,
|
|
129
|
+
message: swapResponse.permit2.eip712.message,
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
: undefined,
|
|
133
|
+
// Add the execute method
|
|
134
|
+
execute: async (
|
|
135
|
+
executeOptions: ExecuteSwapQuoteOptions = {},
|
|
136
|
+
): Promise<ExecuteSwapQuoteResult> => {
|
|
137
|
+
const { transactionHash } = await sendSwapTransaction(client, {
|
|
138
|
+
address: options.signerAddress || taker, // Use signerAddress for smart accounts, taker for EOAs
|
|
139
|
+
network: result.network as SendEvmTransactionBodyNetwork,
|
|
140
|
+
swapQuote: result,
|
|
141
|
+
idempotencyKey: executeOptions.idempotencyKey,
|
|
142
|
+
});
|
|
143
|
+
return { transactionHash };
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GetSwapPriceOptions,
|
|
3
|
+
GetSwapPriceResult,
|
|
4
|
+
SwapUnavailableResult,
|
|
5
|
+
} from "../../../client/evm/evm.types.js";
|
|
6
|
+
import { CdpOpenApiClientType, GetSwapPriceResponse } from "../../../openapi-client/index.js";
|
|
7
|
+
import { Address } from "../../../types/misc.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Gets the price for a swap between two tokens on an EVM network.
|
|
11
|
+
*
|
|
12
|
+
* @param {CdpOpenApiClientType} client - The client to use to get the swap price.
|
|
13
|
+
* @param {GetSwapPriceOptions} options - The options for getting a swap price.
|
|
14
|
+
*
|
|
15
|
+
* @returns {Promise<GetSwapPriceResult | SwapUnavailableResult>} A promise that resolves to the swap price result or a response indicating that liquidity is unavailable.
|
|
16
|
+
*
|
|
17
|
+
* @example **Getting a swap price**
|
|
18
|
+
* ```ts
|
|
19
|
+
* const price = await getSwapPrice(client, {
|
|
20
|
+
* network: "ethereum-mainnet",
|
|
21
|
+
* toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
|
22
|
+
* fromToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
|
|
23
|
+
* fromAmount: BigInt("1000000000000000000"), // 1 WETH in wei
|
|
24
|
+
* taker: "0x1234567890123456789012345678901234567890"
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export async function getSwapPrice(
|
|
29
|
+
client: CdpOpenApiClientType,
|
|
30
|
+
options: GetSwapPriceOptions,
|
|
31
|
+
): Promise<GetSwapPriceResult | SwapUnavailableResult> {
|
|
32
|
+
// Call the getEvmSwapPrice function directly with the client's configured API
|
|
33
|
+
const response = await client.getEvmSwapPrice({
|
|
34
|
+
network: options.network,
|
|
35
|
+
toToken: options.toToken,
|
|
36
|
+
fromToken: options.fromToken,
|
|
37
|
+
fromAmount: options.fromAmount.toString(),
|
|
38
|
+
taker: options.taker,
|
|
39
|
+
signerAddress: options.signerAddress,
|
|
40
|
+
gasPrice: options.gasPrice?.toString(),
|
|
41
|
+
slippageBps: options.slippageBps,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Check if liquidity is unavailable
|
|
45
|
+
if (!response.liquidityAvailable) {
|
|
46
|
+
// Return the SwapUnavailableResult
|
|
47
|
+
return {
|
|
48
|
+
liquidityAvailable: false,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// At this point we know it's a GetSwapPriceResponse with liquidityAvailable as true
|
|
53
|
+
const quoteResponse = response as GetSwapPriceResponse;
|
|
54
|
+
return {
|
|
55
|
+
blockNumber: BigInt(quoteResponse.blockNumber),
|
|
56
|
+
toAmount: BigInt(quoteResponse.toAmount),
|
|
57
|
+
toToken: quoteResponse.toToken as Address,
|
|
58
|
+
fees: {
|
|
59
|
+
gasFee: quoteResponse.fees.gasFee
|
|
60
|
+
? {
|
|
61
|
+
amount: BigInt(quoteResponse.fees.gasFee.amount),
|
|
62
|
+
token: quoteResponse.fees.gasFee.token as Address,
|
|
63
|
+
}
|
|
64
|
+
: undefined,
|
|
65
|
+
protocolFee: quoteResponse.fees.protocolFee
|
|
66
|
+
? {
|
|
67
|
+
amount: BigInt(quoteResponse.fees.protocolFee.amount),
|
|
68
|
+
token: quoteResponse.fees.protocolFee.token as Address,
|
|
69
|
+
}
|
|
70
|
+
: undefined,
|
|
71
|
+
},
|
|
72
|
+
issues: {
|
|
73
|
+
allowance: quoteResponse.issues.allowance
|
|
74
|
+
? {
|
|
75
|
+
currentAllowance: BigInt(quoteResponse.issues.allowance.currentAllowance),
|
|
76
|
+
spender: quoteResponse.issues.allowance.spender as Address,
|
|
77
|
+
}
|
|
78
|
+
: undefined,
|
|
79
|
+
balance: quoteResponse.issues.balance
|
|
80
|
+
? {
|
|
81
|
+
token: quoteResponse.issues.balance.token as Address,
|
|
82
|
+
currentBalance: BigInt(quoteResponse.issues.balance.currentBalance),
|
|
83
|
+
requiredBalance: BigInt(quoteResponse.issues.balance.requiredBalance),
|
|
84
|
+
}
|
|
85
|
+
: undefined,
|
|
86
|
+
simulationIncomplete: quoteResponse.issues.simulationIncomplete,
|
|
87
|
+
},
|
|
88
|
+
liquidityAvailable: true,
|
|
89
|
+
minToAmount: BigInt(quoteResponse.minToAmount),
|
|
90
|
+
fromAmount: BigInt(quoteResponse.fromAmount),
|
|
91
|
+
fromToken: quoteResponse.fromToken as Address,
|
|
92
|
+
gas: quoteResponse.gas ? BigInt(quoteResponse.gas) : undefined,
|
|
93
|
+
gasPrice: quoteResponse.gasPrice ? BigInt(quoteResponse.gasPrice) : undefined,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { concat, numberToHex, size } from "viem";
|
|
2
|
+
|
|
3
|
+
import { createSwapQuote } from "./createSwapQuote.js";
|
|
4
|
+
import { sendTransaction } from "../sendTransaction.js";
|
|
5
|
+
|
|
6
|
+
import type { SendSwapTransactionOptions, SendSwapTransactionResult } from "./types.js";
|
|
7
|
+
import type {
|
|
8
|
+
CreateSwapQuoteResult,
|
|
9
|
+
CreateSwapQuoteOptions,
|
|
10
|
+
SwapUnavailableResult,
|
|
11
|
+
} from "../../../client/evm/evm.types.js";
|
|
12
|
+
import type {
|
|
13
|
+
CdpOpenApiClientType,
|
|
14
|
+
SendEvmTransactionBodyNetwork,
|
|
15
|
+
} from "../../../openapi-client/index.js";
|
|
16
|
+
import type { Hex } from "../../../types/misc.js";
|
|
17
|
+
import type { TransactionRequestEIP1559 } from "viem";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Sends a swap transaction to the blockchain.
|
|
21
|
+
* Handles any permit2 signatures required for the swap.
|
|
22
|
+
*
|
|
23
|
+
* If you encounter token allowance issues, you'll need to perform a token approval transaction first to allow
|
|
24
|
+
* the Permit2 contract to spend the appropriate amount of your fromToken.
|
|
25
|
+
* See `examples/typescript/evm/account.sendSwapTransaction.ts` for example code on handling token approvals.
|
|
26
|
+
*
|
|
27
|
+
* @param {CdpOpenApiClientType} client - The client to use for sending the swap.
|
|
28
|
+
* @param {SendSwapTransactionOptions} options - The options for the swap submission.
|
|
29
|
+
*
|
|
30
|
+
* @returns {Promise<SendSwapTransactionResult>} A promise that resolves to the transaction hash.
|
|
31
|
+
*
|
|
32
|
+
* @throws {Error} If liquidity is not available for the swap.
|
|
33
|
+
* @throws {Error} If there are insufficient token allowances. In this case, you need to approve the
|
|
34
|
+
* Permit2 contract to spend your tokens before attempting the swap. The error message
|
|
35
|
+
* will include the current allowance and the spender address that needs approval.
|
|
36
|
+
* @throws {Error} If no transaction data is found in the swap result.
|
|
37
|
+
*
|
|
38
|
+
* @example **Sending a swap with pre-created swap quote object**
|
|
39
|
+
* ```ts
|
|
40
|
+
* // First create a swap quote
|
|
41
|
+
* const swapQuote = await cdp.evm.createSwapQuote({
|
|
42
|
+
* network: "base",
|
|
43
|
+
* toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
|
44
|
+
* fromToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
|
|
45
|
+
* fromAmount: BigInt("1000000000000000000"), // 1 WETH in wei
|
|
46
|
+
* taker: account.address
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* // Check if liquidity is available
|
|
50
|
+
* if (!swapQuote.liquidityAvailable) {
|
|
51
|
+
* console.error("Insufficient liquidity for swap");
|
|
52
|
+
* return;
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* // Send the swap
|
|
56
|
+
* const result = await sendSwapTransaction(client, {
|
|
57
|
+
* address: account.address,
|
|
58
|
+
* swapQuote: swapQuote
|
|
59
|
+
* });
|
|
60
|
+
*
|
|
61
|
+
* console.log(`Swap sent with transaction hash: ${result.transactionHash}`);
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @example **Sending a swap with inline options (all-in-one)**
|
|
65
|
+
* ```ts
|
|
66
|
+
* // Send swap in one call
|
|
67
|
+
* const result = await sendSwapTransaction(client, {
|
|
68
|
+
* address: account.address,
|
|
69
|
+
* network: "base",
|
|
70
|
+
* toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
|
|
71
|
+
* fromToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
|
|
72
|
+
* fromAmount: BigInt("1000000000000000000"), // 1 WETH in wei
|
|
73
|
+
* taker: account.address
|
|
74
|
+
* });
|
|
75
|
+
*
|
|
76
|
+
* console.log(`Swap sent with transaction hash: ${result.transactionHash}`);
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export async function sendSwapTransaction(
|
|
80
|
+
client: CdpOpenApiClientType,
|
|
81
|
+
options: SendSwapTransactionOptions,
|
|
82
|
+
): Promise<SendSwapTransactionResult> {
|
|
83
|
+
const { address, idempotencyKey } = options;
|
|
84
|
+
|
|
85
|
+
let swapResult: CreateSwapQuoteResult | SwapUnavailableResult;
|
|
86
|
+
|
|
87
|
+
// Determine if we need to create the swap quote or use the provided one
|
|
88
|
+
if ("swapQuote" in options) {
|
|
89
|
+
// Use the provided swap quote
|
|
90
|
+
swapResult = options.swapQuote;
|
|
91
|
+
} else {
|
|
92
|
+
// Create the swap quote using the provided options (InlineSendSwapTransactionOptions)
|
|
93
|
+
swapResult = await createSwapQuote(client, {
|
|
94
|
+
network: options.network as CreateSwapQuoteOptions["network"],
|
|
95
|
+
toToken: options.toToken,
|
|
96
|
+
fromToken: options.fromToken,
|
|
97
|
+
fromAmount: options.fromAmount,
|
|
98
|
+
taker: options.taker,
|
|
99
|
+
signerAddress: options.signerAddress,
|
|
100
|
+
gasPrice: options.gasPrice,
|
|
101
|
+
slippageBps: options.slippageBps,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Check if liquidity is available
|
|
106
|
+
if (!swapResult.liquidityAvailable) {
|
|
107
|
+
throw new Error("Insufficient liquidity for swap");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// At this point, we know that swapResult is CreateSwapQuoteResult
|
|
111
|
+
const swap = swapResult as CreateSwapQuoteResult;
|
|
112
|
+
|
|
113
|
+
// Check for allowance issues
|
|
114
|
+
if (swap.issues?.allowance) {
|
|
115
|
+
const { currentAllowance, spender } = swap.issues.allowance;
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Insufficient token allowance for swap. Current allowance: ${currentAllowance}. ` +
|
|
118
|
+
`Please approve the Permit2 contract (${spender}) to spend your tokens.`,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// If the transaction doesn't exist, throw an error
|
|
123
|
+
if (!swap.transaction) {
|
|
124
|
+
throw new Error("No transaction data found in the swap");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Get the transaction data and modify it if needed for Permit2
|
|
128
|
+
let txData = swap.transaction.data as Hex;
|
|
129
|
+
|
|
130
|
+
if (swap.permit2?.eip712) {
|
|
131
|
+
// Sign the Permit2 EIP-712 message
|
|
132
|
+
const signature = await client.signEvmTypedData(
|
|
133
|
+
address,
|
|
134
|
+
{
|
|
135
|
+
domain: swap.permit2.eip712.domain,
|
|
136
|
+
types: swap.permit2.eip712.types,
|
|
137
|
+
primaryType: swap.permit2.eip712.primaryType,
|
|
138
|
+
message: swap.permit2.eip712.message,
|
|
139
|
+
},
|
|
140
|
+
idempotencyKey,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// Calculate the signature length as a 32-byte hex value
|
|
144
|
+
const signatureLengthInHex = numberToHex(size(signature.signature as Hex), {
|
|
145
|
+
signed: false,
|
|
146
|
+
size: 32,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Append the signature length and signature to the transaction data
|
|
150
|
+
txData = concat([txData, signatureLengthInHex, signature.signature as Hex]);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Create a transaction object
|
|
154
|
+
const transaction: TransactionRequestEIP1559 = {
|
|
155
|
+
to: swap.transaction.to as `0x${string}`,
|
|
156
|
+
data: txData,
|
|
157
|
+
// Only include these properties if they exist
|
|
158
|
+
...(swap.transaction.value ? { value: BigInt(swap.transaction.value) } : {}),
|
|
159
|
+
...(swap.transaction.gas ? { gas: BigInt(swap.transaction.gas) } : {}),
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// Use sendTransaction instead of directly calling client.sendEvmTransaction
|
|
163
|
+
const result = await sendTransaction(client, {
|
|
164
|
+
address,
|
|
165
|
+
network: swap.network as SendEvmTransactionBodyNetwork,
|
|
166
|
+
transaction,
|
|
167
|
+
idempotencyKey,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
transactionHash: result.transactionHash,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CreateSwapQuoteOptions,
|
|
3
|
+
CreateSwapQuoteResult,
|
|
4
|
+
SwapUnavailableResult,
|
|
5
|
+
} from "../../../client/evm/evm.types.js";
|
|
6
|
+
import type { SendEvmTransactionBodyNetwork } from "../../../openapi-client/index.js";
|
|
7
|
+
import type { Address, Hex } from "../../../types/misc.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Base options for sending a swap transaction.
|
|
11
|
+
*/
|
|
12
|
+
interface BaseSendSwapTransactionOptions {
|
|
13
|
+
/**
|
|
14
|
+
* The address of the account that will execute the swap.
|
|
15
|
+
*/
|
|
16
|
+
address: Address;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Optional idempotency key for the request.
|
|
20
|
+
*/
|
|
21
|
+
idempotencyKey?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Options when providing an already created swap quote.
|
|
26
|
+
*/
|
|
27
|
+
interface QuoteBasedSendSwapTransactionOptions extends BaseSendSwapTransactionOptions {
|
|
28
|
+
/**
|
|
29
|
+
* The swap quote returned by the createSwapQuote method.
|
|
30
|
+
*/
|
|
31
|
+
swapQuote: CreateSwapQuoteResult;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Options when creating a swap quote inline.
|
|
36
|
+
*/
|
|
37
|
+
interface InlineSendSwapTransactionOptions extends BaseSendSwapTransactionOptions {
|
|
38
|
+
/**
|
|
39
|
+
* The network to execute the swap on (e.g., "ethereum", "base").
|
|
40
|
+
*/
|
|
41
|
+
network: SendEvmTransactionBodyNetwork;
|
|
42
|
+
/** The token to receive (destination token). */
|
|
43
|
+
toToken: Address;
|
|
44
|
+
/** The token to send (source token). */
|
|
45
|
+
fromToken: Address;
|
|
46
|
+
/** The amount to send in atomic units of the token. */
|
|
47
|
+
fromAmount: bigint;
|
|
48
|
+
/** The address that will perform the swap. */
|
|
49
|
+
taker: Address;
|
|
50
|
+
/** The signer address (only needed if taker is a smart contract). */
|
|
51
|
+
signerAddress?: Address;
|
|
52
|
+
/** The gas price in Wei. */
|
|
53
|
+
gasPrice?: bigint;
|
|
54
|
+
/** The slippage tolerance in basis points (0-10000). */
|
|
55
|
+
slippageBps?: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Options for sending a swap transaction.
|
|
60
|
+
* Either provide a pre-created swap quote result or inline swap parameters.
|
|
61
|
+
*/
|
|
62
|
+
export type SendSwapTransactionOptions =
|
|
63
|
+
| QuoteBasedSendSwapTransactionOptions
|
|
64
|
+
| InlineSendSwapTransactionOptions;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Result of sending a swap transaction.
|
|
68
|
+
*/
|
|
69
|
+
export interface SendSwapTransactionResult {
|
|
70
|
+
/**
|
|
71
|
+
* The transaction hash of the submitted swap.
|
|
72
|
+
*/
|
|
73
|
+
transactionHash: Hex;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Options for creating a swap quote (account-level).
|
|
78
|
+
*/
|
|
79
|
+
export type QuoteSwapOptions = Omit<CreateSwapQuoteOptions, "taker">;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Result of creating a swap quote (account-level).
|
|
83
|
+
*/
|
|
84
|
+
export type QuoteSwapResult = CreateSwapQuoteResult | SwapUnavailableResult;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Options for executing a token swap (account-level).
|
|
88
|
+
*/
|
|
89
|
+
export type SwapOptions = Omit<SendSwapTransactionOptions, "address">;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Result of executing a token swap (account-level).
|
|
93
|
+
*/
|
|
94
|
+
export type SwapResult = SendSwapTransactionResult;
|