@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
|
@@ -1,321 +1,384 @@
|
|
|
1
|
-
import { API_BASE } from "../constants.js";
|
|
2
|
-
|
|
3
|
-
/** API network value used by Switch endpoints. */
|
|
4
|
-
export const ROBINHOOD_NETWORK = "robinhood" as const;
|
|
5
|
-
|
|
6
|
-
/** Robinhood Chain mainnet metadata. */
|
|
7
|
-
export const ROBINHOOD_CHAIN = {
|
|
8
|
-
id: 4663,
|
|
9
|
-
name: "Robinhood Chain",
|
|
10
|
-
nativeCurrency: {
|
|
11
|
-
name: "Ether",
|
|
12
|
-
symbol: "ETH",
|
|
13
|
-
decimals: 18,
|
|
14
|
-
},
|
|
15
|
-
rpcUrls: ["https://rpc.mainnet.chain.robinhood.com"],
|
|
16
|
-
blockExplorerUrl: "https://robinhoodchain.blockscout.com",
|
|
17
|
-
} as const;
|
|
18
|
-
|
|
19
|
-
/** Native-ETH sentinel accepted by the Switch quote API. */
|
|
20
|
-
export const ROBINHOOD_NATIVE_ETH =
|
|
21
|
-
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
22
|
-
|
|
23
|
-
/** Switch contracts deployed on Robinhood Chain. */
|
|
1
|
+
import { API_BASE } from "../constants.js";
|
|
2
|
+
|
|
3
|
+
/** API network value used by Switch endpoints. */
|
|
4
|
+
export const ROBINHOOD_NETWORK = "robinhood" as const;
|
|
5
|
+
|
|
6
|
+
/** Robinhood Chain mainnet metadata. */
|
|
7
|
+
export const ROBINHOOD_CHAIN = {
|
|
8
|
+
id: 4663,
|
|
9
|
+
name: "Robinhood Chain",
|
|
10
|
+
nativeCurrency: {
|
|
11
|
+
name: "Ether",
|
|
12
|
+
symbol: "ETH",
|
|
13
|
+
decimals: 18,
|
|
14
|
+
},
|
|
15
|
+
rpcUrls: ["https://rpc.mainnet.chain.robinhood.com"],
|
|
16
|
+
blockExplorerUrl: "https://robinhoodchain.blockscout.com",
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
/** Native-ETH sentinel accepted by the Switch quote API. */
|
|
20
|
+
export const ROBINHOOD_NATIVE_ETH =
|
|
21
|
+
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
22
|
+
|
|
23
|
+
/** Switch contracts deployed on Robinhood Chain. */
|
|
24
24
|
export const ROBINHOOD_SWITCH_CONTRACTS = {
|
|
25
|
-
/** ERC-20 approval target. Use quote.tx.to when submitting a swap. */
|
|
26
|
-
router: "0x8730C3e2cF2c8CDa8E6166837A1Ed26f46aa9E59",
|
|
27
|
-
routerView: "0xFF6b56d3F444eB5b7FA1db047F57140C84810376",
|
|
28
|
-
uniswapV2Adapter: "0x7a14d7A8509a66209D4332843b983b29bF5604A4",
|
|
29
|
-
uniswapV3Adapter: "0xbcA08f296d9Ba0dc19Aa0E05D355365cE29A3205",
|
|
25
|
+
/** ERC-20 approval target. Use quote.tx.to when submitting a swap. */
|
|
26
|
+
router: "0x8730C3e2cF2c8CDa8E6166837A1Ed26f46aa9E59",
|
|
27
|
+
routerView: "0xFF6b56d3F444eB5b7FA1db047F57140C84810376",
|
|
28
|
+
uniswapV2Adapter: "0x7a14d7A8509a66209D4332843b983b29bF5604A4",
|
|
29
|
+
uniswapV3Adapter: "0xbcA08f296d9Ba0dc19Aa0E05D355365cE29A3205",
|
|
30
30
|
uniswapV4Adapter: "0x754dDCD05aFbAd1cc7Bc42B9268EB586F579E7F6",
|
|
31
|
+
limitOrder: "0x752c50DDd3B426cAE3D7A995F313Ac74ac6B0230",
|
|
32
|
+
nativeEthFlow: "0x029FfC6aF9112eA078f1D6f4a98826DDB2136cf6",
|
|
33
|
+
limitOrderAdapter: "0x412F625072c10e58C619D1e0b3C95cd3d5689871",
|
|
34
|
+
limitOrderAdapterIndex: 3,
|
|
31
35
|
} as const;
|
|
32
36
|
|
|
33
|
-
/**
|
|
34
|
-
export const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
/** Canonical Uniswap V4 singleton and periphery deployments. */
|
|
40
|
-
v4PoolManager: "0x8366a39cc670b4001a1121b8f6a443a643e40951",
|
|
41
|
-
v4PositionDescriptor: "0x9639443158e8c5efa35bd45287bf2effd3d8dc06",
|
|
42
|
-
v4PositionManager: "0x58daec3116aae6d93017baaea7749052e8a04fa7",
|
|
43
|
-
v4Quoter: "0x8dc178efb8111bb0973dd9d722ebeff267c98f94",
|
|
44
|
-
v4StateView: "0xf3334192d15450cdd385c8b70e03f9a6bd9e673b",
|
|
45
|
-
v4UniversalRouter: "0x8876789976decbfcbbbe364623c63652db8c0904",
|
|
46
|
-
permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
37
|
+
/** EIP-712 domain used for Robinhood ERC-20 limit-order signatures. */
|
|
38
|
+
export const ROBINHOOD_LIMIT_ORDER_EIP712_DOMAIN = {
|
|
39
|
+
name: "SwitchLimitOrder",
|
|
40
|
+
version: "2",
|
|
41
|
+
chainId: ROBINHOOD_CHAIN.id,
|
|
42
|
+
verifyingContract: ROBINHOOD_SWITCH_CONTRACTS.limitOrder,
|
|
47
43
|
} as const;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
44
|
+
|
|
45
|
+
/** Uniswap contracts used by the Robinhood Switch deployment. */
|
|
46
|
+
export const ROBINHOOD_UNISWAP_CONTRACTS = {
|
|
47
|
+
v2Factory: "0x8bcEaA40B9AcdfAedF85AdF4FF01F5Ad6517937f",
|
|
48
|
+
v3Factory: "0x1f7d7550B1b028f7571E69A784071F0205FD2EfA",
|
|
49
|
+
v3QuoterV2: "0x33e885eD0Ec9bF04EcfB19341582aADCb4c8A9E7",
|
|
50
|
+
v3SwapRouter02: "0xCaf681a66D020601342297493863E78C959E5cb2",
|
|
51
|
+
/** Canonical Uniswap V4 singleton and periphery deployments. */
|
|
52
|
+
v4PoolManager: "0x8366a39cc670b4001a1121b8f6a443a643e40951",
|
|
53
|
+
v4PositionDescriptor: "0x9639443158e8c5efa35bd45287bf2effd3d8dc06",
|
|
54
|
+
v4PositionManager: "0x58daec3116aae6d93017baaea7749052e8a04fa7",
|
|
55
|
+
v4Quoter: "0x8dc178efb8111bb0973dd9d722ebeff267c98f94",
|
|
56
|
+
v4StateView: "0xf3334192d15450cdd385c8b70e03f9a6bd9e673b",
|
|
57
|
+
v4UniversalRouter: "0x8876789976decbfcbbbe364623c63652db8c0904",
|
|
58
|
+
permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
59
|
+
} as const;
|
|
60
|
+
|
|
61
|
+
export interface RobinhoodToken {
|
|
62
|
+
readonly address: string;
|
|
63
|
+
readonly symbol: string;
|
|
64
|
+
readonly name: string;
|
|
65
|
+
readonly decimals: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Tokens in the Switch Robinhood frontend's curated list.
|
|
70
|
+
*
|
|
71
|
+
* Community-token addresses must never be selected by symbol alone; clones
|
|
72
|
+
* can share the same symbol. The addresses, symbols, and decimals below were
|
|
73
|
+
* checked against Robinhood Chain on 2026-07-11.
|
|
74
|
+
*/
|
|
75
|
+
export const ROBINHOOD_TOKENS = {
|
|
76
|
+
WETH: {
|
|
77
|
+
address: "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
|
|
78
|
+
symbol: "WETH",
|
|
79
|
+
name: "Wrapped Ether",
|
|
80
|
+
decimals: 18,
|
|
81
|
+
},
|
|
82
|
+
USDG: {
|
|
83
|
+
address: "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
|
|
84
|
+
symbol: "USDG",
|
|
85
|
+
name: "Global Dollar",
|
|
86
|
+
decimals: 6,
|
|
87
|
+
},
|
|
88
|
+
VIRTUAL: {
|
|
89
|
+
address: "0xc6911796042b15d7Fa4F6CDe69e245DdCd3d9c31",
|
|
90
|
+
symbol: "VIRTUAL",
|
|
91
|
+
name: "Virtuals Protocol",
|
|
92
|
+
decimals: 18,
|
|
93
|
+
},
|
|
94
|
+
CASHCAT: {
|
|
95
|
+
address: "0x020bfC650A365f8BB26819deAAbF3E21291018b4",
|
|
96
|
+
symbol: "CASHCAT",
|
|
97
|
+
name: "Cash Cat",
|
|
98
|
+
decimals: 18,
|
|
99
|
+
},
|
|
100
|
+
WALLET: {
|
|
101
|
+
address: "0x0339f5459FC690aC85F1782e15782A151b4A9E1b",
|
|
102
|
+
symbol: "WALLET",
|
|
103
|
+
name: "Robinhood Wallet",
|
|
104
|
+
decimals: 18,
|
|
105
|
+
},
|
|
94
106
|
SEEDCOIN: {
|
|
95
|
-
address: "
|
|
96
|
-
symbol: "
|
|
97
|
-
name: "
|
|
98
|
-
decimals: 18,
|
|
99
|
-
},
|
|
100
|
-
JUGGERNAUT: {
|
|
101
|
-
address: "0xD7321801CAae694090694Ff55A9323139F043B88",
|
|
102
|
-
symbol: "JUGGERNAUT",
|
|
103
|
-
name: "The Juggernaut",
|
|
104
|
-
decimals: 18,
|
|
105
|
-
},
|
|
106
|
-
HOODRAT: {
|
|
107
|
-
address: "0x8e62F281f282686fCa6dCB39288069a93fC23F1c",
|
|
108
|
-
symbol: "HOODRAT",
|
|
109
|
-
name: "Hoodrat",
|
|
110
|
-
decimals: 18,
|
|
111
|
-
},
|
|
112
|
-
DIH: {
|
|
113
|
-
address: "0x17bb0C898254406b1Ea2e8E99B0C263e26c9E4a4",
|
|
114
|
-
symbol: "DIH",
|
|
115
|
-
name: "Dog In Hood",
|
|
116
|
-
decimals: 18,
|
|
117
|
-
},
|
|
118
|
-
KITSU: {
|
|
119
|
-
address: "0x8d4dFaaA4198b6486E0293Fec914C2B6a821D4DC",
|
|
120
|
-
symbol: "KITSU",
|
|
121
|
-
name: "KITSU",
|
|
107
|
+
address: "0x58f693A30F124E59b125F7c7b837b0F6bbAF5a45",
|
|
108
|
+
symbol: "SEEDCOIN",
|
|
109
|
+
name: "Seedcoin",
|
|
110
|
+
decimals: 18,
|
|
111
|
+
},
|
|
112
|
+
JUGGERNAUT: {
|
|
113
|
+
address: "0xD7321801CAae694090694Ff55A9323139F043B88",
|
|
114
|
+
symbol: "JUGGERNAUT",
|
|
115
|
+
name: "The Juggernaut",
|
|
116
|
+
decimals: 18,
|
|
117
|
+
},
|
|
118
|
+
HOODRAT: {
|
|
119
|
+
address: "0x8e62F281f282686fCa6dCB39288069a93fC23F1c",
|
|
120
|
+
symbol: "HOODRAT",
|
|
121
|
+
name: "Hoodrat",
|
|
122
|
+
decimals: 18,
|
|
123
|
+
},
|
|
124
|
+
DIH: {
|
|
125
|
+
address: "0x17bb0C898254406b1Ea2e8E99B0C263e26c9E4a4",
|
|
126
|
+
symbol: "DIH",
|
|
127
|
+
name: "Dog In Hood",
|
|
128
|
+
decimals: 18,
|
|
129
|
+
},
|
|
130
|
+
KITSU: {
|
|
131
|
+
address: "0x8d4dFaaA4198b6486E0293Fec914C2B6a821D4DC",
|
|
132
|
+
symbol: "KITSU",
|
|
133
|
+
name: "KITSU",
|
|
134
|
+
decimals: 18,
|
|
135
|
+
},
|
|
136
|
+
WEN: {
|
|
137
|
+
address: "0xA80eb66b3E0CF66ccB46f8b8C9e7ff5803eEb820",
|
|
138
|
+
symbol: "WEN",
|
|
139
|
+
name: "Wen Lambo",
|
|
140
|
+
decimals: 18,
|
|
141
|
+
},
|
|
142
|
+
REPE: {
|
|
143
|
+
address: "0x5266eeafF092D6136AB63D18B975A60a0Cc0C8f7",
|
|
144
|
+
symbol: "REPE",
|
|
145
|
+
name: "Robinhood Pepe",
|
|
146
|
+
decimals: 18,
|
|
147
|
+
},
|
|
148
|
+
TENDIES: {
|
|
149
|
+
address: "0x45242320DBB855EeA8Fd36804C6487E10E97FCF9",
|
|
150
|
+
symbol: "TENDIES",
|
|
151
|
+
name: "TENDIES",
|
|
152
|
+
decimals: 18,
|
|
153
|
+
},
|
|
154
|
+
GME: {
|
|
155
|
+
address: "0x7e86381A763F0Ecca2bDF27C54eAC403ddD48123",
|
|
156
|
+
symbol: "GME",
|
|
157
|
+
name: "GameStop",
|
|
158
|
+
decimals: 18,
|
|
159
|
+
},
|
|
160
|
+
TOKEN_4663: {
|
|
161
|
+
address: "0xd4052415613B34Af236024B895574c467f65b6dD",
|
|
162
|
+
symbol: "4663",
|
|
163
|
+
name: "4663",
|
|
164
|
+
decimals: 18,
|
|
165
|
+
},
|
|
166
|
+
MARIAN: {
|
|
167
|
+
address: "0x01637b14B7378B99dE75A64d50656d98488D9a4d",
|
|
168
|
+
symbol: "MARIAN",
|
|
169
|
+
name: "Lady Marian",
|
|
122
170
|
decimals: 18,
|
|
123
171
|
},
|
|
124
|
-
|
|
125
|
-
address: "
|
|
126
|
-
symbol: "
|
|
127
|
-
name: "
|
|
172
|
+
INDEX: {
|
|
173
|
+
address: "0x56910D4409F3a0C78C64DD8D0545FF0705389870",
|
|
174
|
+
symbol: "Index",
|
|
175
|
+
name: "The Index",
|
|
128
176
|
decimals: 18,
|
|
129
177
|
},
|
|
130
|
-
|
|
131
|
-
address: "
|
|
132
|
-
symbol: "
|
|
133
|
-
name: "
|
|
178
|
+
VEX: {
|
|
179
|
+
address: "0x8Ff92566f2e81BDd68EDfAa8cde73942A723796b",
|
|
180
|
+
symbol: "VEX",
|
|
181
|
+
name: "ProjectVex",
|
|
134
182
|
decimals: 18,
|
|
135
183
|
},
|
|
136
|
-
|
|
137
|
-
address: "
|
|
138
|
-
symbol: "
|
|
139
|
-
name: "
|
|
184
|
+
HOODIE: {
|
|
185
|
+
address: "0xC72c01AAB5f5678dc1d6f5C6d2B417d91D402Ba3",
|
|
186
|
+
symbol: "HOODIE",
|
|
187
|
+
name: "HOODIE",
|
|
140
188
|
decimals: 18,
|
|
141
189
|
},
|
|
142
|
-
|
|
143
|
-
address: "
|
|
144
|
-
symbol: "
|
|
145
|
-
name: "
|
|
190
|
+
WISHBONE: {
|
|
191
|
+
address: "0x77581054581B9c525E7dd7a0155DE43867532d03",
|
|
192
|
+
symbol: "WISHBONE",
|
|
193
|
+
name: "WISHBONE",
|
|
146
194
|
decimals: 18,
|
|
147
195
|
},
|
|
148
|
-
|
|
149
|
-
address: "
|
|
150
|
-
symbol: "
|
|
151
|
-
name: "
|
|
196
|
+
VLAD: {
|
|
197
|
+
address: "0x31BE8f7485e36928C9De86566c62da82d4B6BF81",
|
|
198
|
+
symbol: "VLAD",
|
|
199
|
+
name: "The Green Bull",
|
|
152
200
|
decimals: 18,
|
|
153
201
|
},
|
|
154
|
-
|
|
155
|
-
address: "
|
|
156
|
-
symbol: "
|
|
157
|
-
name: "
|
|
202
|
+
AEON: {
|
|
203
|
+
address: "0xd4c93eD1843606f92CccA078941f3d52A585982f",
|
|
204
|
+
symbol: "AEON",
|
|
205
|
+
name: "Aeon",
|
|
158
206
|
decimals: 18,
|
|
159
207
|
},
|
|
160
208
|
} as const satisfies Readonly<Record<string, RobinhoodToken>>;
|
|
161
|
-
|
|
162
|
-
/** Exact ERC-20 ordering used by the Switch Robinhood token dropdown. */
|
|
163
|
-
export const ROBINHOOD_FRONTEND_TOKEN_LIST = [
|
|
164
|
-
ROBINHOOD_TOKENS.WETH,
|
|
165
|
-
ROBINHOOD_TOKENS.USDG,
|
|
166
|
-
ROBINHOOD_TOKENS.VIRTUAL,
|
|
167
|
-
ROBINHOOD_TOKENS.CASHCAT,
|
|
168
|
-
ROBINHOOD_TOKENS.WALLET,
|
|
169
|
-
ROBINHOOD_TOKENS.SEEDCOIN,
|
|
170
|
-
ROBINHOOD_TOKENS.JUGGERNAUT,
|
|
171
|
-
ROBINHOOD_TOKENS.HOODRAT,
|
|
172
|
-
ROBINHOOD_TOKENS.DIH,
|
|
173
|
-
ROBINHOOD_TOKENS.KITSU,
|
|
174
|
-
ROBINHOOD_TOKENS.WEN,
|
|
175
|
-
ROBINHOOD_TOKENS.REPE,
|
|
176
|
-
ROBINHOOD_TOKENS.TENDIES,
|
|
177
|
-
ROBINHOOD_TOKENS.GME,
|
|
209
|
+
|
|
210
|
+
/** Exact ERC-20 ordering used by the Switch Robinhood token dropdown. */
|
|
211
|
+
export const ROBINHOOD_FRONTEND_TOKEN_LIST = [
|
|
212
|
+
ROBINHOOD_TOKENS.WETH,
|
|
213
|
+
ROBINHOOD_TOKENS.USDG,
|
|
214
|
+
ROBINHOOD_TOKENS.VIRTUAL,
|
|
215
|
+
ROBINHOOD_TOKENS.CASHCAT,
|
|
216
|
+
ROBINHOOD_TOKENS.WALLET,
|
|
217
|
+
ROBINHOOD_TOKENS.SEEDCOIN,
|
|
218
|
+
ROBINHOOD_TOKENS.JUGGERNAUT,
|
|
219
|
+
ROBINHOOD_TOKENS.HOODRAT,
|
|
220
|
+
ROBINHOOD_TOKENS.DIH,
|
|
221
|
+
ROBINHOOD_TOKENS.KITSU,
|
|
222
|
+
ROBINHOOD_TOKENS.WEN,
|
|
223
|
+
ROBINHOOD_TOKENS.REPE,
|
|
224
|
+
ROBINHOOD_TOKENS.TENDIES,
|
|
225
|
+
ROBINHOOD_TOKENS.GME,
|
|
178
226
|
ROBINHOOD_TOKENS.TOKEN_4663,
|
|
179
227
|
ROBINHOOD_TOKENS.MARIAN,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
228
|
+
ROBINHOOD_TOKENS.INDEX,
|
|
229
|
+
ROBINHOOD_TOKENS.VEX,
|
|
230
|
+
ROBINHOOD_TOKENS.HOODIE,
|
|
231
|
+
ROBINHOOD_TOKENS.WISHBONE,
|
|
232
|
+
ROBINHOOD_TOKENS.VLAD,
|
|
233
|
+
ROBINHOOD_TOKENS.AEON,
|
|
234
|
+
] as const satisfies readonly RobinhoodToken[];
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Tokens used to initialize the Robinhood swap UI.
|
|
238
|
+
*
|
|
239
|
+
* The current default pair is native ETH -> USDG. WETH remains in this set so
|
|
240
|
+
* native/wrapped lookup and token selection use the canonical deployment.
|
|
241
|
+
*/
|
|
242
|
+
export const ROBINHOOD_FRONTEND_DEFAULT_TOKENS = [
|
|
243
|
+
{
|
|
244
|
+
address: ROBINHOOD_NATIVE_ETH,
|
|
245
|
+
symbol: "ETH",
|
|
246
|
+
name: "Ether",
|
|
247
|
+
decimals: 18,
|
|
248
|
+
},
|
|
195
249
|
ROBINHOOD_TOKENS.WETH,
|
|
196
250
|
ROBINHOOD_TOKENS.USDG,
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
251
|
+
ROBINHOOD_TOKENS.VIRTUAL,
|
|
252
|
+
ROBINHOOD_TOKENS.CASHCAT,
|
|
253
|
+
ROBINHOOD_TOKENS.INDEX,
|
|
254
|
+
] as const satisfies readonly RobinhoodToken[];
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Production trusted-hop addresses, ordered by routing usefulness.
|
|
258
|
+
*
|
|
259
|
+
* The 2026-07-16 audit combined Dexscreener pool connectivity with Switch tax
|
|
260
|
+
* simulation, then required multiple meaningful liquidity corridors. VEX is
|
|
261
|
+
* selectable but excluded because it is taxed; INDEX is excluded because its
|
|
262
|
+
* dominant liquidity currently depends on unsupported V4 hooks. Keep this
|
|
263
|
+
* list synchronized with the Robinhood backend and operator bot.
|
|
264
|
+
*/
|
|
265
|
+
export const ROBINHOOD_TRUSTED_INTERMEDIATES = [
|
|
266
|
+
ROBINHOOD_TOKENS.WETH.address,
|
|
267
|
+
ROBINHOOD_TOKENS.USDG.address,
|
|
210
268
|
ROBINHOOD_TOKENS.VIRTUAL.address,
|
|
211
269
|
ROBINHOOD_TOKENS.CASHCAT.address,
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
ROBINHOOD_TOKENS.WETH.address,
|
|
217
|
-
ROBINHOOD_TOKENS.USDG.address,
|
|
270
|
+
ROBINHOOD_TOKENS.HOODRAT.address,
|
|
271
|
+
ROBINHOOD_TOKENS.TENDIES.address,
|
|
272
|
+
ROBINHOOD_TOKENS.JUGGERNAUT.address,
|
|
273
|
+
ROBINHOOD_TOKENS.MARIAN.address,
|
|
218
274
|
ROBINHOOD_TOKENS.WALLET.address,
|
|
219
|
-
ROBINHOOD_TOKENS.SEEDCOIN.address,
|
|
220
|
-
ROBINHOOD_TOKENS.CASHCAT.address,
|
|
221
275
|
] as const;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (
|
|
266
|
-
if (
|
|
267
|
-
if (
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
if (params.
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
276
|
+
|
|
277
|
+
/** Preferred Robinhood fee tokens, from highest to lowest priority. */
|
|
278
|
+
export const ROBINHOOD_FEE_TOKEN_PRIORITY = [
|
|
279
|
+
ROBINHOOD_TOKENS.WETH.address,
|
|
280
|
+
ROBINHOOD_TOKENS.USDG.address,
|
|
281
|
+
ROBINHOOD_TOKENS.WALLET.address,
|
|
282
|
+
ROBINHOOD_TOKENS.SEEDCOIN.address,
|
|
283
|
+
ROBINHOOD_TOKENS.CASHCAT.address,
|
|
284
|
+
] as const;
|
|
285
|
+
|
|
286
|
+
const ROBINHOOD_FEE_PRIORITY_BY_ADDRESS = new Map<string, number>(
|
|
287
|
+
ROBINHOOD_FEE_TOKEN_PRIORITY.map((address, index) => [
|
|
288
|
+
address.toLowerCase(),
|
|
289
|
+
index + 1,
|
|
290
|
+
]),
|
|
291
|
+
);
|
|
292
|
+
ROBINHOOD_FEE_PRIORITY_BY_ADDRESS.set(
|
|
293
|
+
ROBINHOOD_NATIVE_ETH.toLowerCase(),
|
|
294
|
+
1,
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
/** Minimum directional tax data required for fee-mode selection. */
|
|
298
|
+
export interface RobinhoodTaxInfo {
|
|
299
|
+
isTaxToken: boolean;
|
|
300
|
+
buyTaxBps: number;
|
|
301
|
+
sellTaxBps: number;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Select the safer/preferred fee side for a Robinhood swap.
|
|
306
|
+
*
|
|
307
|
+
* Tax safety takes precedence over fee-token preference. Native ETH is treated
|
|
308
|
+
* as equivalent to WETH. `false` means fee on input; `true` means fee on output.
|
|
309
|
+
*/
|
|
310
|
+
export function selectRobinhoodFeeOnOutput(
|
|
311
|
+
from: string,
|
|
312
|
+
to: string,
|
|
313
|
+
fromTax: RobinhoodTaxInfo,
|
|
314
|
+
toTax: RobinhoodTaxInfo,
|
|
315
|
+
): boolean {
|
|
316
|
+
const inputHasSellTax = fromTax.isTaxToken && fromTax.sellTaxBps > 0;
|
|
317
|
+
const outputHasBuyTax = toTax.isTaxToken && toTax.buyTaxBps > 0;
|
|
318
|
+
|
|
319
|
+
if (inputHasSellTax && outputHasBuyTax) return false;
|
|
320
|
+
if (outputHasBuyTax) return false;
|
|
321
|
+
if (inputHasSellTax) return true;
|
|
322
|
+
|
|
323
|
+
const inputPriority =
|
|
324
|
+
ROBINHOOD_FEE_PRIORITY_BY_ADDRESS.get(from.toLowerCase()) ?? Infinity;
|
|
325
|
+
const outputPriority =
|
|
326
|
+
ROBINHOOD_FEE_PRIORITY_BY_ADDRESS.get(to.toLowerCase()) ?? Infinity;
|
|
327
|
+
|
|
328
|
+
if (outputPriority < inputPriority) return true;
|
|
329
|
+
if (inputPriority < outputPriority) return false;
|
|
330
|
+
if (inputPriority !== Infinity) return true;
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export interface RobinhoodQuoteParams {
|
|
335
|
+
from: string;
|
|
336
|
+
to: string;
|
|
337
|
+
/** Raw integer input amount in the input token's smallest unit. */
|
|
338
|
+
amount: string | bigint;
|
|
339
|
+
sender?: string;
|
|
340
|
+
receiver?: string;
|
|
341
|
+
/** Slippage in basis points. */
|
|
342
|
+
slippage?: number;
|
|
343
|
+
/** Partner fee in basis points. */
|
|
344
|
+
fee?: number;
|
|
345
|
+
partnerAddress?: string;
|
|
346
|
+
feeOnOutput?: boolean;
|
|
347
|
+
adapters?: string | readonly number[];
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/** Build a Robinhood quote URL with the required network value included. */
|
|
351
|
+
export function buildRobinhoodQuoteUrl(
|
|
352
|
+
params: RobinhoodQuoteParams,
|
|
353
|
+
apiBase: string = API_BASE,
|
|
354
|
+
): string {
|
|
355
|
+
const query = new URLSearchParams({
|
|
356
|
+
network: ROBINHOOD_NETWORK,
|
|
357
|
+
from: params.from,
|
|
358
|
+
to: params.to,
|
|
359
|
+
amount: params.amount.toString(),
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
if (params.sender) query.set("sender", params.sender);
|
|
363
|
+
if (params.receiver) query.set("receiver", params.receiver);
|
|
364
|
+
if (params.slippage !== undefined) {
|
|
365
|
+
query.set("slippage", params.slippage.toString());
|
|
366
|
+
}
|
|
367
|
+
if (params.fee !== undefined) query.set("fee", params.fee.toString());
|
|
368
|
+
if (params.partnerAddress) {
|
|
369
|
+
query.set("partnerAddress", params.partnerAddress);
|
|
370
|
+
}
|
|
371
|
+
if (params.feeOnOutput !== undefined) {
|
|
372
|
+
query.set("feeOnOutput", params.feeOnOutput.toString());
|
|
373
|
+
}
|
|
374
|
+
if (params.adapters !== undefined) {
|
|
375
|
+
query.set(
|
|
376
|
+
"adapters",
|
|
377
|
+
Array.isArray(params.adapters)
|
|
378
|
+
? params.adapters.join(",")
|
|
379
|
+
: String(params.adapters),
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return `${apiBase.replace(/\/$/, "")}/swap/quote?${query.toString()}`;
|
|
384
|
+
}
|