@orbs-network/spot-react 2.0.1 → 2.1.1
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 +277 -148
- package/dist/spot-react/src/context/client-error-notice.d.ts +7 -0
- package/dist/spot-react/src/context/client-error-notice.d.ts.map +1 -0
- package/dist/spot-react/src/context/create-spot-store.d.ts +53 -0
- package/dist/spot-react/src/context/create-spot-store.d.ts.map +1 -0
- package/dist/spot-react/src/context/error-boundary.d.ts +7 -0
- package/dist/spot-react/src/context/error-boundary.d.ts.map +1 -0
- package/dist/spot-react/src/context/order-form-context.d.ts +7 -0
- package/dist/spot-react/src/context/order-form-context.d.ts.map +1 -0
- package/dist/spot-react/src/context/spot-form-synchronizer.d.ts +14 -0
- package/dist/spot-react/src/context/spot-form-synchronizer.d.ts.map +1 -0
- package/dist/spot-react/src/context/spot-provider.d.ts +3 -0
- package/dist/spot-react/src/context/spot-provider.d.ts.map +1 -0
- package/dist/spot-react/src/context/spot-runtime-context.d.ts +33 -0
- package/dist/spot-react/src/context/spot-runtime-context.d.ts.map +1 -0
- package/dist/spot-react/src/context/spot-store-context.d.ts +10 -0
- package/dist/spot-react/src/context/spot-store-context.d.ts.map +1 -0
- package/dist/spot-react/src/context/use-client.d.ts +10 -0
- package/dist/spot-react/src/context/use-client.d.ts.map +1 -0
- package/dist/spot-react/src/context/use-spot-analytics.d.ts +3 -0
- package/dist/spot-react/src/context/use-spot-analytics.d.ts.map +1 -0
- package/dist/spot-react/src/context/use-spot-provider-state.d.ts +11 -0
- package/dist/spot-react/src/context/use-spot-provider-state.d.ts.map +1 -0
- package/dist/spot-react/src/execute-order.d.ts +25 -0
- package/dist/spot-react/src/execute-order.d.ts.map +1 -0
- package/dist/spot-react/src/execution-state.d.ts +19 -0
- package/dist/spot-react/src/execution-state.d.ts.map +1 -0
- package/dist/spot-react/src/hooks/helper-hooks.d.ts +0 -547
- package/dist/spot-react/src/hooks/helper-hooks.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/order-hooks.d.ts +28 -18
- package/dist/spot-react/src/hooks/order-hooks.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/use-cancel-order.d.ts +5 -4
- package/dist/spot-react/src/hooks/use-cancel-order.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/use-disclaimer.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/use-duration.d.ts +3 -20
- package/dist/spot-react/src/hooks/use-duration.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/use-execution.d.ts +30 -0
- package/dist/spot-react/src/hooks/use-execution.d.ts.map +1 -0
- package/dist/spot-react/src/hooks/use-fill-delay.d.ts +3 -22
- package/dist/spot-react/src/hooks/use-fill-delay.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/use-history-order.d.ts +51 -28
- package/dist/spot-react/src/hooks/use-history-order.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/use-input-errors.d.ts +1 -1
- package/dist/spot-react/src/hooks/use-input-errors.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/use-limit-price.d.ts +14 -21
- package/dist/spot-react/src/hooks/use-limit-price.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/use-output-amount.d.ts +5 -0
- package/dist/spot-react/src/hooks/use-output-amount.d.ts.map +1 -0
- package/dist/spot-react/src/hooks/use-price-display.d.ts +10 -0
- package/dist/spot-react/src/hooks/use-price-display.d.ts.map +1 -0
- package/dist/spot-react/src/hooks/use-submit-order.d.ts +1 -2
- package/dist/spot-react/src/hooks/use-submit-order.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/use-swap-execution.d.ts +9 -10
- package/dist/spot-react/src/hooks/use-swap-execution.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/use-trades.d.ts +7 -17
- package/dist/spot-react/src/hooks/use-trades.d.ts.map +1 -1
- package/dist/spot-react/src/hooks/use-trigger-price.d.ts +13 -20
- package/dist/spot-react/src/hooks/use-trigger-price.d.ts.map +1 -1
- package/dist/spot-react/src/index.d.ts +20 -11
- package/dist/spot-react/src/index.d.ts.map +1 -1
- package/dist/spot-react/src/order-history-data.d.ts +14 -0
- package/dist/spot-react/src/order-history-data.d.ts.map +1 -0
- package/dist/spot-react/src/types.d.ts +108 -123
- package/dist/spot-react/src/types.d.ts.map +1 -1
- package/dist/spot-react.js +1627 -6489
- package/dist/spot-react.umd.cjs +1 -64
- package/package.json +8 -13
- package/dist/spot-react/package.json.d.ts +0 -56
- package/dist/spot-react/src/hooks/use-amounts-usd.d.ts +0 -5
- package/dist/spot-react/src/hooks/use-amounts-usd.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-build-order-info.d.ts +0 -62
- package/dist/spot-react/src/hooks/use-build-order-info.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-deadline.d.ts +0 -2
- package/dist/spot-react/src/hooks/use-deadline.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-default-values.d.ts +0 -3
- package/dist/spot-react/src/hooks/use-default-values.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-dst-amount.d.ts +0 -11
- package/dist/spot-react/src/hooks/use-dst-amount.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-dst-token-panel.d.ts +0 -7
- package/dist/spot-react/src/hooks/use-dst-token-panel.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-fees.d.ts +0 -7
- package/dist/spot-react/src/hooks/use-fees.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-form-data.d.ts +0 -57
- package/dist/spot-react/src/hooks/use-form-data.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-input-with-percentage.d.ts +0 -16
- package/dist/spot-react/src/hooks/use-input-with-percentage.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-limit-price-panel.d.ts +0 -22
- package/dist/spot-react/src/hooks/use-limit-price-panel.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-partner-chains.d.ts +0 -2
- package/dist/spot-react/src/hooks/use-partner-chains.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-price-panel.d.ts +0 -21
- package/dist/spot-react/src/hooks/use-price-panel.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-repermit-data.d.ts +0 -7
- package/dist/spot-react/src/hooks/use-repermit-data.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-repermit-order-data.d.ts +0 -20
- package/dist/spot-react/src/hooks/use-repermit-order-data.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-spot.d.ts +0 -40
- package/dist/spot-react/src/hooks/use-spot.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-src-amount.d.ts +0 -6
- package/dist/spot-react/src/hooks/use-src-amount.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-submit-order-panel.d.ts +0 -28
- package/dist/spot-react/src/hooks/use-submit-order-panel.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-trade-price.d.ts +0 -2
- package/dist/spot-react/src/hooks/use-trade-price.d.ts.map +0 -1
- package/dist/spot-react/src/hooks/use-trigger-price-panel.d.ts +0 -23
- package/dist/spot-react/src/hooks/use-trigger-price-panel.d.ts.map +0 -1
- package/dist/spot-react/src/spot-context.d.ts +0 -6
- package/dist/spot-react/src/spot-context.d.ts.map +0 -1
- package/dist/spot-react/src/store.d.ts +0 -11
- package/dist/spot-react/src/store.d.ts.map +0 -1
- package/dist/spot-react/src/utils.d.ts +0 -20
- package/dist/spot-react/src/utils.d.ts.map +0 -1
- package/dist/spot-ui/src/index.d.ts +0 -14
- package/dist/spot-ui/src/index.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/abi/erc20.json.d.ts +0 -291
- package/dist/spot-ui/src/lib/abi/index.d.ts +0 -260
- package/dist/spot-ui/src/lib/abi/index.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/abi/iweth.json.d.ts +0 -41
- package/dist/spot-ui/src/lib/abi/repermit.json.d.ts +0 -315
- package/dist/spot-ui/src/lib/analytics.d.ts +0 -111
- package/dist/spot-ui/src/lib/analytics.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/build-repermit-order-data.d.ts +0 -35
- package/dist/spot-ui/src/lib/build-repermit-order-data.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/consts.d.ts +0 -99
- package/dist/spot-ui/src/lib/consts.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/lib.d.ts +0 -80
- package/dist/spot-ui/src/lib/lib.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/networks.d.ts +0 -571
- package/dist/spot-ui/src/lib/networks.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/orders/index.d.ts +0 -15
- package/dist/spot-ui/src/lib/orders/index.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/orders/v1-orders.d.ts +0 -34
- package/dist/spot-ui/src/lib/orders/v1-orders.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/orders/v2-orders.d.ts +0 -11
- package/dist/spot-ui/src/lib/orders/v2-orders.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/submit-order.d.ts +0 -3
- package/dist/spot-ui/src/lib/submit-order.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/types.d.ts +0 -318
- package/dist/spot-ui/src/lib/types.d.ts.map +0 -1
- package/dist/spot-ui/src/lib/utils.d.ts +0 -578
- package/dist/spot-ui/src/lib/utils.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
React SDK for building TWAP, Limit, Stop-Loss, and Take-Profit order interfaces on top of the [Orbs Spot protocol](https://www.orbs.com/).
|
|
4
4
|
|
|
5
|
-
`spot-react` owns Spot order state and exposes it through `SpotProvider` and
|
|
5
|
+
`spot-react` owns Spot order state and exposes it through `SpotProvider` and focused named hooks. The host DEX remains responsible for swap-form state, wallet access, components, styling, translations, routing, and modal shells.
|
|
6
6
|
|
|
7
7
|
For the complete integration workflow, see the [Spot React integration skill](https://github.com/orbs-network/spot-ui/tree/master/skills/spot-react-integration) and the [reference implementation](https://github.com/orbs-network/spot-ui/blob/master/apps/web/components/spot/spot-form.tsx).
|
|
8
8
|
|
|
@@ -12,9 +12,17 @@ Every DEX needs a member of the exported `Partners` enum and a server-side Orbs
|
|
|
12
12
|
|
|
13
13
|
### RePermit configuration security
|
|
14
14
|
|
|
15
|
-
The `/config` endpoint is a security boundary. The SDK
|
|
15
|
+
The `/config` endpoint is a security boundary. The SDK rejects configurations whose domain or order chain differs from the requested chain, and rejects zero or malformed RePermit and exchange-adapter addresses. It uses `domain.verifyingContract` as the ERC-20 approval spender and the v2 cancellation contract, and uses the returned adapter, reactor, and executor when constructing orders. The SDK does not independently verify deployed bytecode or contract identity, so deployments must use the trusted Orbs endpoint over TLS and contract-address changes require explicit approval from the protocol/security owner.
|
|
16
16
|
|
|
17
|
-
`SpotProvider`
|
|
17
|
+
`SpotProvider` initializes the `spot-ui` client only when the connected chain supports the selected partner. It never substitutes another chain. Client state and order history are scoped to that provider, with no global cache or host query provider required. The framework-neutral `createClient` factory also retains no global state. The client owns configuration-dependent order preparation, signing/approval/cancellation request values, submission, and configured history access; calculations remain package-level functions. Form previews and order construction share the framework-agnostic `calculateOrderForm` model, so defaults, prices, trades, schedules, errors, raw/token-formatted/USD values, and signed execution values cannot diverge. Form calculation is time-independent; `prepareOrder` assigns fresh start, deadline, and nonce values after wrapping and approval, immediately before signing. Initialization is retried twice. After those retries, the provider keeps its children mounted and renders the retryable `clientErrorFallback` alongside them. Supply that component to localize and style the error for the host DEX.
|
|
18
|
+
|
|
19
|
+
The authoritative shared model is available from `useOrderForm()`.
|
|
20
|
+
|
|
21
|
+
Each mounted `SpotProvider` owns one stable store. Changing the module or token
|
|
22
|
+
pair reapplies form defaults without recreating the partner/chain client,
|
|
23
|
+
history cache, or cancellation state. If that scope changes during execution,
|
|
24
|
+
the reset waits until the frozen execution reaches a terminal phase. Changing
|
|
25
|
+
partner or chain reconfigures only the resources whose keys actually changed.
|
|
18
26
|
|
|
19
27
|
The completed integration should:
|
|
20
28
|
|
|
@@ -36,56 +44,82 @@ npm install @orbs-network/spot-react@latest @orbs-network/swap-ui@latest
|
|
|
36
44
|
|
|
37
45
|
If migrating from `@orbs-network/twap-ui`, remove it before installing the packages above.
|
|
38
46
|
|
|
39
|
-
###
|
|
47
|
+
### Migrating from 1.x
|
|
40
48
|
|
|
41
|
-
|
|
49
|
+
Version 2 is a deliberately breaking, headless API. Replace the broad `useSpot`
|
|
50
|
+
and `useSwapExecution` interfaces with focused hooks such as `useOrderForm`,
|
|
51
|
+
`useExecution`, `useSubmitButton`, and `useOrders`. Provider values now use
|
|
52
|
+
`input`/`output` terminology (`inputToken`, `outputToken`, `inputBalanceRaw`,
|
|
53
|
+
and `minTradeSizeUsd`), and the host supplies wallet operations through
|
|
54
|
+
`walletInteractions`. Debug query parameters and the `isDev` option are no
|
|
55
|
+
longer supported.
|
|
42
56
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
`@orbs-network/swap-ui` is a recommended companion for the documented order
|
|
58
|
+
progress modal, but it is not imported by `spot-react` and is not required for
|
|
59
|
+
a headless or custom-progress integration.
|
|
60
|
+
|
|
61
|
+
### Peer Dependency
|
|
62
|
+
|
|
63
|
+
The host application must provide React. Zustand is an internal runtime
|
|
64
|
+
dependency of `spot-react`; integrators do not install or configure it.
|
|
46
65
|
|
|
47
66
|
| Package | Version |
|
|
48
67
|
| --- | --- |
|
|
49
|
-
| `@tanstack/react-query` | `^5.90.12` |
|
|
50
|
-
| `bignumber.js` | `^9.3.1` |
|
|
51
|
-
| `react-error-boundary` | `^6.0.0` |
|
|
52
|
-
| `zustand` | `^5.0.9` |
|
|
53
68
|
| `react` | `^18 \|\| ^19` |
|
|
54
|
-
| `react-dom` | `^18 \|\| ^19` |
|
|
55
69
|
|
|
56
70
|
`viem` is not a dependency. Adapt the wallet library already used by the DEX through `walletInteractions`.
|
|
57
71
|
|
|
72
|
+
The published entry includes a `"use client"` directive, so it can be imported
|
|
73
|
+
directly from a Next.js App Router client component.
|
|
74
|
+
|
|
58
75
|
## Integration Model
|
|
59
76
|
|
|
60
77
|
Keep the DEX swap form as the source of truth. Pass the following adapted values directly to `SpotProvider`:
|
|
61
78
|
|
|
62
79
|
| Value | Expected shape |
|
|
63
80
|
| --- | --- |
|
|
64
|
-
| Selected tokens | `Token` objects with `address`, `symbol`, `decimals`, and `logoUrl` |
|
|
81
|
+
| Selected tokens | `Token` objects with `address`, `symbol`, `decimals`, and optional `logoUrl` |
|
|
82
|
+
| Wrapped native token | The connected chain's wrapped-native `Token`, supplied by the DEX |
|
|
65
83
|
| Typed source amount | User-facing decimal string, for example `"1.25"` |
|
|
66
84
|
| Quote output | Raw destination-token amount for the current typed input |
|
|
67
|
-
|
|
|
85
|
+
| Input balance | Raw integer string |
|
|
68
86
|
| USD prices | USD value of exactly one whole source/destination token |
|
|
69
87
|
| Chain and account | Values from the connected wallet/account state |
|
|
70
88
|
|
|
71
89
|
If several Spot components need the same DEX-owned values, expose a small DEX adapter context. Do not copy the swap state into a parallel Spot store, prop-drill long value lists, or create a hook whose only purpose is forwarding props to `SpotProvider`.
|
|
72
90
|
|
|
73
|
-
Memoize objects with `useMemo` and functions with `useCallback`. In particular, keep stable identities for tokens, `
|
|
91
|
+
Memoize objects with `useMemo` and functions with `useCallback`. In particular, keep stable identities for selected tokens, `wrappedNativeToken`, `marketQuote`, `walletInteractions`, and `callbacks`.
|
|
74
92
|
|
|
75
93
|
## Provider Setup
|
|
76
94
|
|
|
77
95
|
```tsx
|
|
78
96
|
import { useMemo } from "react";
|
|
79
97
|
import {
|
|
98
|
+
type ClientErrorFallbackProps,
|
|
80
99
|
Module,
|
|
81
100
|
Partners,
|
|
82
101
|
SpotProvider,
|
|
83
102
|
type Callbacks,
|
|
84
|
-
type
|
|
103
|
+
type MarketQuote,
|
|
85
104
|
type Token,
|
|
86
105
|
type WalletInteractions,
|
|
87
106
|
} from "@orbs-network/spot-react";
|
|
88
107
|
|
|
108
|
+
function ClientErrorFallback({
|
|
109
|
+
error,
|
|
110
|
+
retry,
|
|
111
|
+
isRetrying,
|
|
112
|
+
}: ClientErrorFallbackProps) {
|
|
113
|
+
return (
|
|
114
|
+
<div role="alert">
|
|
115
|
+
<p>{getLocalizedErrorMessage(error)}</p>
|
|
116
|
+
<button type="button" disabled={isRetrying} onClick={retry}>
|
|
117
|
+
{isRetrying ? t("retrying") : t("retry")}
|
|
118
|
+
</button>
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
89
123
|
function SpotOrderForm({ module }: { module: Module }) {
|
|
90
124
|
// Read these from the DEX's existing swap and wallet state.
|
|
91
125
|
const {
|
|
@@ -93,19 +127,19 @@ function SpotOrderForm({ module }: { module: Module }) {
|
|
|
93
127
|
chainId,
|
|
94
128
|
inputCurrency,
|
|
95
129
|
outputCurrency,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
130
|
+
wrappedNativeCurrency,
|
|
131
|
+
inputBalanceRaw,
|
|
132
|
+
inputAmountUi,
|
|
133
|
+
quotedInputAmountUi,
|
|
134
|
+
quotedOutputAmountRaw,
|
|
101
135
|
isQuoteLoading,
|
|
102
|
-
|
|
103
|
-
|
|
136
|
+
inputTokenUsdPrice,
|
|
137
|
+
outputTokenUsdPrice,
|
|
104
138
|
refetchBalances,
|
|
105
139
|
dexWallet,
|
|
106
140
|
} = useDexSpotAdapter();
|
|
107
141
|
|
|
108
|
-
const
|
|
142
|
+
const inputToken = useMemo<Token | undefined>(() => {
|
|
109
143
|
if (!inputCurrency) return undefined;
|
|
110
144
|
return {
|
|
111
145
|
address: inputCurrency.address,
|
|
@@ -115,7 +149,7 @@ function SpotOrderForm({ module }: { module: Module }) {
|
|
|
115
149
|
};
|
|
116
150
|
}, [inputCurrency]);
|
|
117
151
|
|
|
118
|
-
const
|
|
152
|
+
const outputToken = useMemo<Token | undefined>(() => {
|
|
119
153
|
if (!outputCurrency) return undefined;
|
|
120
154
|
return {
|
|
121
155
|
address: outputCurrency.address,
|
|
@@ -125,26 +159,38 @@ function SpotOrderForm({ module }: { module: Module }) {
|
|
|
125
159
|
};
|
|
126
160
|
}, [outputCurrency]);
|
|
127
161
|
|
|
128
|
-
const
|
|
162
|
+
const wrappedNativeToken = useMemo<Token | undefined>(() => {
|
|
163
|
+
if (!wrappedNativeCurrency) return undefined;
|
|
164
|
+
return {
|
|
165
|
+
address: wrappedNativeCurrency.address,
|
|
166
|
+
symbol: wrappedNativeCurrency.symbol,
|
|
167
|
+
decimals: wrappedNativeCurrency.decimals,
|
|
168
|
+
logoUrl: wrappedNativeCurrency.logoUrl,
|
|
169
|
+
};
|
|
170
|
+
}, [wrappedNativeCurrency]);
|
|
171
|
+
|
|
172
|
+
const marketQuote = useMemo<MarketQuote>(() => {
|
|
129
173
|
const shouldQuote = Boolean(
|
|
130
|
-
|
|
174
|
+
inputAmountUi && inputCurrency && outputCurrency,
|
|
131
175
|
);
|
|
132
|
-
const isStale = shouldQuote &&
|
|
133
|
-
const
|
|
176
|
+
const isStale = shouldQuote && inputAmountUi !== quotedInputAmountUi;
|
|
177
|
+
const currentQuotedOutputAmountRaw =
|
|
178
|
+
!shouldQuote || isStale ? undefined : quotedOutputAmountRaw;
|
|
134
179
|
const isLoading = shouldQuote && (isStale || isQuoteLoading);
|
|
135
180
|
|
|
136
181
|
return {
|
|
137
|
-
|
|
182
|
+
quotedOutputAmountRaw: currentQuotedOutputAmountRaw,
|
|
138
183
|
isLoading,
|
|
139
|
-
noLiquidity:
|
|
184
|
+
noLiquidity:
|
|
185
|
+
shouldQuote && !isLoading && !currentQuotedOutputAmountRaw,
|
|
140
186
|
};
|
|
141
187
|
}, [
|
|
142
188
|
inputCurrency,
|
|
143
189
|
isQuoteLoading,
|
|
144
190
|
outputCurrency,
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
191
|
+
quotedOutputAmountRaw,
|
|
192
|
+
quotedInputAmountUi,
|
|
193
|
+
inputAmountUi,
|
|
148
194
|
]);
|
|
149
195
|
|
|
150
196
|
const walletInteractions = useMemo<WalletInteractions>(
|
|
@@ -167,22 +213,23 @@ function SpotOrderForm({ module }: { module: Module }) {
|
|
|
167
213
|
<SpotProvider
|
|
168
214
|
partner={Partners.Quick}
|
|
169
215
|
module={module}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
216
|
+
inputAmountUi={inputAmountUi}
|
|
217
|
+
priceProtectionPercent={3}
|
|
218
|
+
minTradeSizeUsd={5}
|
|
219
|
+
marketQuote={marketQuote}
|
|
174
220
|
walletInteractions={walletInteractions}
|
|
175
221
|
chainId={chainId}
|
|
176
222
|
account={account}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
223
|
+
inputToken={inputToken}
|
|
224
|
+
outputToken={outputToken}
|
|
225
|
+
wrappedNativeToken={wrappedNativeToken}
|
|
226
|
+
inputBalanceRaw={inputBalanceRaw}
|
|
227
|
+
inputTokenUsdPrice={inputTokenUsdPrice}
|
|
228
|
+
outputTokenUsdPrice={outputTokenUsdPrice}
|
|
183
229
|
callbacks={callbacks}
|
|
230
|
+
clientErrorFallback={ClientErrorFallback}
|
|
184
231
|
appId="my-dex"
|
|
185
|
-
|
|
232
|
+
displayFeePercent={0.25}
|
|
186
233
|
>
|
|
187
234
|
<SpotFormContent />
|
|
188
235
|
</SpotProvider>
|
|
@@ -190,9 +237,16 @@ function SpotOrderForm({ module }: { module: Module }) {
|
|
|
190
237
|
}
|
|
191
238
|
```
|
|
192
239
|
|
|
193
|
-
`
|
|
240
|
+
`marketQuote.quotedOutputAmountRaw` is the DEX quote's raw output amount for the current `inputAmountUi`, not a standalone per-token price. If the quote belongs to an older input or token pair, omit `quotedOutputAmountRaw` and report `isLoading: true` until a current quote arrives.
|
|
241
|
+
|
|
242
|
+
`spot-react` has no network registry. Always pass the `wrappedNativeToken` prop
|
|
243
|
+
from the DEX's own chain configuration; its value may be `undefined` only until
|
|
244
|
+
a chain is known. It is used for native/wrapped pair detection, allowance checks,
|
|
245
|
+
approval, and order preparation. Explorer links are also host-owned; callbacks
|
|
246
|
+
and history values expose transaction hashes so the DEX can format links with
|
|
247
|
+
its existing chain metadata.
|
|
194
248
|
|
|
195
|
-
Use the connected wallet chain as the
|
|
249
|
+
Use the connected wallet chain as the source of truth. When it is absent or unsupported, the provider does not initialize a client and submission stays disabled. The DEX submit area should show its connect-wallet or switch-network control.
|
|
196
250
|
|
|
197
251
|
### SpotProvider Props
|
|
198
252
|
|
|
@@ -200,27 +254,36 @@ Use the connected wallet chain as the UI source of truth. The provider falls bac
|
|
|
200
254
|
| --- | --- | --- | --- |
|
|
201
255
|
| `partner` | `Partners` | Yes | DEX partner enum |
|
|
202
256
|
| `module` | `Module` | Yes | `TWAP`, `LIMIT`, `STOP_LOSS`, or `TAKE_PROFIT` |
|
|
203
|
-
| `
|
|
204
|
-
| `
|
|
205
|
-
| `
|
|
206
|
-
| `
|
|
257
|
+
| `inputAmountUi` | `string` | Yes | User-entered input-token amount |
|
|
258
|
+
| `priceProtectionPercent` | `number` | Yes | Price Protection percentage; this is not swap slippage |
|
|
259
|
+
| `minTradeSizeUsd` | `number` | Yes | Minimum individual trade size in USD |
|
|
260
|
+
| `marketQuote` | `MarketQuote` | Yes | `{ quotedOutputAmountRaw?, isLoading?, noLiquidity? }` for the current DEX quote |
|
|
207
261
|
| `walletInteractions` | `WalletInteractions` | Yes | Five wallet methods implemented by the DEX |
|
|
208
262
|
| `chainId` | `number` | No | Connected wallet chain ID |
|
|
209
|
-
| `account` | `
|
|
210
|
-
| `appId` | `string` | No |
|
|
211
|
-
| `
|
|
212
|
-
| `
|
|
213
|
-
| `
|
|
214
|
-
| `
|
|
215
|
-
| `
|
|
216
|
-
| `
|
|
217
|
-
| `enableQueryParams` | `boolean` | No | Sync supported form state to URL query parameters |
|
|
263
|
+
| `account` | `Address` | No | Connected wallet address |
|
|
264
|
+
| `appId` | `string` | No | Stable host-defined analytics identifier (for example the DEX slug) |
|
|
265
|
+
| `inputToken` | `Token` | No | Input token metadata |
|
|
266
|
+
| `outputToken` | `Token` | No | Output token metadata |
|
|
267
|
+
| `wrappedNativeToken` | `Token \| undefined` | Yes | Host-provided wrapped-native token; pass `undefined` only before a chain is known |
|
|
268
|
+
| `inputBalanceRaw` | `string \| undefined` | Yes | Raw input-token balance; pass `undefined` while disconnected or loading |
|
|
269
|
+
| `inputTokenUsdPrice` | `string \| undefined` | Yes | USD value of one whole input token; pass `undefined` while loading |
|
|
270
|
+
| `outputTokenUsdPrice` | `string` | No | USD value of one whole output token |
|
|
218
271
|
| `callbacks` | `Callbacks` | No | Lifecycle and field-change callbacks |
|
|
219
|
-
| `
|
|
220
|
-
| `isDev` | `boolean` | No | Use development services/configuration |
|
|
272
|
+
| `displayFeePercent` | `number` | No | Display-only fee estimate percentage; does not collect or subtract fees |
|
|
221
273
|
| `supportLegacyOrders` | `boolean` | No | Include supported legacy v1 orders in history |
|
|
274
|
+
| `clientErrorFallback` | `ComponentType<ClientErrorFallbackProps>` | No | Host-rendered client initialization error UI with `error`, `retry`, and `isRetrying` |
|
|
275
|
+
| `errorFallback` | `ComponentType<SpotErrorFallbackProps>` | No | Host-rendered fallback for unexpected calculation or rendering errors |
|
|
222
276
|
|
|
223
|
-
|
|
277
|
+
`inputBalanceRaw` and `inputTokenUsdPrice` are required provider props; pass
|
|
278
|
+
`undefined` only while their values are genuinely unavailable. The output-token
|
|
279
|
+
USD price remains optional because it is used for display details rather than
|
|
280
|
+
submission readiness.
|
|
281
|
+
|
|
282
|
+
`minTradeSizeUsd` must be a positive USD threshold approved for the partner;
|
|
283
|
+
there is intentionally no SDK default. `priceProtectionPercent` uses percentage
|
|
284
|
+
units, so `3` means 3% (300 bps). `displayFeePercent` only populates `form.fees`
|
|
285
|
+
for the review UI. Protocol fee collection is configured separately by the
|
|
286
|
+
partner and backend.
|
|
224
287
|
|
|
225
288
|
## WalletInteractions
|
|
226
289
|
|
|
@@ -255,8 +318,8 @@ const walletInteractions: WalletInteractions = {
|
|
|
255
318
|
return txHash;
|
|
256
319
|
},
|
|
257
320
|
|
|
258
|
-
signOrder: ({
|
|
259
|
-
dexWallet.signTypedData({
|
|
321
|
+
signOrder: ({ signerAddress, typedData }) =>
|
|
322
|
+
dexWallet.signTypedData({ ...typedData, account: signerAddress }),
|
|
260
323
|
|
|
261
324
|
getAllowance: ({ tokenAddress, spenderAddress }) =>
|
|
262
325
|
dexWallet.getAllowance({ tokenAddress, spenderAddress }),
|
|
@@ -268,39 +331,64 @@ const walletInteractions: WalletInteractions = {
|
|
|
268
331
|
| `wrapNativeToken(amountWei)` | Wrap native currency, wait for confirmation, return tx hash |
|
|
269
332
|
| `approveToken({ tokenAddress, amount, spenderAddress })` | Approve the requested spender, wait for confirmation, return tx hash |
|
|
270
333
|
| `cancelOrder({ order, contractAddress, args, abi })` | Call `cancel` with the supplied ABI and args, wait for confirmation, return tx hash |
|
|
271
|
-
| `signOrder({
|
|
334
|
+
| `signOrder({ signerAddress, typedData })` | Adapt the framework-neutral EIP-712 request to the host wallet and return its original `0x`-prefixed signature |
|
|
272
335
|
| `getAllowance({ tokenAddress, spenderAddress })` | Return the connected account's raw allowance as a string |
|
|
273
336
|
|
|
274
|
-
|
|
337
|
+
The signature returned by `signOrder` is submitted unchanged. Do not split it into `{ v, r, s }`, rewrite its recovery byte, or otherwise normalize the wallet's byte representation.
|
|
338
|
+
|
|
339
|
+
## Building with focused hooks
|
|
275
340
|
|
|
276
|
-
|
|
341
|
+
Import only the hooks each component needs. Leaf components should call the
|
|
342
|
+
smallest hook that provides what they render:
|
|
277
343
|
|
|
278
344
|
```tsx
|
|
279
|
-
|
|
345
|
+
import {
|
|
346
|
+
useExecution,
|
|
347
|
+
useLimitPrice,
|
|
348
|
+
useOrderForm,
|
|
349
|
+
useOrders,
|
|
350
|
+
useOutputAmount,
|
|
351
|
+
usePriceDisplay,
|
|
352
|
+
useTrades,
|
|
353
|
+
} from "@orbs-network/spot-react";
|
|
354
|
+
|
|
355
|
+
const calculatedForm = useOrderForm();
|
|
356
|
+
const tradesPanel = useTrades();
|
|
357
|
+
const limitPricePanel = useLimitPrice();
|
|
358
|
+
const outputAmount = useOutputAmount();
|
|
359
|
+
|
|
360
|
+
const execution = useExecution();
|
|
361
|
+
const history = useOrders();
|
|
280
362
|
```
|
|
281
363
|
|
|
364
|
+
`useOrderForm()` reads the calculated form shared by `OrderFormProvider`; it does not rerun the calculation. The other hooks expose smaller panel contracts for clearer component code. They currently share the same calculated-form context, so a form update can rerender every mounted form-panel hook.
|
|
365
|
+
|
|
282
366
|
| Value | Key returns |
|
|
283
367
|
| --- | --- |
|
|
284
|
-
| `
|
|
285
|
-
| `
|
|
286
|
-
| `
|
|
287
|
-
| `
|
|
288
|
-
| `
|
|
289
|
-
| `
|
|
290
|
-
| `
|
|
291
|
-
| `
|
|
292
|
-
| `
|
|
293
|
-
| `
|
|
294
|
-
| `
|
|
295
|
-
| `
|
|
296
|
-
| `
|
|
297
|
-
| `
|
|
298
|
-
| `
|
|
299
|
-
| `
|
|
300
|
-
|
|
301
|
-
Child components should call
|
|
302
|
-
|
|
303
|
-
|
|
368
|
+
| `useOutputAmount()` | `amount: { raw, ui, usd }`, `isLoading` |
|
|
369
|
+
| `useTrades()` | `totalTrades`, `maxTrades`, `onChange`, `error`, structured input/min-output/trigger-output amounts, input/output tokens |
|
|
370
|
+
| `useDuration()` | `duration`, input/unit callbacks, `milliseconds`, `error` |
|
|
371
|
+
| `useFillDelay()` | `fillDelay`, input/unit callbacks, `milliseconds`, `error` |
|
|
372
|
+
| `useLimitPrice()` | `price: { raw, ui, usd }`, canonical raw price, percentage, enable/toggle actions, tokens, loading/error state |
|
|
373
|
+
| `useTriggerPrice()` | `price: { raw, ui, usd }`, canonical raw price, percentage, structured output-per-trade amount, tokens, loading/error state |
|
|
374
|
+
| `usePriceDisplay()` | Inversion state/callback, actual and display-direction tokens, market-order state |
|
|
375
|
+
| `useDisclaimer()` | Disclaimer translation key or `undefined` |
|
|
376
|
+
| `useInputErrors()` | `{ type, args }` or `undefined` |
|
|
377
|
+
| `useSubmitButton()` | `disabled` and `loading` |
|
|
378
|
+
| `useExecution()` | Submission, status, steps, errors, resets, resolved tokens, and tx hashes |
|
|
379
|
+
| `useOrders()` | Provider-scoped categorized order lists and polling state |
|
|
380
|
+
| `useHistoryOrder()` | Display-ready values for one history order |
|
|
381
|
+
| `useCancelOrder()` | Per-order cancellation state and action |
|
|
382
|
+
| `useClient()` | Provider-scoped initialized client state |
|
|
383
|
+
| `useAmountUi()` | Raw-token amount formatting |
|
|
384
|
+
|
|
385
|
+
Child components should call the relevant focused hook themselves instead of receiving hook-returned panels through intermediate props. `useOrders()` activates order-history fetching while an orders consumer is mounted; form-only integrations do not fetch or poll history.
|
|
386
|
+
|
|
387
|
+
Keep the submit button disabled while `loading` is true. If client initialization fails, `SpotProvider` keeps child components mounted and renders the retryable `clientErrorFallback` alongside them.
|
|
388
|
+
|
|
389
|
+
### Trade-count validation behavior
|
|
390
|
+
|
|
391
|
+
An explicitly selected TWAP trade count persists when `inputAmountUi` changes. If lowering the amount makes that count greater than the newly calculated `maxTrades`, Spot does not clamp or reset it: `useTrades().error` and `useInputErrors()` report `InputErrors.MAX_TRADES`, and submission remains disabled until the user selects a valid count. This is an intentional behavior change from integrations that silently reset the trade count on every amount edit. Hosts should render the returned validation error so the user can correct the value.
|
|
304
392
|
|
|
305
393
|
### Panel Visibility
|
|
306
394
|
|
|
@@ -316,87 +404,106 @@ Use `TimeUnit.Minutes`, `TimeUnit.Hours`, and `TimeUnit.Days` for duration and f
|
|
|
316
404
|
|
|
317
405
|
### Display Amounts
|
|
318
406
|
|
|
319
|
-
|
|
407
|
+
Every calculated amount uses the same `{ raw, ui, usd }` shape. Convert `raw`
|
|
408
|
+
into the DEX's native amount type before display when possible:
|
|
320
409
|
|
|
321
410
|
```tsx
|
|
322
411
|
const amount = CurrencyAmount.fromRawAmount(
|
|
323
412
|
inputCurrency,
|
|
324
|
-
|
|
413
|
+
tradesPanel.inputAmountPerTrade.raw,
|
|
325
414
|
);
|
|
326
415
|
|
|
327
416
|
return `${amount.toSignificant()} ${inputCurrency.symbol}`;
|
|
328
417
|
```
|
|
329
418
|
|
|
330
|
-
Use
|
|
419
|
+
Use `.ui` for editable text inputs or when the DEX has no amount object. Do not
|
|
420
|
+
format `.raw` integer strings directly for user display.
|
|
331
421
|
|
|
332
422
|
## Submit and Progress Modal
|
|
333
423
|
|
|
334
|
-
Use `
|
|
424
|
+
Use `useExecution()` for execution state, `useOrderForm()` for review details, and `@orbs-network/swap-ui`'s `SwapFlow` for the creation/progress UI.
|
|
335
425
|
|
|
336
426
|
```tsx
|
|
337
|
-
import { SwapFlow } from "@orbs-network/swap-ui";
|
|
338
|
-
import {
|
|
427
|
+
import { SwapFlow, SwapStatus as SwapUiStatus } from "@orbs-network/swap-ui";
|
|
428
|
+
import {
|
|
429
|
+
ExecutionStatus,
|
|
430
|
+
useExecution,
|
|
431
|
+
useOrderForm,
|
|
432
|
+
} from "@orbs-network/spot-react";
|
|
339
433
|
|
|
340
434
|
function SpotOrderFlow() {
|
|
341
435
|
const {
|
|
342
436
|
status,
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
437
|
+
error,
|
|
438
|
+
inputToken,
|
|
439
|
+
outputToken,
|
|
440
|
+
currentStepIndex,
|
|
347
441
|
totalSteps,
|
|
348
|
-
} =
|
|
349
|
-
const form =
|
|
442
|
+
} = useExecution();
|
|
443
|
+
const form = useOrderForm();
|
|
444
|
+
const swapStatus =
|
|
445
|
+
status === ExecutionStatus.SUCCESS
|
|
446
|
+
? SwapUiStatus.SUCCESS
|
|
447
|
+
: status === ExecutionStatus.FAILED
|
|
448
|
+
? SwapUiStatus.FAILED
|
|
449
|
+
: status === ExecutionStatus.LOADING
|
|
450
|
+
? SwapUiStatus.LOADING
|
|
451
|
+
: undefined;
|
|
350
452
|
|
|
351
453
|
return (
|
|
352
454
|
<SwapFlow
|
|
353
|
-
inAmount={form.
|
|
354
|
-
outAmount={form.
|
|
355
|
-
inToken={{ symbol:
|
|
356
|
-
outToken={{ symbol:
|
|
357
|
-
swapStatus={
|
|
358
|
-
currentStepIndex={
|
|
455
|
+
inAmount={form.inputAmount.ui}
|
|
456
|
+
outAmount={form.outputAmount.ui}
|
|
457
|
+
inToken={{ symbol: inputToken?.symbol, logoUrl: inputToken?.logoUrl }}
|
|
458
|
+
outToken={{ symbol: outputToken?.symbol, logoUrl: outputToken?.logoUrl }}
|
|
459
|
+
swapStatus={swapStatus}
|
|
460
|
+
currentStepIndex={currentStepIndex}
|
|
359
461
|
totalSteps={totalSteps}
|
|
360
462
|
components={{
|
|
361
|
-
Main: <SwapFlow.Main inUsd={form.
|
|
463
|
+
Main: <SwapFlow.Main inUsd={form.inputAmount.usd} outUsd={form.outputAmount.usd} />,
|
|
362
464
|
Success: <SwapFlow.Success title="Order created" />,
|
|
363
|
-
Failed: <SwapFlow.Failed error={
|
|
465
|
+
Failed: <SwapFlow.Failed error={error?.message} />,
|
|
364
466
|
}}
|
|
365
467
|
/>
|
|
366
468
|
);
|
|
367
469
|
}
|
|
368
470
|
```
|
|
369
471
|
|
|
370
|
-
Wrap `SwapFlow` in the DEX's modal shell and skin it with DEX colors, surfaces, typography, token logos, and loaders. Once `
|
|
472
|
+
Wrap `SwapFlow` in the DEX's modal shell and skin it with DEX colors, surfaces, typography, token logos, and loaders. Once `useExecution().status` is set, hide the review details, confirm button, duplicate title, and secondary footer actions so the progress/success/failure content owns the modal.
|
|
371
473
|
|
|
372
474
|
### Execution State and Reset
|
|
373
475
|
|
|
374
|
-
`
|
|
476
|
+
`useExecution()` returns:
|
|
375
477
|
|
|
376
|
-
- `
|
|
377
|
-
- `
|
|
378
|
-
- `
|
|
379
|
-
- `
|
|
478
|
+
- `submitOrder`, `phase`, `status`, `isExecuting`, `isSuccess`, `isFailed`, `isRejected`, `isPreparingOrder`, and `canDismiss`;
|
|
479
|
+
- `currentStep`, `currentStepIndex`, `totalSteps`, and `executionSteps`;
|
|
480
|
+
- `error`, `inputToken`, `outputToken`, `chainId`, `wrapTxHash`, and `approvalTxHash`;
|
|
481
|
+
- `returnToOrderForm()` and `startNewOrder()`.
|
|
380
482
|
|
|
381
483
|
`spot-react` does not clear the DEX input. Do that only when a successful modal closes:
|
|
382
484
|
|
|
383
485
|
```tsx
|
|
384
|
-
const { status, isSuccess,
|
|
385
|
-
|
|
486
|
+
const { status, isSuccess, isExecuting, returnToOrderForm, startNewOrder } =
|
|
487
|
+
useExecution();
|
|
386
488
|
|
|
387
489
|
const onClose = useCallback(() => {
|
|
490
|
+
if (isExecuting) return;
|
|
388
491
|
setIsModalOpen(false);
|
|
389
492
|
|
|
390
493
|
if (isSuccess) {
|
|
391
494
|
setInputAmount("");
|
|
392
|
-
setTimeout(
|
|
495
|
+
setTimeout(startNewOrder, 500);
|
|
393
496
|
} else if (status) {
|
|
394
|
-
setTimeout(
|
|
497
|
+
setTimeout(returnToOrderForm, 500);
|
|
395
498
|
}
|
|
396
|
-
}, [
|
|
499
|
+
}, [isExecuting, isSuccess, returnToOrderForm, setInputAmount, startNewOrder, status]);
|
|
397
500
|
```
|
|
398
501
|
|
|
399
|
-
|
|
502
|
+
Neither reset action can clear an active execution: both return `false` while `isExecuting` is true. Keep the modal open during execution. `returnToOrderForm()` dismisses a failed or rejected execution while preserving the form and a completed native-token wrap for a safe retry. `startNewOrder()` resets Spot's internal form state and all retry metadata after a terminal execution; the host must still clear its own input amount. The short delay lets the close animation finish before state resets.
|
|
503
|
+
|
|
504
|
+
`phase` is the precise execution state: `idle → preparing → wrapping → approving → signing → submitting → success`, with `failed` and `rejected` terminal branches. `status` is the coarser `ExecutionStatus` value. Map it explicitly to the separately versioned `@orbs-network/swap-ui` `SwapStatus` enum as shown above. Each attempt has an internal identity, duplicate starts are rejected atomically, and stale async writes cannot replace a newer attempt. Host callbacks are observational: synchronous throws and rejected callback promises never change a wallet or API result.
|
|
505
|
+
|
|
506
|
+
Once submission begins, `useOrderForm()` exposes the frozen form and `useExecution()` exposes the frozen tokens and chain associated with that execution. The prepared order is frozen internally and reused through approval, wrapping, signing, and submission. Host quote, token, chain, or time updates cannot change the active order.
|
|
400
507
|
|
|
401
508
|
## Callbacks
|
|
402
509
|
|
|
@@ -405,9 +512,9 @@ Callbacks cover wallet notifications, analytics, field synchronization, and bala
|
|
|
405
512
|
```tsx
|
|
406
513
|
const callbacks: Callbacks = {
|
|
407
514
|
onWrapRequest: () => {},
|
|
408
|
-
onWrapSuccess: ({ txHash,
|
|
515
|
+
onWrapSuccess: ({ txHash, amount }) => {},
|
|
409
516
|
onApproveRequest: () => {},
|
|
410
|
-
onApproveSuccess: ({ txHash,
|
|
517
|
+
onApproveSuccess: ({ txHash, token, amount }) => {},
|
|
411
518
|
onSignOrderRequest: () => {},
|
|
412
519
|
onSignOrderSuccess: (signature) => {},
|
|
413
520
|
onSignOrderError: (error) => {},
|
|
@@ -417,16 +524,16 @@ const callbacks: Callbacks = {
|
|
|
417
524
|
onSubmitOrderFailed: ({ code, message }) => {},
|
|
418
525
|
onSubmitOrderRejected: () => {},
|
|
419
526
|
onCancelOrderRequest: (order) => {},
|
|
420
|
-
onCancelOrderSuccess: ({ order, txHash
|
|
527
|
+
onCancelOrderSuccess: ({ order, txHash }) => {},
|
|
421
528
|
onCancelOrderFailed: (error) => {},
|
|
422
529
|
onCopy: () => {},
|
|
423
530
|
onLimitPriceChange: (price) => {},
|
|
424
531
|
onLimitPricePercentChange: (percent) => {},
|
|
425
532
|
onTriggerPriceChange: (price) => {},
|
|
426
533
|
onTriggerPricePercentChange: (percent) => {},
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
534
|
+
onOrderDurationChange: (orderDuration) => {},
|
|
535
|
+
onTradeIntervalChange: (tradeInterval) => {},
|
|
536
|
+
onTradeCountChange: (tradeCount) => {},
|
|
430
537
|
};
|
|
431
538
|
```
|
|
432
539
|
|
|
@@ -453,18 +560,31 @@ function CancelButton({ order }) {
|
|
|
453
560
|
}
|
|
454
561
|
```
|
|
455
562
|
|
|
456
|
-
|
|
563
|
+
Cancellation uses the initialized client for both v1 and v2 orders, keeping request construction on one path; `disabled` remains true while that client is loading or unavailable. History starts after client initialization because v2 requests need the configured exchange adapter. When `supportLegacyOrders` is enabled, v1 history is loaded once and retained while v2 history continues polling.
|
|
457
564
|
|
|
458
|
-
Order history is available from `
|
|
565
|
+
Order history is available directly from `useOrders()`. The query is enabled only while a component using this hook is mounted:
|
|
459
566
|
|
|
460
567
|
```tsx
|
|
461
|
-
const { orders, isLoading, isRefetching,
|
|
462
|
-
useSpot().orderHistoryPanel;
|
|
568
|
+
const { data: orders, isLoading, isRefetching, refetch } = useOrders();
|
|
463
569
|
|
|
464
|
-
// orders
|
|
570
|
+
// orders?.all, orders?.open, orders?.completed, orders?.cancelled, orders?.expired
|
|
465
571
|
```
|
|
466
572
|
|
|
467
|
-
|
|
573
|
+
Like `useClient()`, `data` is undefined before the first result. `refetch()`
|
|
574
|
+
resolves to the latest categorized orders or `undefined` when no request can be
|
|
575
|
+
made. Default the category you render to an empty array, for example
|
|
576
|
+
`const allOrders = orders?.all ?? []`.
|
|
577
|
+
|
|
578
|
+
Use `useHistoryOrder(order, inputToken?, outputToken?)` for display fields. For large histories, use the virtualization library already present in the DEX for both the orders and fills lists. Store the selected `order.historyKey`, then look up the current order from `orders?.all ?? []` by that key; do not store a stale copy of the order object. The key avoids collisions between numeric v1 IDs from different TWAP contracts; `order.id` remains the protocol ID used for display and cancellation.
|
|
579
|
+
|
|
580
|
+
Amounts returned by `useHistoryOrder` and its `fills` use `{ raw, ui }`, matching
|
|
581
|
+
the form model without fabricating unavailable historical USD values.
|
|
582
|
+
|
|
583
|
+
`OrderFilter` contains `ALL`, `OPEN`, `COMPLETED`, `CANCELLED`, and `EXPIRED`.
|
|
584
|
+
`OrderType` identifies the calculated module/mode combination: limit, TWAP
|
|
585
|
+
market/limit, stop-loss market/limit, or take-profit market/limit. Normalized
|
|
586
|
+
`Order` and `OrderFill` retain `src`/`dst` and `in`/`out` names because those are
|
|
587
|
+
protocol/history response models; form-facing APIs use `input`/`output`.
|
|
468
588
|
|
|
469
589
|
Keep history, details, and modal portals under `SpotProvider` context. Details should include execution summary, order info, fills, explorer/copy actions, and cancellation for open orders.
|
|
470
590
|
|
|
@@ -478,35 +598,41 @@ Disclaimer keys are:
|
|
|
478
598
|
- `marketOrderDisclaimer`
|
|
479
599
|
- `triggerMarketPriceDisclaimer`
|
|
480
600
|
|
|
481
|
-
Input errors have the shape `{ type, args }`. Resolve `type` through the DEX's i18n system and interpolate `args`, including values such as `
|
|
601
|
+
Input errors have the shape `{ type, args }`. Resolve `type` through the DEX's i18n system and interpolate `args`, including values such as `maxTrades`, `minTrades`, `minTradeSize`, `duration`, and `fillDelay`. Current duration and fill-delay arguments are human-readable; custom or older integrations should convert raw milliseconds before display.
|
|
482
602
|
|
|
483
|
-
##
|
|
603
|
+
## React helper APIs
|
|
484
604
|
|
|
485
605
|
```tsx
|
|
486
606
|
import {
|
|
487
|
-
useAmountUi,
|
|
488
|
-
|
|
489
|
-
useNetwork, // () => current network metadata
|
|
490
|
-
useRePermitData, // () => { data, error, isLoading, refetch }
|
|
491
|
-
useSignOrder, // low-level signing hook
|
|
492
|
-
useSubmitOrder, // low-level submission mutation
|
|
493
|
-
useSwapExecution, // low-level execution state
|
|
607
|
+
useAmountUi,
|
|
608
|
+
useClient,
|
|
494
609
|
} from "@orbs-network/spot-react";
|
|
610
|
+
|
|
611
|
+
useAmountUi(decimals, rawAmount);
|
|
612
|
+
useClient();
|
|
495
613
|
```
|
|
496
614
|
|
|
497
|
-
|
|
615
|
+
Submit through `useExecution()`. Internal mutations and execution-store hooks
|
|
616
|
+
are deliberately not exported, keeping one supported workflow and one error
|
|
617
|
+
contract. `useClient()` must be called under `SpotProvider`; every caller shares
|
|
618
|
+
the same partner/chain query, and RePermit configuration is available as
|
|
619
|
+
`client?.rePermitData`. Initialization recovery belongs to
|
|
620
|
+
`clientErrorFallback`, which receives the query error and retry action.
|
|
498
621
|
|
|
499
622
|
Public utilities and constants include:
|
|
500
623
|
|
|
501
624
|
```tsx
|
|
502
625
|
import {
|
|
503
|
-
getMinChunkSizeUsd,
|
|
504
|
-
getNetwork,
|
|
505
626
|
getOrderExecutionRate,
|
|
506
627
|
getOrderFillDelayMillis,
|
|
507
628
|
getOrderLimitPriceRate,
|
|
508
629
|
getPartnerChains,
|
|
509
630
|
getPartners,
|
|
631
|
+
getTwapConfig,
|
|
632
|
+
calculateOrderForm,
|
|
633
|
+
toAmountRaw,
|
|
634
|
+
toAmountUI,
|
|
635
|
+
invertPriceInput,
|
|
510
636
|
getTriggerPriceRate,
|
|
511
637
|
eqIgnoreCase,
|
|
512
638
|
isNativeAddress,
|
|
@@ -516,11 +642,14 @@ import {
|
|
|
516
642
|
ORBS_LOGO,
|
|
517
643
|
ORBS_WEBSITE_URL,
|
|
518
644
|
SPOT_VERSION,
|
|
519
|
-
networks,
|
|
520
645
|
} from "@orbs-network/spot-react";
|
|
521
646
|
```
|
|
522
647
|
|
|
523
|
-
|
|
648
|
+
React integrations can import the single `calculateOrderForm` entry point and
|
|
649
|
+
its public calculated types directly from `@orbs-network/spot-react`. Non-React
|
|
650
|
+
integrations should import them from `@orbs-network/spot-ui`. Lower-level
|
|
651
|
+
calculators remain internal entry points; do not import from `dist/*` or
|
|
652
|
+
package-internal source paths.
|
|
524
653
|
|
|
525
654
|
## Integration Checklist
|
|
526
655
|
|