@switch-win/sdk 1.0.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/README.md +950 -0
- package/abi/SwitchLimitOrderABI.json +1296 -0
- package/abi/SwitchRouterABI.json +954 -0
- package/package.json +41 -0
- package/src/constants.ts +238 -0
- package/src/index.ts +110 -0
- package/src/limit-orders.ts +435 -0
- package/src/types.ts +423 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Switch DEX Aggregator -- API Response Types
|
|
3
|
+
*
|
|
4
|
+
* TypeScript interfaces for all objects returned by the /swap/quote endpoint.
|
|
5
|
+
* Import these to get full type safety when integrating with the Switch API.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import type { BestPathResponse } from "@switch-win/sdk/types";
|
|
10
|
+
*
|
|
11
|
+
* const res = await fetch("https://quote.switch.win/swap/quote?...");
|
|
12
|
+
* const quote: BestPathResponse = await res.json();
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// -- Top-level response --
|
|
17
|
+
|
|
18
|
+
/** Full response from `GET /swap/quote` */
|
|
19
|
+
export interface BestPathResponse {
|
|
20
|
+
/** Input token address */
|
|
21
|
+
fromToken: string;
|
|
22
|
+
/** Output token address */
|
|
23
|
+
toToken: string;
|
|
24
|
+
/** Recipient address for output tokens. Same as `sender` unless a custom `receiver` was specified. */
|
|
25
|
+
receiver?: string;
|
|
26
|
+
/** Total input amount in wei */
|
|
27
|
+
totalAmountIn: string;
|
|
28
|
+
/**
|
|
29
|
+
* Raw DEX output in wei -- reflects price impact only.
|
|
30
|
+
* This is the amount the pools would return before any taxes, fees, or slippage are applied.
|
|
31
|
+
*/
|
|
32
|
+
totalAmountOut: string;
|
|
33
|
+
/**
|
|
34
|
+
* Expected output the user will actually receive, in wei.
|
|
35
|
+
* Accounts for sell tax, protocol fee, and buy tax -- but NOT slippage.
|
|
36
|
+
*
|
|
37
|
+
* Use this for UI display of the estimated received amount. For tax tokens,
|
|
38
|
+
* this is significantly more accurate than applying taxes as linear
|
|
39
|
+
* multipliers to `totalAmountOut`.
|
|
40
|
+
*/
|
|
41
|
+
expectedOutputAmount: string;
|
|
42
|
+
/**
|
|
43
|
+
* Minimum acceptable output after taxes, fee, and slippage.
|
|
44
|
+
*
|
|
45
|
+
* Calculated as:
|
|
46
|
+
* `totalAmountOut -- (1 -- sellTax) -- (1 -- fee) -- (1 -- buyTax) -- (1 -- slippage)`
|
|
47
|
+
*
|
|
48
|
+
* This is the value encoded in the `tx` calldata as `_minTotalAmountOut`.
|
|
49
|
+
*/
|
|
50
|
+
minAmountOut: string;
|
|
51
|
+
/** Human-readable path descriptions */
|
|
52
|
+
paths: SwapPath[];
|
|
53
|
+
/** Structured route breakdown (matches on-chain structs) */
|
|
54
|
+
routeAllocation?: RouteAllocationPlan;
|
|
55
|
+
/** Ready-to-send transaction with fee on **input** (default). Only present when `sender` query param is provided. */
|
|
56
|
+
tx?: SwapTransaction;
|
|
57
|
+
/**
|
|
58
|
+
* Ready-to-send transaction with fee on **output**.
|
|
59
|
+
* Only present when `sender` query param is provided.
|
|
60
|
+
*
|
|
61
|
+
* Use this variant when fee-on-output is preferred (e.g. to collect fees in
|
|
62
|
+
* the output token). See the README for recommended strategies.
|
|
63
|
+
*/
|
|
64
|
+
txFeeOnOutput?: SwapTransaction;
|
|
65
|
+
/**
|
|
66
|
+
* Transfer tax info for the input token.
|
|
67
|
+
* Present when the API detects whether the token has a fee-on-transfer mechanism.
|
|
68
|
+
*/
|
|
69
|
+
fromTokenTax?: TokenTaxResponse;
|
|
70
|
+
/**
|
|
71
|
+
* Transfer tax info for the output token.
|
|
72
|
+
* Present when the API detects whether the token has a fee-on-transfer mechanism.
|
|
73
|
+
* If `toTokenTax.isTaxToken` is true, `minAmountOut` already accounts for the buy tax.
|
|
74
|
+
*/
|
|
75
|
+
toTokenTax?: TokenTaxResponse;
|
|
76
|
+
/**
|
|
77
|
+
* Effective slippage in basis points = user slippage + sell tax + buy tax + auto-liq buffer.
|
|
78
|
+
*
|
|
79
|
+
* For example, if a user requests 50 bps (0.5%) slippage but the input token has
|
|
80
|
+
* a 120 bps (1.2%) sell tax, effectiveSlippageBps = 170.
|
|
81
|
+
*
|
|
82
|
+
* Display this in your UI so users understand the total tolerance applied.
|
|
83
|
+
*/
|
|
84
|
+
effectiveSlippageBps: number;
|
|
85
|
+
/**
|
|
86
|
+
* Human-readable effective slippage percentage.
|
|
87
|
+
*
|
|
88
|
+
* Examples: `"0.5"` (no tax), `"1.7"` (0.5% user + 1.2% sell tax), `"4.5"` (0.5% + 2% sell + 2% buy).
|
|
89
|
+
*/
|
|
90
|
+
effectiveSlippagePercent: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Transfer tax information for a token (fee-on-transfer) */
|
|
94
|
+
export interface TokenTaxResponse {
|
|
95
|
+
/** Whether this token has a transfer tax */
|
|
96
|
+
isTaxToken: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Buy tax in basis points.
|
|
99
|
+
* Applied when the token is acquired (i.e. when it is the output token).
|
|
100
|
+
* For example, 500 = 5% buy tax.
|
|
101
|
+
*/
|
|
102
|
+
buyTaxBps: number;
|
|
103
|
+
/**
|
|
104
|
+
* Sell tax in basis points.
|
|
105
|
+
* Applied when the token is sold (i.e. when it is the input token).
|
|
106
|
+
* For example, 500 = 5% sell tax.
|
|
107
|
+
*/
|
|
108
|
+
sellTaxBps: number;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// -- Transaction (on-chain) --
|
|
112
|
+
|
|
113
|
+
/** Transaction object ready to be sent on-chain via `signer.sendTransaction()` */
|
|
114
|
+
export interface SwapTransaction {
|
|
115
|
+
/** SwitchRouter contract address */
|
|
116
|
+
to: string;
|
|
117
|
+
/** ABI-encoded `goSwitch()` calldata */
|
|
118
|
+
data: string;
|
|
119
|
+
/** Native PLS to send (wei). `"0"` for ERC-20 input tokens. */
|
|
120
|
+
value: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// -- Human-readable paths --
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Human-readable summary of a single route split.
|
|
127
|
+
* Useful for UI display (e.g. "60% via PulseX, 40% via 9inch").
|
|
128
|
+
*/
|
|
129
|
+
export interface SwapPath {
|
|
130
|
+
/** Human-readable DEX adapter name (e.g. `"PulseXV2"`, `"UniswapV3"`, `"9inchV2"`) */
|
|
131
|
+
adapter: string;
|
|
132
|
+
/** Input amount for this path (wei) */
|
|
133
|
+
amountIn: string;
|
|
134
|
+
/** Expected output for this path (wei) */
|
|
135
|
+
amountOut: string;
|
|
136
|
+
/** Ordered list of token addresses traversed (e.g. `[tokenIn, intermediate, tokenOut]`) */
|
|
137
|
+
path: string[];
|
|
138
|
+
/** Human-readable adapter names used at each hop */
|
|
139
|
+
adapters: string[];
|
|
140
|
+
/** Percentage of total input routed through this path */
|
|
141
|
+
percentage?: number;
|
|
142
|
+
/** Detailed breakdown of each hop-leg in this path */
|
|
143
|
+
legs?: SwapPathLeg[];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** A single leg within a swap path */
|
|
147
|
+
export interface SwapPathLeg {
|
|
148
|
+
/** Leg input token */
|
|
149
|
+
tokenIn: string;
|
|
150
|
+
/** Leg output token */
|
|
151
|
+
tokenOut: string;
|
|
152
|
+
/** Human-readable DEX adapter name */
|
|
153
|
+
adapter?: string;
|
|
154
|
+
/** Input amount (wei) */
|
|
155
|
+
amountIn: string;
|
|
156
|
+
/** Output amount (wei) */
|
|
157
|
+
amountOut: string;
|
|
158
|
+
/** Percentage of the hop routed through this adapter */
|
|
159
|
+
percentage?: number;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// -- Route allocation (matches on-chain structs) --
|
|
163
|
+
|
|
164
|
+
/** Top-level route allocation plan */
|
|
165
|
+
export interface RouteAllocationPlan {
|
|
166
|
+
/** Total input in wei */
|
|
167
|
+
amountIn: string;
|
|
168
|
+
/** Total expected output in wei */
|
|
169
|
+
totalAmountOut: string;
|
|
170
|
+
/** Array of split routes */
|
|
171
|
+
routes: SingleRouteAllocation[];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** A single route within the split */
|
|
175
|
+
export interface SingleRouteAllocation {
|
|
176
|
+
/** Input amount for this route portion (wei) */
|
|
177
|
+
amountIn: string;
|
|
178
|
+
/** Sequential hops in this route */
|
|
179
|
+
hops: HopAllocationPlan[];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** A single hop within a route */
|
|
183
|
+
export interface HopAllocationPlan {
|
|
184
|
+
/** Hop input token */
|
|
185
|
+
tokenIn: string;
|
|
186
|
+
/** Hop output token */
|
|
187
|
+
tokenOut: string;
|
|
188
|
+
/** Total output from all legs in this hop (wei) */
|
|
189
|
+
totalAmountOut: string;
|
|
190
|
+
/** Adapter legs executing this hop (can be split across DEXes) */
|
|
191
|
+
legs: HopAdapterAllocationPlan[];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** A single adapter leg within a hop */
|
|
195
|
+
export interface HopAdapterAllocationPlan {
|
|
196
|
+
/** DEX adapter contract address */
|
|
197
|
+
adapter: string;
|
|
198
|
+
/** Input amount routed through this adapter (wei) */
|
|
199
|
+
amountIn: string;
|
|
200
|
+
/** Expected output from this adapter (wei) */
|
|
201
|
+
amountOut: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// -- Error response --
|
|
205
|
+
|
|
206
|
+
/** Error response returned when the API encounters a problem */
|
|
207
|
+
export interface ErrorResponse {
|
|
208
|
+
error: string;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** The quote endpoint returns either a successful response or an error */
|
|
212
|
+
export type QuoteResponse = BestPathResponse | ErrorResponse;
|
|
213
|
+
|
|
214
|
+
/** Type guard to check if a response is an error */
|
|
215
|
+
export function isErrorResponse(
|
|
216
|
+
response: QuoteResponse,
|
|
217
|
+
): response is ErrorResponse {
|
|
218
|
+
return "error" in response;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// -- Adapters endpoint --
|
|
222
|
+
|
|
223
|
+
/** A single adapter (DEX) returned by `GET /swap/adapters` */
|
|
224
|
+
export interface AdapterInfo {
|
|
225
|
+
/** On-chain adapter index (used in the `adapters` query param for `/swap/quote`) */
|
|
226
|
+
index: number;
|
|
227
|
+
/** Human-readable DEX name (e.g. `"PulseXV2"`, `"UniswapV3"`, `"9inchV2"`) */
|
|
228
|
+
name: string;
|
|
229
|
+
/** On-chain adapter contract address */
|
|
230
|
+
address: string;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Response from `GET /swap/adapters` */
|
|
234
|
+
export interface AdaptersResponse {
|
|
235
|
+
adapters: AdapterInfo[];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// -- Check Tax endpoint --
|
|
239
|
+
|
|
240
|
+
/** Response from `GET /swap/checkTax` */
|
|
241
|
+
export interface CheckTaxResponse {
|
|
242
|
+
/** Lowercased token address that was checked */
|
|
243
|
+
token: string;
|
|
244
|
+
/** Whether this token has a non-zero transfer tax */
|
|
245
|
+
isTaxToken: boolean;
|
|
246
|
+
/** Buy tax in basis points (applied when the token is the output) */
|
|
247
|
+
buyTaxBps: number;
|
|
248
|
+
/** Sell tax in basis points (applied when the token is the input) */
|
|
249
|
+
sellTaxBps: number;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** Type guard for CheckTaxResponse errors */
|
|
253
|
+
export type CheckTaxResult = CheckTaxResponse | ErrorResponse;
|
|
254
|
+
|
|
255
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
256
|
+
// Limit Orders (V2 — EIP-712 signed, approve-only)
|
|
257
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
258
|
+
|
|
259
|
+
// -- Order parameters --
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Parameters for a limit order — the fields the maker signs via EIP-712.
|
|
263
|
+
*
|
|
264
|
+
* All amounts are raw integer strings in wei (same convention as swap quotes).
|
|
265
|
+
* The `nonce` MUST be unique per maker — once used (filled or cancelled) it
|
|
266
|
+
* cannot be reused.
|
|
267
|
+
*/
|
|
268
|
+
export interface LimitOrderParams {
|
|
269
|
+
/** Maker (signer) address */
|
|
270
|
+
maker: string;
|
|
271
|
+
/** Input token address (token the maker is selling) */
|
|
272
|
+
tokenIn: string;
|
|
273
|
+
/** Output token address (token the maker wants to receive) */
|
|
274
|
+
tokenOut: string;
|
|
275
|
+
/** Amount of tokenIn the maker is offering (wei) */
|
|
276
|
+
amountIn: string;
|
|
277
|
+
/** Minimum amount of tokenOut the maker will accept (wei) */
|
|
278
|
+
minAmountOut: string;
|
|
279
|
+
/**
|
|
280
|
+
* Unix timestamp after which the order expires. Set to `0` for no expiry.
|
|
281
|
+
* The contract will revert with `OrderExpired()` if `block.timestamp > deadline` (when > 0).
|
|
282
|
+
*/
|
|
283
|
+
deadline: number;
|
|
284
|
+
/**
|
|
285
|
+
* Unique nonce per maker. Once a nonce is used (filled or cancelled on-chain),
|
|
286
|
+
* it cannot be reused. Use `Date.now()` or a random integer for uniqueness.
|
|
287
|
+
*/
|
|
288
|
+
nonce: number;
|
|
289
|
+
/**
|
|
290
|
+
* If `true`, the contract fee is deducted from the output (tokenOut) instead
|
|
291
|
+
* of the input (tokenIn). Same concept as swap fee modes.
|
|
292
|
+
*/
|
|
293
|
+
feeOnOutput: boolean;
|
|
294
|
+
/**
|
|
295
|
+
* Address that receives the output tokens. Defaults to the maker if set
|
|
296
|
+
* to the zero address (`0x0000…`).
|
|
297
|
+
*/
|
|
298
|
+
recipient: string;
|
|
299
|
+
/**
|
|
300
|
+
* If `true` and tokenOut is WPLS, the contract unwraps to native PLS
|
|
301
|
+
* before sending to the recipient.
|
|
302
|
+
*/
|
|
303
|
+
unwrapOutput: boolean;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* A signed limit order — the order parameters plus the EIP-712 signature.
|
|
308
|
+
* This is what gets submitted to the Switch backend via `POST /limit-orders`.
|
|
309
|
+
*/
|
|
310
|
+
export interface SignedLimitOrder extends LimitOrderParams {
|
|
311
|
+
/** EIP-712 signature of the order struct, produced by the maker's wallet */
|
|
312
|
+
signature: string;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// -- API request/response types --
|
|
316
|
+
|
|
317
|
+
/** Body for `POST /limit-orders` */
|
|
318
|
+
export type CreateLimitOrderRequest = SignedLimitOrder;
|
|
319
|
+
|
|
320
|
+
/** Body for `DELETE /limit-orders` */
|
|
321
|
+
export interface CancelLimitOrderRequest {
|
|
322
|
+
/** Maker address */
|
|
323
|
+
maker: string;
|
|
324
|
+
/** Nonce of the order to cancel */
|
|
325
|
+
nonce: number;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/** Order status in the backend database */
|
|
329
|
+
export type LimitOrderStatus = "ACTIVE" | "FILLED" | "CANCELLED" | "EXPIRED";
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* A limit order record as returned by the Switch backend API.
|
|
333
|
+
*
|
|
334
|
+
* Includes all order parameters plus metadata fields added by the backend.
|
|
335
|
+
*/
|
|
336
|
+
export interface LimitOrderRecord {
|
|
337
|
+
/** Unique database ID (cuid) */
|
|
338
|
+
id: string;
|
|
339
|
+
/** Maker address (lowercased) */
|
|
340
|
+
maker: string;
|
|
341
|
+
/** Recipient address (lowercased) */
|
|
342
|
+
recipient: string;
|
|
343
|
+
/** Input token address (lowercased) */
|
|
344
|
+
tokenIn: string;
|
|
345
|
+
/** Output token address (lowercased) */
|
|
346
|
+
tokenOut: string;
|
|
347
|
+
/** Input amount in wei */
|
|
348
|
+
amountIn: string;
|
|
349
|
+
/** Minimum output amount in wei */
|
|
350
|
+
minAmountOut: string;
|
|
351
|
+
/** Expiry timestamp (0 = no expiry) */
|
|
352
|
+
deadline: number;
|
|
353
|
+
/** Unique nonce for this maker */
|
|
354
|
+
nonce: number;
|
|
355
|
+
/** Fee mode flag */
|
|
356
|
+
feeOnOutput: boolean;
|
|
357
|
+
/** Unwrap output to native PLS flag */
|
|
358
|
+
unwrapOutput: boolean;
|
|
359
|
+
/** EIP-712 signature */
|
|
360
|
+
signature: string;
|
|
361
|
+
/** Pair key in format `tokenIn:tokenOut` (lowercased) */
|
|
362
|
+
pairKey: string;
|
|
363
|
+
/** Current order status */
|
|
364
|
+
status: LimitOrderStatus;
|
|
365
|
+
/** ISO 8601 creation timestamp */
|
|
366
|
+
createdAt: string;
|
|
367
|
+
/** ISO 8601 last update timestamp */
|
|
368
|
+
updatedAt: string;
|
|
369
|
+
/** Block number where the order was filled (if status is FILLED) */
|
|
370
|
+
filledBlock?: number | null;
|
|
371
|
+
/** Transaction hash of the fill (if status is FILLED) */
|
|
372
|
+
filledTxHash?: string | null;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/** Response from `POST /limit-orders` (success) */
|
|
376
|
+
export interface CreateLimitOrderResponse {
|
|
377
|
+
success: true;
|
|
378
|
+
order: LimitOrderRecord;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** Response from `DELETE /limit-orders` (success) */
|
|
382
|
+
export interface CancelLimitOrderResponse {
|
|
383
|
+
success: true;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/** Response from `GET /limit-orders` */
|
|
387
|
+
export interface ListLimitOrdersResponse {
|
|
388
|
+
/** Total matching orders */
|
|
389
|
+
total: number;
|
|
390
|
+
/** Page size used */
|
|
391
|
+
limit: number;
|
|
392
|
+
/** Page offset used */
|
|
393
|
+
offset: number;
|
|
394
|
+
/** Array of order records */
|
|
395
|
+
orders: LimitOrderRecord[];
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/** Response from `GET /limit-orders/pairs` */
|
|
399
|
+
export interface LimitOrderPair {
|
|
400
|
+
/** Pair key in format `tokenIn:tokenOut` */
|
|
401
|
+
pairKey: string;
|
|
402
|
+
/** Input token address */
|
|
403
|
+
tokenIn: string;
|
|
404
|
+
/** Output token address */
|
|
405
|
+
tokenOut: string;
|
|
406
|
+
/** Number of active orders for this pair */
|
|
407
|
+
activeOrders: number;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/** Response from `GET /limit-orders/stats` */
|
|
411
|
+
export interface LimitOrderStats {
|
|
412
|
+
active: number;
|
|
413
|
+
filled: number;
|
|
414
|
+
cancelled: number;
|
|
415
|
+
expired: number;
|
|
416
|
+
total: number;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/** Union type for limit order mutation responses */
|
|
420
|
+
export type LimitOrderMutationResponse =
|
|
421
|
+
| CreateLimitOrderResponse
|
|
422
|
+
| CancelLimitOrderResponse
|
|
423
|
+
| ErrorResponse;
|