@switch-win/sdk 1.2.8 → 1.3.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 +26 -0
- package/GASLESS.md +407 -0
- package/LIMIT-ORDERS.md +212 -198
- package/README.md +131 -105
- package/ROBINHOOD.md +201 -198
- package/abi/GaslessSwitchV2ABI.json +1095 -0
- package/dist/constants.d.ts +276 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +403 -0
- package/dist/constants.js.map +1 -0
- package/dist/gasless-client.d.ts +81 -0
- package/dist/gasless-client.d.ts.map +1 -0
- package/dist/gasless-client.js +467 -0
- package/dist/gasless-client.js.map +1 -0
- package/dist/gasless-index.d.ts +5 -0
- package/dist/gasless-index.d.ts.map +1 -0
- package/dist/gasless-index.js +5 -0
- package/dist/gasless-index.js.map +1 -0
- package/dist/gasless-operators.d.ts +32 -0
- package/dist/gasless-operators.d.ts.map +1 -0
- package/dist/gasless-operators.js +132 -0
- package/dist/gasless-operators.js.map +1 -0
- package/dist/gasless-store.d.ts +18 -0
- package/dist/gasless-store.d.ts.map +1 -0
- package/dist/gasless-store.js +83 -0
- package/dist/gasless-store.js.map +1 -0
- package/dist/gasless-types.d.ts +218 -0
- package/dist/gasless-types.d.ts.map +1 -0
- package/dist/gasless-types.js +2 -0
- package/dist/gasless-types.js.map +1 -0
- package/dist/gasless.d.ts +135 -0
- package/dist/gasless.d.ts.map +1 -0
- package/dist/gasless.js +513 -0
- package/dist/gasless.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/limit-orders.d.ts +440 -0
- package/dist/limit-orders.d.ts.map +1 -0
- package/dist/limit-orders.js +387 -0
- package/dist/limit-orders.js.map +1 -0
- package/dist/networks/index.d.ts +3 -0
- package/dist/networks/index.d.ts.map +1 -0
- package/dist/networks/index.js +2 -0
- package/dist/networks/index.js.map +1 -0
- package/dist/networks/robinhood.d.ts +536 -0
- package/dist/networks/robinhood.d.ts.map +1 -0
- package/dist/networks/robinhood.js +489 -0
- package/dist/networks/robinhood.js.map +1 -0
- package/dist/types.d.ts +436 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/examples/gasless-nextjs-proxy.ts +87 -0
- package/examples/gasless-operator.ts +76 -0
- package/examples/gasless-swap.ts +170 -0
- package/examples/limit-order-ethers.ts +195 -0
- package/examples/nextjs-proxy.ts +82 -0
- package/examples/react-hooks.tsx +396 -0
- package/examples/swap-ethers.ts +209 -0
- package/examples/swap-web3py.py +267 -0
- package/package.json +53 -12
- package/src/constants.ts +181 -178
- package/src/gasless-client.ts +823 -0
- package/src/gasless-index.ts +4 -0
- package/src/gasless-operators.ts +227 -0
- package/src/gasless-store.ts +137 -0
- package/src/gasless-types.ts +258 -0
- package/src/gasless.ts +756 -0
- package/src/index.ts +69 -63
- package/src/limit-orders.ts +206 -195
- package/src/types.ts +80 -55
package/src/limit-orders.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Switch Limit Orders (V2) — Helper Functions
|
|
3
3
|
*
|
|
4
4
|
* Provides a complete toolkit for creating, signing, submitting, querying,
|
|
5
|
-
* and cancelling EIP-712 signed limit orders on PulseChain and Robinhood
|
|
6
|
-
* Chain.
|
|
5
|
+
* and cancelling EIP-712 signed limit orders on PulseChain and Robinhood
|
|
6
|
+
* Chain.
|
|
7
7
|
*
|
|
8
8
|
* ## How it works
|
|
9
9
|
*
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
* 2. **Sign** via EIP-712 with your wallet (ethers.js `signTypedData`)
|
|
12
12
|
* 3. **Submit** the signed order to the Switch backend with `submitLimitOrder()`
|
|
13
13
|
* 4. The Switch filler bot monitors active orders and fills them when profitable
|
|
14
|
-
* 5. **Cancel** an order on-chain via `invalidateNonce()`; the backend indexer
|
|
15
|
-
* observes the cancellation event
|
|
14
|
+
* 5. **Cancel** an order on-chain via `invalidateNonce()`; the backend indexer
|
|
15
|
+
* observes the cancellation event
|
|
16
16
|
*
|
|
17
17
|
* @example
|
|
18
18
|
* ```ts
|
|
@@ -28,8 +28,8 @@ import type {
|
|
|
28
28
|
ListLimitOrdersResponse,
|
|
29
29
|
LimitOrderRecord,
|
|
30
30
|
LimitOrderPair,
|
|
31
|
-
LimitOrderStats,
|
|
32
|
-
LimitOrderConfigResponse,
|
|
31
|
+
LimitOrderStats,
|
|
32
|
+
LimitOrderConfigResponse,
|
|
33
33
|
LimitOrderStatus,
|
|
34
34
|
ErrorResponse,
|
|
35
35
|
} from "./types.js";
|
|
@@ -43,15 +43,21 @@ import {
|
|
|
43
43
|
SWITCH_LIMIT_ORDER,
|
|
44
44
|
SWITCH_ROUTER,
|
|
45
45
|
SWITCH_PLS_FLOW,
|
|
46
|
-
WPLS,
|
|
47
|
-
NATIVE_PLS,
|
|
48
|
-
} from "./constants.js";
|
|
49
|
-
import {
|
|
50
|
-
ROBINHOOD_CHAIN,
|
|
51
|
-
ROBINHOOD_NATIVE_ETH,
|
|
52
|
-
ROBINHOOD_SWITCH_CONTRACTS,
|
|
53
|
-
ROBINHOOD_TOKENS,
|
|
54
|
-
} from "./networks/robinhood.js";
|
|
46
|
+
WPLS,
|
|
47
|
+
NATIVE_PLS,
|
|
48
|
+
} from "./constants.js";
|
|
49
|
+
import {
|
|
50
|
+
ROBINHOOD_CHAIN,
|
|
51
|
+
ROBINHOOD_NATIVE_ETH,
|
|
52
|
+
ROBINHOOD_SWITCH_CONTRACTS,
|
|
53
|
+
ROBINHOOD_TOKENS,
|
|
54
|
+
} from "./networks/robinhood.js";
|
|
55
|
+
import { GASLESS_DEPLOYMENTS, GASLESS_LEGACY_CONTRACTS } from "./gasless.js";
|
|
56
|
+
|
|
57
|
+
const gaslessContracts = new Set([
|
|
58
|
+
...Object.values(GASLESS_DEPLOYMENTS).map(deployment => deployment.contract),
|
|
59
|
+
...Object.values(GASLESS_LEGACY_CONTRACTS).flat(),
|
|
60
|
+
].map(address => address.toLowerCase()));
|
|
55
61
|
|
|
56
62
|
// ── Re-export EIP-712 constants for convenience ─────────────────────────────
|
|
57
63
|
|
|
@@ -117,8 +123,8 @@ export interface BuildLimitOrderOptions {
|
|
|
117
123
|
* one tax. Avoids the double sell-tax of maker → LO → pool.)
|
|
118
124
|
* - **Tax output token** → set `feeOnOutput: false` (default)
|
|
119
125
|
* (Output goes directly to recipient in one transfer.)
|
|
120
|
-
* - **Both tokens tax** → use `feeOnOutput: false`; execution is restricted
|
|
121
|
-
* to tax-compatible Uniswap V2 routing.
|
|
126
|
+
* - **Both tokens tax** → use `feeOnOutput: false`; execution is restricted
|
|
127
|
+
* to tax-compatible Uniswap V2 routing.
|
|
122
128
|
*
|
|
123
129
|
* **Bottom line:** Use `feeOnOutput: false` (default) unless the input
|
|
124
130
|
* token is a tax token. This gives operators maximum flexibility and
|
|
@@ -192,16 +198,19 @@ export function buildLimitOrder(options: BuildLimitOrderOptions): LimitOrderPara
|
|
|
192
198
|
* const signature = await signer._signTypedData(domain, types, order);
|
|
193
199
|
* ```
|
|
194
200
|
*/
|
|
195
|
-
export function getEIP712SigningParams(
|
|
196
|
-
limitOrderContract?: string,
|
|
197
|
-
chainId: number = 369,
|
|
198
|
-
) {
|
|
201
|
+
export function getEIP712SigningParams(
|
|
202
|
+
limitOrderContract?: string,
|
|
203
|
+
chainId: number = 369,
|
|
204
|
+
) {
|
|
205
|
+
if (limitOrderContract && gaslessContracts.has(limitOrderContract.toLowerCase())) {
|
|
206
|
+
throw new Error("GaslessSwitch requires its dedicated signing domain. Use getGaslessSigningParams() for V2.");
|
|
207
|
+
}
|
|
199
208
|
if (limitOrderContract) {
|
|
200
209
|
return {
|
|
201
210
|
domain: {
|
|
202
211
|
name: "SwitchLimitOrder" as const,
|
|
203
212
|
version: "2" as const,
|
|
204
|
-
chainId,
|
|
213
|
+
chainId,
|
|
205
214
|
verifyingContract: limitOrderContract,
|
|
206
215
|
},
|
|
207
216
|
types: LIMIT_ORDER_EIP712_TYPES,
|
|
@@ -239,8 +248,8 @@ export function getApprovalTarget(limitOrderContract?: string): string {
|
|
|
239
248
|
*
|
|
240
249
|
* @returns The SwitchRouter contract address
|
|
241
250
|
*/
|
|
242
|
-
export function getRouterApprovalTarget(routerContract?: string): string {
|
|
243
|
-
return routerContract || SWITCH_ROUTER;
|
|
251
|
+
export function getRouterApprovalTarget(routerContract?: string): string {
|
|
252
|
+
return routerContract || SWITCH_ROUTER;
|
|
244
253
|
}
|
|
245
254
|
|
|
246
255
|
/**
|
|
@@ -249,15 +258,15 @@ export function getRouterApprovalTarget(routerContract?: string): string {
|
|
|
249
258
|
* Returns `true` only if `tokenOut` is WPLS (the output will be unwrapped
|
|
250
259
|
* to native PLS by the contract).
|
|
251
260
|
*/
|
|
252
|
-
export function shouldUnwrapOutput(
|
|
253
|
-
tokenOut: string,
|
|
254
|
-
wrappedNativeToken: string = WPLS,
|
|
255
|
-
): boolean {
|
|
256
|
-
return tokenOut.toLowerCase() === wrappedNativeToken.toLowerCase();
|
|
261
|
+
export function shouldUnwrapOutput(
|
|
262
|
+
tokenOut: string,
|
|
263
|
+
wrappedNativeToken: string = WPLS,
|
|
264
|
+
): boolean {
|
|
265
|
+
return tokenOut.toLowerCase() === wrappedNativeToken.toLowerCase();
|
|
257
266
|
}
|
|
258
267
|
|
|
259
268
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
260
|
-
// Native-currency flow (SwitchPLSFlow ABI: PLS on PulseChain, ETH on Robinhood)
|
|
269
|
+
// Native-currency flow (SwitchPLSFlow ABI: PLS on PulseChain, ETH on Robinhood)
|
|
261
270
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
262
271
|
|
|
263
272
|
/**
|
|
@@ -268,95 +277,95 @@ export function shouldUnwrapOutput(
|
|
|
268
277
|
*
|
|
269
278
|
* @returns The SwitchPLSFlow contract address
|
|
270
279
|
*/
|
|
271
|
-
export function getPLSFlowAddress(nativeFlowContract?: string): string {
|
|
272
|
-
return nativeFlowContract || SWITCH_PLS_FLOW;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/** Networks supported by the shared Switch limit-order API. */
|
|
276
|
-
export type LimitOrderNetwork = "pulsechain" | "robinhood";
|
|
277
|
-
|
|
278
|
-
/** Complete deployment metadata needed to create or fill limit orders. */
|
|
279
|
-
export interface LimitOrderNetworkConfig {
|
|
280
|
-
network: LimitOrderNetwork;
|
|
281
|
-
chainId: number;
|
|
282
|
-
chainName: string;
|
|
283
|
-
nativeSymbol: "PLS" | "ETH";
|
|
284
|
-
nativeSentinel: string;
|
|
285
|
-
wrappedNativeToken: string;
|
|
286
|
-
routerContract: string;
|
|
287
|
-
limitOrderContract: string;
|
|
288
|
-
nativeFlowContract: string;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/** Static defaults. Prefer {@link fetchLimitOrderConfig} at application startup. */
|
|
292
|
-
export const LIMIT_ORDER_NETWORK_CONFIGS: Readonly<
|
|
293
|
-
Record<LimitOrderNetwork, LimitOrderNetworkConfig>
|
|
294
|
-
> = {
|
|
295
|
-
pulsechain: {
|
|
296
|
-
network: "pulsechain",
|
|
297
|
-
chainId: 369,
|
|
298
|
-
chainName: "PulseChain",
|
|
299
|
-
nativeSymbol: "PLS",
|
|
300
|
-
nativeSentinel: NATIVE_PLS,
|
|
301
|
-
wrappedNativeToken: WPLS,
|
|
302
|
-
routerContract: SWITCH_ROUTER,
|
|
303
|
-
limitOrderContract: SWITCH_LIMIT_ORDER,
|
|
304
|
-
nativeFlowContract: SWITCH_PLS_FLOW,
|
|
305
|
-
},
|
|
306
|
-
robinhood: {
|
|
307
|
-
network: "robinhood",
|
|
308
|
-
chainId: ROBINHOOD_CHAIN.id,
|
|
309
|
-
chainName: ROBINHOOD_CHAIN.name,
|
|
310
|
-
nativeSymbol: "ETH",
|
|
311
|
-
nativeSentinel: ROBINHOOD_NATIVE_ETH,
|
|
312
|
-
wrappedNativeToken: ROBINHOOD_TOKENS.WETH.address,
|
|
313
|
-
routerContract: ROBINHOOD_SWITCH_CONTRACTS.router,
|
|
314
|
-
limitOrderContract: ROBINHOOD_SWITCH_CONTRACTS.limitOrder,
|
|
315
|
-
nativeFlowContract: ROBINHOOD_SWITCH_CONTRACTS.nativeEthFlow,
|
|
316
|
-
},
|
|
317
|
-
} as const;
|
|
318
|
-
|
|
319
|
-
/** Return the static deployment defaults for a supported limit-order network. */
|
|
320
|
-
export function getLimitOrderNetworkConfig(
|
|
321
|
-
network: LimitOrderNetwork = "pulsechain",
|
|
322
|
-
): LimitOrderNetworkConfig {
|
|
323
|
-
return LIMIT_ORDER_NETWORK_CONFIGS[network];
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/** Build the correct EIP-712 signing domain for a supported network. */
|
|
327
|
-
export function getNetworkEIP712SigningParams(
|
|
328
|
-
network: LimitOrderNetwork,
|
|
329
|
-
limitOrderContract?: string,
|
|
330
|
-
) {
|
|
331
|
-
const config = getLimitOrderNetworkConfig(network);
|
|
332
|
-
return getEIP712SigningParams(
|
|
333
|
-
limitOrderContract ?? config.limitOrderContract,
|
|
334
|
-
config.chainId,
|
|
335
|
-
);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/** Resolve the maker's ERC-20 approval target for the selected fee mode. */
|
|
339
|
-
export function getLimitOrderApprovalTarget(
|
|
340
|
-
network: LimitOrderNetwork,
|
|
341
|
-
feeOnOutput: boolean,
|
|
342
|
-
overrides: { limitOrderContract?: string; routerContract?: string } = {},
|
|
343
|
-
): string {
|
|
344
|
-
const config = getLimitOrderNetworkConfig(network);
|
|
345
|
-
return feeOnOutput
|
|
346
|
-
? getRouterApprovalTarget(overrides.routerContract ?? config.routerContract)
|
|
347
|
-
: getApprovalTarget(overrides.limitOrderContract ?? config.limitOrderContract);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
export interface LimitOrderNetworkOptions {
|
|
351
|
-
network?: LimitOrderNetwork;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
function endpointForNetwork(endpoint: string, network?: string): string {
|
|
355
|
-
if (!network) return endpoint;
|
|
356
|
-
const url = new URL(endpoint);
|
|
357
|
-
url.searchParams.set("network", network);
|
|
358
|
-
return url.toString();
|
|
359
|
-
}
|
|
280
|
+
export function getPLSFlowAddress(nativeFlowContract?: string): string {
|
|
281
|
+
return nativeFlowContract || SWITCH_PLS_FLOW;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** Networks supported by the shared Switch limit-order API. */
|
|
285
|
+
export type LimitOrderNetwork = "pulsechain" | "robinhood";
|
|
286
|
+
|
|
287
|
+
/** Complete deployment metadata needed to create or fill limit orders. */
|
|
288
|
+
export interface LimitOrderNetworkConfig {
|
|
289
|
+
network: LimitOrderNetwork;
|
|
290
|
+
chainId: number;
|
|
291
|
+
chainName: string;
|
|
292
|
+
nativeSymbol: "PLS" | "ETH";
|
|
293
|
+
nativeSentinel: string;
|
|
294
|
+
wrappedNativeToken: string;
|
|
295
|
+
routerContract: string;
|
|
296
|
+
limitOrderContract: string;
|
|
297
|
+
nativeFlowContract: string;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** Static defaults. Prefer {@link fetchLimitOrderConfig} at application startup. */
|
|
301
|
+
export const LIMIT_ORDER_NETWORK_CONFIGS: Readonly<
|
|
302
|
+
Record<LimitOrderNetwork, LimitOrderNetworkConfig>
|
|
303
|
+
> = {
|
|
304
|
+
pulsechain: {
|
|
305
|
+
network: "pulsechain",
|
|
306
|
+
chainId: 369,
|
|
307
|
+
chainName: "PulseChain",
|
|
308
|
+
nativeSymbol: "PLS",
|
|
309
|
+
nativeSentinel: NATIVE_PLS,
|
|
310
|
+
wrappedNativeToken: WPLS,
|
|
311
|
+
routerContract: SWITCH_ROUTER,
|
|
312
|
+
limitOrderContract: SWITCH_LIMIT_ORDER,
|
|
313
|
+
nativeFlowContract: SWITCH_PLS_FLOW,
|
|
314
|
+
},
|
|
315
|
+
robinhood: {
|
|
316
|
+
network: "robinhood",
|
|
317
|
+
chainId: ROBINHOOD_CHAIN.id,
|
|
318
|
+
chainName: ROBINHOOD_CHAIN.name,
|
|
319
|
+
nativeSymbol: "ETH",
|
|
320
|
+
nativeSentinel: ROBINHOOD_NATIVE_ETH,
|
|
321
|
+
wrappedNativeToken: ROBINHOOD_TOKENS.WETH.address,
|
|
322
|
+
routerContract: ROBINHOOD_SWITCH_CONTRACTS.router,
|
|
323
|
+
limitOrderContract: ROBINHOOD_SWITCH_CONTRACTS.limitOrder,
|
|
324
|
+
nativeFlowContract: ROBINHOOD_SWITCH_CONTRACTS.nativeEthFlow,
|
|
325
|
+
},
|
|
326
|
+
} as const;
|
|
327
|
+
|
|
328
|
+
/** Return the static deployment defaults for a supported limit-order network. */
|
|
329
|
+
export function getLimitOrderNetworkConfig(
|
|
330
|
+
network: LimitOrderNetwork = "pulsechain",
|
|
331
|
+
): LimitOrderNetworkConfig {
|
|
332
|
+
return LIMIT_ORDER_NETWORK_CONFIGS[network];
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** Build the correct EIP-712 signing domain for a supported network. */
|
|
336
|
+
export function getNetworkEIP712SigningParams(
|
|
337
|
+
network: LimitOrderNetwork,
|
|
338
|
+
limitOrderContract?: string,
|
|
339
|
+
) {
|
|
340
|
+
const config = getLimitOrderNetworkConfig(network);
|
|
341
|
+
return getEIP712SigningParams(
|
|
342
|
+
limitOrderContract ?? config.limitOrderContract,
|
|
343
|
+
config.chainId,
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/** Resolve the maker's ERC-20 approval target for the selected fee mode. */
|
|
348
|
+
export function getLimitOrderApprovalTarget(
|
|
349
|
+
network: LimitOrderNetwork,
|
|
350
|
+
feeOnOutput: boolean,
|
|
351
|
+
overrides: { limitOrderContract?: string; routerContract?: string } = {},
|
|
352
|
+
): string {
|
|
353
|
+
const config = getLimitOrderNetworkConfig(network);
|
|
354
|
+
return feeOnOutput
|
|
355
|
+
? getRouterApprovalTarget(overrides.routerContract ?? config.routerContract)
|
|
356
|
+
: getApprovalTarget(overrides.limitOrderContract ?? config.limitOrderContract);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export interface LimitOrderNetworkOptions {
|
|
360
|
+
network?: LimitOrderNetwork;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function endpointForNetwork(endpoint: string, network?: string): string {
|
|
364
|
+
if (!network) return endpoint;
|
|
365
|
+
const url = new URL(endpoint);
|
|
366
|
+
url.searchParams.set("network", network);
|
|
367
|
+
return url.toString();
|
|
368
|
+
}
|
|
360
369
|
|
|
361
370
|
/**
|
|
362
371
|
* Check if the input token is native PLS (should use PLSFlow instead of EIP-712).
|
|
@@ -367,27 +376,27 @@ function endpointForNetwork(endpoint: string, network?: string): string {
|
|
|
367
376
|
* @param tokenIn - The input token address
|
|
368
377
|
* @returns `true` if tokenIn is the native PLS sentinel address
|
|
369
378
|
*/
|
|
370
|
-
export function isNativePLS(tokenIn: string): boolean {
|
|
379
|
+
export function isNativePLS(tokenIn: string): boolean {
|
|
371
380
|
const NATIVE_SENTINEL = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
372
381
|
return tokenIn.toLowerCase() === NATIVE_SENTINEL.toLowerCase();
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/** Network-neutral native-currency sentinel check (PLS or ETH). */
|
|
376
|
-
export function isNativeCurrency(tokenIn: string): boolean {
|
|
377
|
-
const normalized = tokenIn.toLowerCase();
|
|
378
|
-
return (
|
|
379
|
-
normalized === NATIVE_PLS.toLowerCase() ||
|
|
380
|
-
normalized === ROBINHOOD_NATIVE_ETH.toLowerCase()
|
|
381
|
-
);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/** Return the native-order flow contract for PulseChain or Robinhood Chain. */
|
|
385
|
-
export function getNativeFlowAddress(
|
|
386
|
-
network: LimitOrderNetwork,
|
|
387
|
-
nativeFlowContract?: string,
|
|
388
|
-
): string {
|
|
389
|
-
return nativeFlowContract ?? getLimitOrderNetworkConfig(network).nativeFlowContract;
|
|
390
|
-
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/** Network-neutral native-currency sentinel check (PLS or ETH). */
|
|
385
|
+
export function isNativeCurrency(tokenIn: string): boolean {
|
|
386
|
+
const normalized = tokenIn.toLowerCase();
|
|
387
|
+
return (
|
|
388
|
+
normalized === NATIVE_PLS.toLowerCase() ||
|
|
389
|
+
normalized === ROBINHOOD_NATIVE_ETH.toLowerCase()
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/** Return the native-order flow contract for PulseChain or Robinhood Chain. */
|
|
394
|
+
export function getNativeFlowAddress(
|
|
395
|
+
network: LimitOrderNetwork,
|
|
396
|
+
nativeFlowContract?: string,
|
|
397
|
+
): string {
|
|
398
|
+
return nativeFlowContract ?? getLimitOrderNetworkConfig(network).nativeFlowContract;
|
|
399
|
+
}
|
|
391
400
|
|
|
392
401
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
393
402
|
// API Helpers
|
|
@@ -407,12 +416,14 @@ export function getNativeFlowAddress(
|
|
|
407
416
|
* 1. Call `submitLimitOrder()` **immediately** after the user signs.
|
|
408
417
|
* 2. **Await** the response and verify `success: true` before showing
|
|
409
418
|
* the order as "created" in your UI.
|
|
410
|
-
* 3. If the POST fails,
|
|
411
|
-
*
|
|
419
|
+
* 3. If the POST fails, first query the same maker + nonce and verify its
|
|
420
|
+
* contract and every signed field. The backend rejects duplicate nonces;
|
|
421
|
+
* it does not return an idempotent success. Retry only the identical payload,
|
|
422
|
+
* preserving its nonce and signature while the order is still live.
|
|
412
423
|
* 4. Do **not** navigate away or close the signing flow until the
|
|
413
424
|
* backend confirms the order.
|
|
414
425
|
*
|
|
415
|
-
* Native PLS/ETH flow orders are an exception — they are recorded
|
|
426
|
+
* Native PLS/ETH flow orders are an exception — they are recorded
|
|
416
427
|
* on-chain first, so the backend can discover them via event indexing
|
|
417
428
|
* even if the POST never arrives.
|
|
418
429
|
*
|
|
@@ -432,11 +443,11 @@ export function getNativeFlowAddress(
|
|
|
432
443
|
* }
|
|
433
444
|
* ```
|
|
434
445
|
*/
|
|
435
|
-
export async function submitLimitOrder(
|
|
436
|
-
signedOrder: SignedLimitOrder,
|
|
437
|
-
options: LimitOrderNetworkOptions = {},
|
|
438
|
-
): Promise<CreateLimitOrderResponse | ErrorResponse> {
|
|
439
|
-
const res = await fetch(endpointForNetwork(LIMIT_ORDERS_ENDPOINT, options.network), {
|
|
446
|
+
export async function submitLimitOrder(
|
|
447
|
+
signedOrder: SignedLimitOrder,
|
|
448
|
+
options: LimitOrderNetworkOptions = {},
|
|
449
|
+
): Promise<CreateLimitOrderResponse | ErrorResponse> {
|
|
450
|
+
const res = await fetch(endpointForNetwork(LIMIT_ORDERS_ENDPOINT, options.network), {
|
|
440
451
|
method: "POST",
|
|
441
452
|
headers: { "Content-Type": "application/json" },
|
|
442
453
|
body: JSON.stringify(signedOrder),
|
|
@@ -446,24 +457,24 @@ export async function submitLimitOrder(
|
|
|
446
457
|
}
|
|
447
458
|
|
|
448
459
|
/**
|
|
449
|
-
* Legacy helper for backend deployments that implemented REST cancellation.
|
|
450
|
-
*
|
|
451
|
-
* The current hosted Switch API intentionally has no DELETE endpoint.
|
|
452
|
-
* Cancellation must be performed on-chain with `invalidateNonce(nonce)` on
|
|
453
|
-
* the contract stored in the order's `limitOrderContract` field. The indexer
|
|
454
|
-
* then updates the order status from the emitted event.
|
|
460
|
+
* Legacy helper for backend deployments that implemented REST cancellation.
|
|
461
|
+
*
|
|
462
|
+
* The current hosted Switch API intentionally has no DELETE endpoint.
|
|
463
|
+
* Cancellation must be performed on-chain with `invalidateNonce(nonce)` on
|
|
464
|
+
* the contract stored in the order's `limitOrderContract` field. The indexer
|
|
465
|
+
* then updates the order status from the emitted event.
|
|
455
466
|
*
|
|
456
467
|
* @param maker - Maker address
|
|
457
468
|
* @param nonce - Nonce of the order to cancel
|
|
458
|
-
* @returns Success confirmation or error on compatible legacy backends
|
|
459
|
-
* @deprecated Do not use with the hosted Switch API; cancel on-chain instead.
|
|
469
|
+
* @returns Success confirmation or error on compatible legacy backends
|
|
470
|
+
* @deprecated Do not use with the hosted Switch API; cancel on-chain instead.
|
|
460
471
|
*/
|
|
461
|
-
export async function cancelLimitOrder(
|
|
462
|
-
maker: string,
|
|
463
|
-
nonce: number,
|
|
464
|
-
options: LimitOrderNetworkOptions = {},
|
|
465
|
-
): Promise<CancelLimitOrderResponse | ErrorResponse> {
|
|
466
|
-
const res = await fetch(endpointForNetwork(LIMIT_ORDERS_ENDPOINT, options.network), {
|
|
472
|
+
export async function cancelLimitOrder(
|
|
473
|
+
maker: string,
|
|
474
|
+
nonce: number,
|
|
475
|
+
options: LimitOrderNetworkOptions = {},
|
|
476
|
+
): Promise<CancelLimitOrderResponse | ErrorResponse> {
|
|
477
|
+
const res = await fetch(endpointForNetwork(LIMIT_ORDERS_ENDPOINT, options.network), {
|
|
467
478
|
method: "DELETE",
|
|
468
479
|
headers: { "Content-Type": "application/json" },
|
|
469
480
|
body: JSON.stringify({ maker, nonce }),
|
|
@@ -473,9 +484,9 @@ export async function cancelLimitOrder(
|
|
|
473
484
|
}
|
|
474
485
|
|
|
475
486
|
/** Filter options for listing limit orders */
|
|
476
|
-
export interface ListLimitOrdersOptions {
|
|
477
|
-
/** Backend network process to query. */
|
|
478
|
-
network?: LimitOrderNetwork;
|
|
487
|
+
export interface ListLimitOrdersOptions {
|
|
488
|
+
/** Backend network process to query. */
|
|
489
|
+
network?: LimitOrderNetwork;
|
|
479
490
|
/** Filter by order status. Default: `"ACTIVE"` */
|
|
480
491
|
status?: LimitOrderStatus;
|
|
481
492
|
/** Filter by maker address */
|
|
@@ -540,8 +551,8 @@ export async function fetchLimitOrders(
|
|
|
540
551
|
if (options.tokenOut) params.set("tokenOut", options.tokenOut);
|
|
541
552
|
if (options.pair) params.set("pair", options.pair);
|
|
542
553
|
if (options.limit != null) params.set("limit", String(options.limit));
|
|
543
|
-
if (options.offset != null) params.set("offset", String(options.offset));
|
|
544
|
-
if (options.network) params.set("network", options.network);
|
|
554
|
+
if (options.offset != null) params.set("offset", String(options.offset));
|
|
555
|
+
if (options.network) params.set("network", options.network);
|
|
545
556
|
|
|
546
557
|
const url = params.toString()
|
|
547
558
|
? `${LIMIT_ORDERS_ENDPOINT}?${params}`
|
|
@@ -558,14 +569,14 @@ export async function fetchLimitOrders(
|
|
|
558
569
|
* @param nonce - Order nonce
|
|
559
570
|
* @returns The order record, or an error if not found
|
|
560
571
|
*/
|
|
561
|
-
export async function fetchLimitOrder(
|
|
562
|
-
maker: string,
|
|
563
|
-
nonce: number,
|
|
564
|
-
options: LimitOrderNetworkOptions = {},
|
|
565
|
-
): Promise<LimitOrderRecord | ErrorResponse> {
|
|
566
|
-
const res = await fetch(
|
|
567
|
-
endpointForNetwork(`${LIMIT_ORDERS_ENDPOINT}/${maker}/${nonce}`, options.network),
|
|
568
|
-
);
|
|
572
|
+
export async function fetchLimitOrder(
|
|
573
|
+
maker: string,
|
|
574
|
+
nonce: number,
|
|
575
|
+
options: LimitOrderNetworkOptions = {},
|
|
576
|
+
): Promise<LimitOrderRecord | ErrorResponse> {
|
|
577
|
+
const res = await fetch(
|
|
578
|
+
endpointForNetwork(`${LIMIT_ORDERS_ENDPOINT}/${maker}/${nonce}`, options.network),
|
|
579
|
+
);
|
|
569
580
|
return res.json() as Promise<LimitOrderRecord | ErrorResponse>;
|
|
570
581
|
}
|
|
571
582
|
|
|
@@ -574,34 +585,34 @@ export async function fetchLimitOrder(
|
|
|
574
585
|
*
|
|
575
586
|
* Useful for displaying which token pairs have open limit orders.
|
|
576
587
|
*/
|
|
577
|
-
export async function fetchLimitOrderPairs(
|
|
578
|
-
options: LimitOrderNetworkOptions = {},
|
|
579
|
-
): Promise<LimitOrderPair[]> {
|
|
580
|
-
const res = await fetch(endpointForNetwork(LIMIT_ORDER_PAIRS_ENDPOINT, options.network));
|
|
588
|
+
export async function fetchLimitOrderPairs(
|
|
589
|
+
options: LimitOrderNetworkOptions = {},
|
|
590
|
+
): Promise<LimitOrderPair[]> {
|
|
591
|
+
const res = await fetch(endpointForNetwork(LIMIT_ORDER_PAIRS_ENDPOINT, options.network));
|
|
581
592
|
return res.json() as Promise<LimitOrderPair[]>;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
/** Fetch the active deployment and EIP-712 domain for a network. */
|
|
585
|
-
export async function fetchLimitOrderConfig(
|
|
586
|
-
options: LimitOrderNetworkOptions = {},
|
|
587
|
-
): Promise<LimitOrderConfigResponse> {
|
|
588
|
-
const res = await fetch(
|
|
589
|
-
endpointForNetwork(`${LIMIT_ORDERS_ENDPOINT}/config`, options.network),
|
|
590
|
-
);
|
|
591
|
-
if (!res.ok) {
|
|
592
|
-
throw new Error(`Failed to fetch limit-order config (${res.status})`);
|
|
593
|
-
}
|
|
594
|
-
return res.json() as Promise<LimitOrderConfigResponse>;
|
|
595
|
-
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/** Fetch the active deployment and EIP-712 domain for a network. */
|
|
596
|
+
export async function fetchLimitOrderConfig(
|
|
597
|
+
options: LimitOrderNetworkOptions = {},
|
|
598
|
+
): Promise<LimitOrderConfigResponse> {
|
|
599
|
+
const res = await fetch(
|
|
600
|
+
endpointForNetwork(`${LIMIT_ORDERS_ENDPOINT}/config`, options.network),
|
|
601
|
+
);
|
|
602
|
+
if (!res.ok) {
|
|
603
|
+
throw new Error(`Failed to fetch limit-order config (${res.status})`);
|
|
604
|
+
}
|
|
605
|
+
return res.json() as Promise<LimitOrderConfigResponse>;
|
|
606
|
+
}
|
|
596
607
|
|
|
597
608
|
/**
|
|
598
609
|
* Fetch summary statistics for all limit orders.
|
|
599
610
|
*
|
|
600
611
|
* Returns counts of active, filled, cancelled, and expired orders.
|
|
601
612
|
*/
|
|
602
|
-
export async function fetchLimitOrderStats(
|
|
603
|
-
options: LimitOrderNetworkOptions = {},
|
|
604
|
-
): Promise<LimitOrderStats> {
|
|
605
|
-
const res = await fetch(endpointForNetwork(LIMIT_ORDER_STATS_ENDPOINT, options.network));
|
|
613
|
+
export async function fetchLimitOrderStats(
|
|
614
|
+
options: LimitOrderNetworkOptions = {},
|
|
615
|
+
): Promise<LimitOrderStats> {
|
|
616
|
+
const res = await fetch(endpointForNetwork(LIMIT_ORDER_STATS_ENDPOINT, options.network));
|
|
606
617
|
return res.json() as Promise<LimitOrderStats>;
|
|
607
618
|
}
|