@switch-win/sdk 1.2.1 → 1.2.3
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/LIMIT-ORDERS.md +737 -0
- package/README.md +91 -83
- package/ROBINHOOD.md +676 -580
- package/package.json +3 -2
- package/src/index.ts +41 -29
- package/src/limit-orders.ts +193 -47
- package/src/networks/index.ts +19 -18
- package/src/networks/robinhood.ts +355 -292
- package/src/types.ts +33 -11
package/README.md
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@switch-win/sdk)
|
|
4
4
|
[](https://www.npmjs.com/package/@switch-win/sdk)
|
|
5
5
|
|
|
6
|
-
> **Official integration kit for the Switch DEX Aggregator on PulseChain and Robinhood Chain**
|
|
6
|
+
> **Official integration kit for the Switch DEX Aggregator on PulseChain and Robinhood Chain**
|
|
7
7
|
|
|
8
8
|
Everything partners need to integrate Switch swaps and limit orders — API docs, TypeScript types, ABIs, constants, and ready-to-use examples.
|
|
9
9
|
|
|
10
|
-
**Swap API:** `https://quote.switch.win` | **Swap chains:** PulseChain (369), Robinhood Chain (4663) | **Limit orders:** PulseChain
|
|
10
|
+
**Swap API:** `https://quote.switch.win` | **Swap chains:** PulseChain (369), Robinhood Chain (4663) | **Limit orders:** PulseChain and Robinhood Chain
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -20,9 +20,9 @@ Switch-SDK/
|
|
|
20
20
|
├── src/
|
|
21
21
|
│ ├── index.ts # Main entry — re-exports everything
|
|
22
22
|
│ ├── types.ts # TypeScript types (swap + limit orders)
|
|
23
|
-
│ ├── constants.ts # PulseChain addresses, ABIs, EIP-712, PLSFlow config
|
|
24
|
-
│ ├── networks/
|
|
25
|
-
│ │ └── robinhood.ts # Robinhood metadata, contracts, tokens, quote URL helper
|
|
23
|
+
│ ├── constants.ts # PulseChain addresses, ABIs, EIP-712, PLSFlow config
|
|
24
|
+
│ ├── networks/
|
|
25
|
+
│ │ └── robinhood.ts # Robinhood metadata, contracts, tokens, quote URL helper
|
|
26
26
|
│ └── limit-orders.ts # Limit order helpers (build, sign, submit, query, PLSFlow)
|
|
27
27
|
├── abi/
|
|
28
28
|
│ ├── SwitchRouterABI.json # Full SwitchRouter contract ABI
|
|
@@ -42,26 +42,26 @@ Switch-SDK/
|
|
|
42
42
|
|
|
43
43
|
0. [Installation](#installation)
|
|
44
44
|
|
|
45
|
-
### Swaps
|
|
46
|
-
|
|
47
|
-
1. [Quickstart](#quickstart)
|
|
48
|
-
2. [Robinhood Chain](#robinhood-chain)
|
|
49
|
-
3. [Authentication](#authentication)
|
|
50
|
-
4. [Swap Integration Flow](#swap-integration-flow)
|
|
51
|
-
5. [Swap API Reference](#swap-api-reference)
|
|
52
|
-
6. [Error Handling](#error-handling)
|
|
53
|
-
7. [Partner Fee Sharing](#partner-fee-sharing)
|
|
45
|
+
### Swaps
|
|
46
|
+
|
|
47
|
+
1. [Quickstart](#quickstart)
|
|
48
|
+
2. [Robinhood Chain](#robinhood-chain)
|
|
49
|
+
3. [Authentication](#authentication)
|
|
50
|
+
4. [Swap Integration Flow](#swap-integration-flow)
|
|
51
|
+
5. [Swap API Reference](#swap-api-reference)
|
|
52
|
+
6. [Error Handling](#error-handling)
|
|
53
|
+
7. [Partner Fee Sharing](#partner-fee-sharing)
|
|
54
54
|
|
|
55
55
|
### Limit Orders
|
|
56
56
|
|
|
57
|
-
8. [Limit Orders](#limit-orders) — full guide in [`LIMIT-ORDERS.md`](LIMIT-ORDERS.md)
|
|
57
|
+
8. [Limit Orders](#limit-orders) — full guide in [`LIMIT-ORDERS.md`](LIMIT-ORDERS.md)
|
|
58
58
|
|
|
59
59
|
### General
|
|
60
60
|
|
|
61
|
-
9. [Constants & Addresses](#constants--addresses)
|
|
62
|
-
10. [Full Integration Examples](#full-integration-examples)
|
|
63
|
-
11. [Rate Limits](#rate-limits)
|
|
64
|
-
12. [Support](#support)
|
|
61
|
+
9. [Constants & Addresses](#constants--addresses)
|
|
62
|
+
10. [Full Integration Examples](#full-integration-examples)
|
|
63
|
+
11. [Rate Limits](#rate-limits)
|
|
64
|
+
12. [Support](#support)
|
|
65
65
|
|
|
66
66
|
---
|
|
67
67
|
|
|
@@ -86,7 +86,7 @@ Get a swap quote and execute it in **three steps**:
|
|
|
86
86
|
curl -H "x-api-key: YOUR_KEY" \
|
|
87
87
|
"https://quote.switch.win/swap/quote?network=pulsechain&from=0xA1077a294dDE1B09bB078844df40758a5D0f9a27&to=0x95B303987A60C71504D99Aa1b13B4DA07b0790ab&amount=1000000000000000000&sender=0xYOUR_WALLET&slippage=100"
|
|
88
88
|
|
|
89
|
-
# 2. Approve the SwitchRouter to spend your input token (ERC-20 only; skip for native currency)
|
|
89
|
+
# 2. Approve the SwitchRouter to spend your input token (ERC-20 only; skip for native currency)
|
|
90
90
|
|
|
91
91
|
# 3. Send the transaction using the `tx` object from the response:
|
|
92
92
|
# { to: "0x0305...", data: "0x...", value: "0" }
|
|
@@ -106,7 +106,7 @@ const res = await fetch(
|
|
|
106
106
|
);
|
|
107
107
|
const quote: BestPathResponse = await res.json();
|
|
108
108
|
|
|
109
|
-
// 2. Approve SwitchRouter (ERC-20 only — skip for native currency)
|
|
109
|
+
// 2. Approve SwitchRouter (ERC-20 only — skip for native currency)
|
|
110
110
|
const token = new ethers.Contract(fromToken, ["function approve(address,uint256)"], signer);
|
|
111
111
|
await (await token.approve(SWITCH_ROUTER, amount)).wait();
|
|
112
112
|
|
|
@@ -116,40 +116,44 @@ await signer.sendTransaction(quote.tx);
|
|
|
116
116
|
|
|
117
117
|
> **⚠️ Always use `tx.to` from the quote response** when sending swap transactions. Do NOT hardcode the router address — the contract may be redeployed.
|
|
118
118
|
|
|
119
|
-
For a production integration with tax token handling, adapter filtering, and fee mode selection, see [Swap Integration Flow](#swap-integration-flow) and the [full examples](examples/).
|
|
120
|
-
|
|
121
|
-
### Robinhood Chain
|
|
122
|
-
|
|
123
|
-
Robinhood uses the same quote endpoint; set `network=robinhood`. The dedicated
|
|
119
|
+
For a production integration with tax token handling, adapter filtering, and fee mode selection, see [Swap Integration Flow](#swap-integration-flow) and the [full examples](examples/).
|
|
120
|
+
|
|
121
|
+
### Robinhood Chain
|
|
122
|
+
|
|
123
|
+
Robinhood uses the same quote endpoint; set `network=robinhood`. The dedicated
|
|
124
124
|
module includes canonical chain metadata, deployed Switch contracts, vetted
|
|
125
125
|
routing hubs, and a URL builder that always includes the correct network.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
126
|
+
The production router exposes fourteen adapters across Uniswap, SwapHood,
|
|
127
|
+
Up33, Sheriff, Aeon, Catnip, PancakeSwap, RobinSwap, SushiSwap, and Switch limit
|
|
128
|
+
orders.
|
|
129
|
+
|
|
130
|
+
For network configuration, deployed addresses, tax handling, execution, and
|
|
131
|
+
the complete frontend token list, see [`ROBINHOOD.md`](ROBINHOOD.md).
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import {
|
|
135
|
+
ROBINHOOD_NATIVE_ETH,
|
|
136
|
+
ROBINHOOD_TOKENS,
|
|
137
|
+
buildRobinhoodQuoteUrl,
|
|
138
|
+
} from "@switch-win/sdk/networks/robinhood";
|
|
139
|
+
|
|
140
|
+
const url = buildRobinhoodQuoteUrl({
|
|
141
|
+
from: ROBINHOOD_NATIVE_ETH,
|
|
142
|
+
to: ROBINHOOD_TOKENS.USDG.address,
|
|
143
|
+
amount: 1_000_000_000_000_000n,
|
|
144
|
+
sender: walletAddress,
|
|
145
|
+
slippage: 100, // 1%, matching the Robinhood frontend default
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const response = await fetch(url, {
|
|
149
|
+
headers: { "x-api-key": process.env.SWITCH_API_KEY! },
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Always approve `ROBINHOOD_SWITCH_CONTRACTS.router` for ERC-20 input, but submit
|
|
154
|
+
the transaction to `quote.tx.to` so integrations remain safe across router
|
|
155
|
+
upgrades. Robinhood limit-order deployment constants and EIP-712 domain values
|
|
156
|
+
are exported from `src/networks/robinhood.ts`.
|
|
153
157
|
|
|
154
158
|
---
|
|
155
159
|
|
|
@@ -250,8 +254,8 @@ function determineFeeOnOutput(
|
|
|
250
254
|
const isSellTax = fromTax.isTaxToken && fromTax.sellTaxBps > 0;
|
|
251
255
|
const isBuyTax = toTax.isTaxToken && toTax.buyTaxBps > 0;
|
|
252
256
|
|
|
253
|
-
// Both tokens are taxed — use fee on input to avoid extra output transfers.
|
|
254
|
-
if (isSellTax && isBuyTax) return false;
|
|
257
|
+
// Both tokens are taxed — use fee on input to avoid extra output transfers.
|
|
258
|
+
if (isSellTax && isBuyTax) return false;
|
|
255
259
|
|
|
256
260
|
// Only output token is tax — fee on input (avoids router holding output tokens)
|
|
257
261
|
if (isBuyTax) return false;
|
|
@@ -290,15 +294,15 @@ Fee portion: Router ──transfer──▶ FeeClaimer (3rd buy tax on fee amoun
|
|
|
290
294
|
```
|
|
291
295
|
The output token is transferred **three times** through different addresses, each incurring a buy tax. The user receives significantly less than expected.
|
|
292
296
|
|
|
293
|
-
**Bottom line:** When the output token has a buy tax, always use `feeOnOutput=false` so the router routes output directly to the user in a single transfer. This applies to both regular swaps and limit orders.
|
|
294
|
-
|
|
295
|
-
### Executing the Swap
|
|
297
|
+
**Bottom line:** When the output token has a buy tax, always use `feeOnOutput=false` so the router routes output directly to the user in a single transfer. This applies to both regular swaps and limit orders.
|
|
298
|
+
|
|
299
|
+
### Executing the Swap
|
|
296
300
|
|
|
297
301
|
Once you have a quote, execute it in two steps:
|
|
298
302
|
|
|
299
303
|
#### Step 1 — Approve Token Spend (ERC-20 inputs only)
|
|
300
304
|
|
|
301
|
-
If the input token is an **ERC-20** rather than the chain's native currency, the user must approve the network's SwitchRouter contract to spend `amount` tokens before submitting the swap.
|
|
305
|
+
If the input token is an **ERC-20** rather than the chain's native currency, the user must approve the network's SwitchRouter contract to spend `amount` tokens before submitting the swap.
|
|
302
306
|
|
|
303
307
|
Before sending an approval transaction, check whether the user already has sufficient allowance to avoid wasting gas on a redundant approve:
|
|
304
308
|
|
|
@@ -326,7 +330,7 @@ const { tx } = quoteResponse;
|
|
|
326
330
|
const txResponse = await signer.sendTransaction({
|
|
327
331
|
to: tx.to,
|
|
328
332
|
data: tx.data,
|
|
329
|
-
value: tx.value, // "0" for ERC-20 inputs, amountIn for native currency
|
|
333
|
+
value: tx.value, // "0" for ERC-20 inputs, amountIn for native currency
|
|
330
334
|
});
|
|
331
335
|
|
|
332
336
|
const receipt = await txResponse.wait();
|
|
@@ -386,7 +390,7 @@ Returns all available DEX adapters with their on-chain indices and contract addr
|
|
|
386
390
|
|
|
387
391
|
| Param | Required | Type | Description |
|
|
388
392
|
|---|---|---|---|
|
|
389
|
-
| `network` | **Yes** | string | Target blockchain network: `"pulsechain"` or `"robinhood"`. |
|
|
393
|
+
| `network` | **Yes** | string | Target blockchain network: `"pulsechain"` or `"robinhood"`. |
|
|
390
394
|
|
|
391
395
|
#### Authentication
|
|
392
396
|
|
|
@@ -455,7 +459,7 @@ Detects whether a token has a fee-on-transfer mechanism (tax token) and returns
|
|
|
455
459
|
| Parameter | Required | Type | Description |
|
|
456
460
|
|---|---|---|---|
|
|
457
461
|
| `token` | **Yes** | address | Token address to check (0x + 40 hex chars) |
|
|
458
|
-
| `network` | No | string | Target blockchain: `"pulsechain"` or `"robinhood"`. |
|
|
462
|
+
| `network` | No | string | Target blockchain: `"pulsechain"` or `"robinhood"`. |
|
|
459
463
|
|
|
460
464
|
#### Latency
|
|
461
465
|
|
|
@@ -569,9 +573,9 @@ Returns the optimal split-route for a swap and (optionally) a ready-to-send tran
|
|
|
569
573
|
|
|
570
574
|
| Parameter | Required | Type | Default | Description |
|
|
571
575
|
|---|---|---|---|---|
|
|
572
|
-
| `network` | **Yes** | string | — | Target blockchain network: `"pulsechain"` or `"robinhood"`. |
|
|
573
|
-
| `from` | **Yes** | address | — | Input token address. Use `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` for the network's native currency (PLS or ETH). |
|
|
574
|
-
| `to` | **Yes** | address | — | Output token address. Use `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` for the network's native currency (PLS or ETH). |
|
|
576
|
+
| `network` | **Yes** | string | — | Target blockchain network: `"pulsechain"` or `"robinhood"`. |
|
|
577
|
+
| `from` | **Yes** | address | — | Input token address. Use `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` for the network's native currency (PLS or ETH). |
|
|
578
|
+
| `to` | **Yes** | address | — | Output token address. Use `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` for the network's native currency (PLS or ETH). |
|
|
575
579
|
| `amount` | **Yes** | string | — | Input amount in **wei** (raw integer string, no decimals). Max: 10²⁷. |
|
|
576
580
|
| `sender` | No* | address | — | Sender wallet address. **Required to receive `tx` calldata in the response.** |
|
|
577
581
|
| `receiver` | No | address | `sender` | Custom recipient address. If omitted, output tokens are sent to `sender`. |
|
|
@@ -660,7 +664,7 @@ GET /swap/quote?network=pulsechain&from=0xA1077a294dDE1B09bB078844df40758a5D0f9a
|
|
|
660
664
|
"tx": {
|
|
661
665
|
"to": "0x0305fcb5dA680EA6fd1B01A96C1949175B99d406",
|
|
662
666
|
"data": "0x...", // ABI-encoded goSwitch() calldata with feeOnOutput = false
|
|
663
|
-
"value": "0" // "0" for ERC-20 input; amountIn for native-currency input
|
|
667
|
+
"value": "0" // "0" for ERC-20 input; amountIn for native-currency input
|
|
664
668
|
},
|
|
665
669
|
// Same swap but with fee taken from the output token instead
|
|
666
670
|
"txFeeOnOutput": {
|
|
@@ -798,7 +802,7 @@ Errors are returned as JSON with an `error` field:
|
|
|
798
802
|
| Error | Cause |
|
|
799
803
|
|---|---|
|
|
800
804
|
| `"Missing required parameter: network"` | `network` query param absent |
|
|
801
|
-
| `"This network is not supported at this time."` | `network` is not a supported value (`"pulsechain"` or `"robinhood"`) |
|
|
805
|
+
| `"This network is not supported at this time."` | `network` is not a supported value (`"pulsechain"` or `"robinhood"`) |
|
|
802
806
|
| `"Missing required parameters: from, to, amount"` | One or more required query params absent |
|
|
803
807
|
| `"Invalid from address (must be 0x + 40 hex chars)"` | `from` is not a valid hex address |
|
|
804
808
|
| `"Invalid to address (must be 0x + 40 hex chars)"` | `to` is not a valid hex address |
|
|
@@ -828,7 +832,7 @@ If the swap transaction reverts on-chain, the SwitchRouter contract returns one
|
|
|
828
832
|
| `FinalAmountOutTooLow()` | Output after fees fell below `_minTotalAmountOut` — price moved beyond your slippage tolerance. Retry with a fresh quote or increase slippage. |
|
|
829
833
|
| `ExcessiveFee()` | `_fee` exceeds the contract maximum (100 bps / 1 %). |
|
|
830
834
|
| `InsufficientFee()` | `_fee` is below the protocol's `MIN_FEE`. Contact the Switch team if you need a lower fee. |
|
|
831
|
-
| `MsgValueMismatch()` | For native-currency swaps, `msg.value` must exactly equal the route's total `amountIn`. |
|
|
835
|
+
| `MsgValueMismatch()` | For native-currency swaps, `msg.value` must exactly equal the route's total `amountIn`. |
|
|
832
836
|
| `ZeroInput()` | No input amount was provided. |
|
|
833
837
|
|
|
834
838
|
---
|
|
@@ -881,11 +885,11 @@ function shouldFeeOnOutput(from: string, to: string, quote?: BestPathResponse):
|
|
|
881
885
|
if (toAddr === MY_PROJECT_TOKEN) return false; // fee on input = collect input
|
|
882
886
|
|
|
883
887
|
// Priority 2: Avoid collecting tax tokens (fee revenue lost to transfer tax)
|
|
884
|
-
if (quote) {
|
|
885
|
-
const fromIsTax = quote.fromTokenTax?.isTaxToken ?? false;
|
|
886
|
-
const toIsTax = quote.toTokenTax?.isTaxToken ?? false;
|
|
887
|
-
if (fromIsTax && toIsTax) return false;
|
|
888
|
-
if (fromIsTax && !toIsTax) return true; // collect non-tax output
|
|
888
|
+
if (quote) {
|
|
889
|
+
const fromIsTax = quote.fromTokenTax?.isTaxToken ?? false;
|
|
890
|
+
const toIsTax = quote.toTokenTax?.isTaxToken ?? false;
|
|
891
|
+
if (fromIsTax && toIsTax) return false;
|
|
892
|
+
if (fromIsTax && !toIsTax) return true; // collect non-tax output
|
|
889
893
|
if (toIsTax && !fromIsTax) return false; // collect non-tax input
|
|
890
894
|
}
|
|
891
895
|
|
|
@@ -916,26 +920,30 @@ await signer.sendTransaction(chosenTx);
|
|
|
916
920
|
|
|
917
921
|
## Limit Orders
|
|
918
922
|
|
|
919
|
-
Switch Limit Orders let users place **gasless, signed orders** that are filled automatically when market conditions are met — no gas to create, no token deposits, EIP-712 signed.
|
|
920
|
-
|
|
921
|
-
**→ Full integration guide: [`LIMIT-ORDERS.md`](LIMIT-ORDERS.md)**
|
|
922
|
-
|
|
923
|
-
Covers
|
|
923
|
+
Switch Limit Orders let users place **gasless, signed orders** that are filled automatically when market conditions are met — no gas to create, no token deposits, EIP-712 signed.
|
|
924
|
+
|
|
925
|
+
**→ Full integration guide: [`LIMIT-ORDERS.md`](LIMIT-ORDERS.md)**
|
|
926
|
+
|
|
927
|
+
Covers both `pulsechain` and `robinhood`: creating orders, live deployment
|
|
928
|
+
discovery, approvals, `feeOnOutput` decision rules, native PLS/ETH flows,
|
|
929
|
+
querying, cancellation, API types, and EIP-712 details. Use
|
|
930
|
+
`fetchLimitOrderConfig({ network })` at startup and include `network` in every
|
|
931
|
+
orderbook request.
|
|
924
932
|
|
|
925
933
|
---
|
|
926
934
|
|
|
927
935
|
## Constants & Addresses
|
|
928
936
|
|
|
929
|
-
PulseChain constants are importable from [`src/constants.ts`](src/constants.ts).
|
|
930
|
-
Robinhood constants are available from
|
|
931
|
-
[`src/networks/robinhood.ts`](src/networks/robinhood.ts); see the complete
|
|
932
|
-
[`ROBINHOOD.md`](ROBINHOOD.md) integration reference.
|
|
937
|
+
PulseChain constants are importable from [`src/constants.ts`](src/constants.ts).
|
|
938
|
+
Robinhood constants are available from
|
|
939
|
+
[`src/networks/robinhood.ts`](src/networks/robinhood.ts); see the complete
|
|
940
|
+
[`ROBINHOOD.md`](ROBINHOOD.md) integration reference.
|
|
933
941
|
|
|
934
942
|
> **⚠️ Do not hardcode the SwitchRouter address.** The router contract may be redeployed from time to time. Always use the `tx.to` (or `txFeeOnOutput.to`) address returned by the `/bestPath` API response when building your transaction. This ensures your integration automatically picks up router upgrades without code changes.
|
|
935
943
|
|
|
936
944
|
| Name | Value |
|
|
937
945
|
|---|---|
|
|
938
|
-
| **Chain** | PulseChain (Chain ID `369`); Robinhood Chain uses ID `4663` and network-specific exports |
|
|
946
|
+
| **Chain** | PulseChain (Chain ID `369`); Robinhood Chain uses ID `4663` and network-specific exports |
|
|
939
947
|
| **SwitchRouter** | `0x0305fcb5dA680EA6fd1B01A96C1949175B99d406` |
|
|
940
948
|
| **SwitchLimitOrder** (V2 — current) | `0x8e3881bdF81Fc0211383B2e576076B654F7aFD86` |
|
|
941
949
|
| **SwitchLimitOrder** (V1 — legacy) | `0x0e884072a891b406C0D814907A1E2310fE5F5Deb` |
|