@pear-protocol/symmio-client 0.2.26 → 0.2.28
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/dist/react/index.d.mts +14 -1
- package/dist/react/index.d.ts +14 -1
- package/dist/react/index.js +1299 -1113
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1299 -1114
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/provider.js +426 -0
- package/dist/react/provider.js.map +1 -1
- package/dist/react/provider.mjs +427 -1
- package/dist/react/provider.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { createContext, useContext, useMemo, useRef, useCallback, useEffect } from 'react';
|
|
3
3
|
import { createSymmSDK, isAuthExpiredError, isNetworkError, isInsufficientMarginError, isRateLimitedError, isTimeoutError } from '@pear-protocol/symm-core';
|
|
4
|
-
import { jsx } from 'react/jsx-runtime';
|
|
5
4
|
import { create } from 'zustand';
|
|
5
|
+
import { jsx } from 'react/jsx-runtime';
|
|
6
6
|
import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
|
|
7
7
|
import { isAddress, encodeFunctionData } from 'viem';
|
|
8
8
|
|
|
@@ -14,342 +14,773 @@ function useSymmContext() {
|
|
|
14
14
|
}
|
|
15
15
|
return ctx;
|
|
16
16
|
}
|
|
17
|
-
function SymmProvider({
|
|
18
|
-
chainId = 42161,
|
|
19
|
-
address,
|
|
20
|
-
symmCoreConfig = {
|
|
21
|
-
apiUrl: "https://nginx-server-staging.up.railway.app",
|
|
22
|
-
wsUrl: "wss://nginx-server-staging.up.railway.app"
|
|
23
|
-
},
|
|
24
|
-
symmioConfig,
|
|
25
|
-
children
|
|
26
|
-
}) {
|
|
27
|
-
const symmCoreClient = useMemo(() => {
|
|
28
|
-
return createSymmSDK({
|
|
29
|
-
apiUrl: symmCoreConfig.apiUrl,
|
|
30
|
-
wsUrl: symmCoreConfig.wsUrl,
|
|
31
|
-
defaultChainId: chainId
|
|
32
|
-
});
|
|
33
|
-
}, [chainId, symmCoreConfig.apiUrl, symmCoreConfig.wsUrl]);
|
|
34
|
-
const value = useMemo(
|
|
35
|
-
() => ({
|
|
36
|
-
symmCoreClient,
|
|
37
|
-
chainId,
|
|
38
|
-
address,
|
|
39
|
-
symmioConfig
|
|
40
|
-
}),
|
|
41
|
-
[symmCoreClient, chainId, address, symmioConfig]
|
|
42
|
-
);
|
|
43
|
-
return /* @__PURE__ */ jsx(SymmContext.Provider, { value, children });
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// src/react/hooks/use-symm-core-client.ts
|
|
47
|
-
function useSymmCoreClient() {
|
|
48
|
-
return useSymmContext().symmCoreClient;
|
|
49
|
-
}
|
|
50
17
|
|
|
51
|
-
// src/
|
|
52
|
-
var
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"https://muon-oracle2.rasa.capital/v1/",
|
|
56
|
-
"https://muon-oracle3.rasa.capital/v1/",
|
|
57
|
-
"https://muon-oracle4.rasa.capital/v1/"
|
|
58
|
-
];
|
|
59
|
-
var MUON_APP_NAME = "symmio";
|
|
60
|
-
var MUON_REQUEST_TIMEOUT = 15e3;
|
|
61
|
-
var HEDGER_BASE_URLS = {
|
|
62
|
-
[42161 /* ARBITRUM */]: "https://www.perps-streaming.com/v1/42161a/0x6273242a7E88b3De90822b31648C212215caaFE4",
|
|
63
|
-
[8453 /* BASE */]: "https://www.perps-streaming.com/v1/8453a/0x6273242a7E88b3De90822b31648C212215caaFE4"
|
|
18
|
+
// src/utils/binance-symbol-map.ts
|
|
19
|
+
var SYMBOL_OVERRIDES = {
|
|
20
|
+
// Add overrides here as needed for SYMM markets that don't map 1:1 to Binance
|
|
21
|
+
// e.g., 'SOME_SYMM_SYMBOL': 'BINANCE_SYMBOL',
|
|
64
22
|
};
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (!
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const expirationTime = new Date(
|
|
78
|
-
Date.now() + 30 * 24 * 60 * 60 * 1e3
|
|
79
|
-
).toISOString();
|
|
80
|
-
const message = [
|
|
81
|
-
`${params.domain} wants you to sign in with your Ethereum account:`,
|
|
82
|
-
params.address,
|
|
83
|
-
"",
|
|
84
|
-
params.statement,
|
|
85
|
-
"",
|
|
86
|
-
`URI: ${params.uri}`,
|
|
87
|
-
`Version: ${version}`,
|
|
88
|
-
`Chain ID: ${params.chainId}`,
|
|
89
|
-
`Nonce: ${params.nonce}`,
|
|
90
|
-
`Issued At: ${issuedAt}`,
|
|
91
|
-
`Expiration Time: ${expirationTime}`
|
|
92
|
-
].join("\n");
|
|
93
|
-
return { message, issuedAt, expirationTime };
|
|
94
|
-
}
|
|
95
|
-
async function getNonce(chainId, subAccount) {
|
|
96
|
-
const hedgerBaseUrl = getHedgerBaseUrl(chainId);
|
|
97
|
-
const url = new URL(`nonce/${subAccount}`, hedgerBaseUrl).href;
|
|
98
|
-
const response = await fetch(url);
|
|
99
|
-
if (!response.ok) {
|
|
100
|
-
throw new Error(`Failed to fetch nonce: ${response.statusText}`);
|
|
23
|
+
var UNSUPPORTED_SYMBOLS = /* @__PURE__ */ new Set([
|
|
24
|
+
// Add symbols here that have no Binance equivalent
|
|
25
|
+
]);
|
|
26
|
+
function resolveBinanceSymbol(symmSymbol) {
|
|
27
|
+
if (!symmSymbol || !symmSymbol.trim()) {
|
|
28
|
+
return {
|
|
29
|
+
symmSymbol,
|
|
30
|
+
normalizedSymbol: "",
|
|
31
|
+
binanceSymbol: null,
|
|
32
|
+
supported: false,
|
|
33
|
+
reason: "missing_symbol"
|
|
34
|
+
};
|
|
101
35
|
}
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
issued_at: params.issuedAt,
|
|
112
|
-
signature: params.signature,
|
|
113
|
-
nonce: params.nonce
|
|
114
|
-
};
|
|
115
|
-
const response = await fetch(url, {
|
|
116
|
-
method: "POST",
|
|
117
|
-
headers: { "Content-Type": "application/json" },
|
|
118
|
-
body: JSON.stringify(body)
|
|
119
|
-
});
|
|
120
|
-
if (!response.ok) {
|
|
121
|
-
const errorData = await response.json().catch(() => null);
|
|
122
|
-
throw new Error(
|
|
123
|
-
errorData?.error_message ?? `Login failed: ${response.statusText}`
|
|
124
|
-
);
|
|
36
|
+
const normalized = symmSymbol.toUpperCase().trim();
|
|
37
|
+
if (!/^[A-Z0-9]+$/.test(normalized)) {
|
|
38
|
+
return {
|
|
39
|
+
symmSymbol,
|
|
40
|
+
normalizedSymbol: normalized,
|
|
41
|
+
binanceSymbol: null,
|
|
42
|
+
supported: false,
|
|
43
|
+
reason: "invalid_symbol"
|
|
44
|
+
};
|
|
125
45
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
46
|
+
if (UNSUPPORTED_SYMBOLS.has(normalized)) {
|
|
47
|
+
return {
|
|
48
|
+
symmSymbol,
|
|
49
|
+
normalizedSymbol: normalized,
|
|
50
|
+
binanceSymbol: null,
|
|
51
|
+
supported: false,
|
|
52
|
+
reason: "unsupported_symbol"
|
|
53
|
+
};
|
|
129
54
|
}
|
|
55
|
+
const binanceSymbol = SYMBOL_OVERRIDES[normalized] ?? (normalized.endsWith("USDT") ? normalized : `${normalized}USDT`);
|
|
130
56
|
return {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
57
|
+
symmSymbol,
|
|
58
|
+
normalizedSymbol: normalized,
|
|
59
|
+
binanceSymbol,
|
|
60
|
+
supported: true,
|
|
61
|
+
reason: null
|
|
134
62
|
};
|
|
135
63
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
var TOKEN_STORAGE_PREFIX = "symm_access_token";
|
|
139
|
-
var TOKEN_STORAGE_VERSION = 1;
|
|
140
|
-
var tokenCache = /* @__PURE__ */ new Map();
|
|
141
|
-
function cacheKey(address, chainId) {
|
|
142
|
-
return `${address}:${chainId}`;
|
|
64
|
+
function getUnsupportedBinanceSymbols(symbols) {
|
|
65
|
+
return symbols.filter((symbol) => !resolveBinanceSymbol(symbol).supported);
|
|
143
66
|
}
|
|
144
|
-
function
|
|
145
|
-
return
|
|
67
|
+
function toBinanceSymbol(symmSymbol) {
|
|
68
|
+
return resolveBinanceSymbol(symmSymbol).binanceSymbol;
|
|
146
69
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (Date.now() >= parsed.expiresAt) {
|
|
158
|
-
window.localStorage.removeItem(storageKey(address, chainId));
|
|
159
|
-
return null;
|
|
70
|
+
|
|
71
|
+
// src/utils/binance-ws.ts
|
|
72
|
+
var BINANCE_WS_URL = "wss://fstream.binance.com/ws";
|
|
73
|
+
var RECONNECT_DELAYS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
|
|
74
|
+
var STABLE_QUOTES = ["USDT0", "USDT", "USDC", "USDE", "USDH", "USD"];
|
|
75
|
+
function normalizeBaseSymbol(symbol) {
|
|
76
|
+
const normalized = symbol.toUpperCase().trim();
|
|
77
|
+
for (const quote of STABLE_QUOTES) {
|
|
78
|
+
if (normalized.endsWith(quote) && normalized.length > quote.length) {
|
|
79
|
+
return normalized.slice(0, -quote.length);
|
|
160
80
|
}
|
|
161
|
-
return parsed;
|
|
162
|
-
} catch {
|
|
163
|
-
window.localStorage.removeItem(storageKey(address, chainId));
|
|
164
|
-
return null;
|
|
165
81
|
}
|
|
82
|
+
return normalized;
|
|
166
83
|
}
|
|
167
|
-
function
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
storageKey(address, chainId),
|
|
172
|
-
JSON.stringify(cached)
|
|
173
|
-
);
|
|
174
|
-
} catch {
|
|
175
|
-
}
|
|
84
|
+
function isBinanceMarkPriceTicker(value) {
|
|
85
|
+
return Boolean(
|
|
86
|
+
value && typeof value === "object" && typeof value.s === "string" && typeof value.p === "string" && typeof value.i === "string" && typeof value.E === "number"
|
|
87
|
+
);
|
|
176
88
|
}
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return cached.token;
|
|
89
|
+
function extractTickers(payload) {
|
|
90
|
+
if (Array.isArray(payload)) {
|
|
91
|
+
return payload.filter(isBinanceMarkPriceTicker);
|
|
181
92
|
}
|
|
182
|
-
if (
|
|
183
|
-
|
|
93
|
+
if (payload && typeof payload === "object") {
|
|
94
|
+
const maybeData = payload.data;
|
|
95
|
+
if (Array.isArray(maybeData)) {
|
|
96
|
+
return maybeData.filter(isBinanceMarkPriceTicker);
|
|
97
|
+
}
|
|
98
|
+
return isBinanceMarkPriceTicker(payload) ? [payload] : [];
|
|
184
99
|
}
|
|
185
|
-
|
|
186
|
-
if (!stored) return null;
|
|
187
|
-
tokenCache.set(cacheKey(address, chainId), stored);
|
|
188
|
-
return stored.token;
|
|
100
|
+
return [];
|
|
189
101
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
102
|
+
var BinanceWsManager = class {
|
|
103
|
+
ws = null;
|
|
104
|
+
streams = /* @__PURE__ */ new Map();
|
|
105
|
+
reconnectAttempt = 0;
|
|
106
|
+
reconnectTimer = null;
|
|
107
|
+
intentionalClose = false;
|
|
108
|
+
pendingSubscribes = [];
|
|
109
|
+
idCounter = 0;
|
|
110
|
+
/**
|
|
111
|
+
* Subscribe to a kline stream. Returns an unsubscribe function.
|
|
112
|
+
*/
|
|
113
|
+
subscribeKline(symbol, interval, cb) {
|
|
114
|
+
const streamName = `${symbol.toLowerCase()}@kline_${interval}`;
|
|
115
|
+
const id = this.generateId();
|
|
116
|
+
const wrappedCb = (raw) => {
|
|
117
|
+
const k = raw.k;
|
|
118
|
+
if (!k) return;
|
|
119
|
+
cb({
|
|
120
|
+
symbol: raw.s,
|
|
121
|
+
interval: k.i,
|
|
122
|
+
openTime: k.t,
|
|
123
|
+
closeTime: k.T,
|
|
124
|
+
open: parseFloat(k.o),
|
|
125
|
+
high: parseFloat(k.h),
|
|
126
|
+
low: parseFloat(k.l),
|
|
127
|
+
close: parseFloat(k.c),
|
|
128
|
+
volume: parseFloat(k.v),
|
|
129
|
+
isFinal: k.x
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
this.addStreamCallback(streamName, id, wrappedCb);
|
|
133
|
+
return () => this.removeStreamCallback(streamName, id);
|
|
194
134
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Subscribe to a mark price stream (1s updates). Returns an unsubscribe function.
|
|
137
|
+
*/
|
|
138
|
+
subscribeMarkPrice(symbol, cb) {
|
|
139
|
+
const streamName = `${symbol.toLowerCase()}@markPrice@1s`;
|
|
140
|
+
const id = this.generateId();
|
|
141
|
+
const wrappedCb = (raw) => {
|
|
142
|
+
cb({
|
|
143
|
+
symbol: normalizeBaseSymbol(raw.s),
|
|
144
|
+
markPrice: parseFloat(raw.p),
|
|
145
|
+
indexPrice: parseFloat(raw.i),
|
|
146
|
+
time: raw.E
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
this.addStreamCallback(streamName, id, wrappedCb);
|
|
150
|
+
return () => this.removeStreamCallback(streamName, id);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Subscribe to the all-market mark price stream (1s updates).
|
|
154
|
+
* Returns an unsubscribe function.
|
|
155
|
+
*/
|
|
156
|
+
subscribeAllMarkPrices(cb) {
|
|
157
|
+
const streamName = "!markPrice@arr@1s";
|
|
158
|
+
const id = this.generateId();
|
|
159
|
+
const wrappedCb = (raw) => {
|
|
160
|
+
cb(
|
|
161
|
+
extractTickers(raw).map((entry) => ({
|
|
162
|
+
symbol: normalizeBaseSymbol(entry.s),
|
|
163
|
+
markPrice: parseFloat(entry.p),
|
|
164
|
+
indexPrice: parseFloat(entry.i),
|
|
165
|
+
time: entry.E
|
|
166
|
+
}))
|
|
167
|
+
);
|
|
168
|
+
};
|
|
169
|
+
this.addStreamCallback(streamName, id, wrappedCb);
|
|
170
|
+
return () => this.removeStreamCallback(streamName, id);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Destroy the manager and close the connection.
|
|
174
|
+
*/
|
|
175
|
+
destroy() {
|
|
176
|
+
this.intentionalClose = true;
|
|
177
|
+
if (this.reconnectTimer) {
|
|
178
|
+
clearTimeout(this.reconnectTimer);
|
|
179
|
+
this.reconnectTimer = null;
|
|
180
|
+
}
|
|
181
|
+
if (this.ws) {
|
|
182
|
+
this.ws.close();
|
|
183
|
+
this.ws = null;
|
|
184
|
+
}
|
|
185
|
+
this.streams.clear();
|
|
186
|
+
}
|
|
187
|
+
// --- Private ---
|
|
188
|
+
generateId() {
|
|
189
|
+
return `sub_${++this.idCounter}_${Date.now()}`;
|
|
190
|
+
}
|
|
191
|
+
addStreamCallback(streamName, id, cb) {
|
|
192
|
+
let sub = this.streams.get(streamName);
|
|
193
|
+
const isNew = !sub;
|
|
194
|
+
if (!sub) {
|
|
195
|
+
sub = { callbacks: /* @__PURE__ */ new Map() };
|
|
196
|
+
this.streams.set(streamName, sub);
|
|
197
|
+
}
|
|
198
|
+
sub.callbacks.set(id, cb);
|
|
199
|
+
if (isNew) {
|
|
200
|
+
this.ensureConnected();
|
|
201
|
+
this.sendSubscribe([streamName]);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
removeStreamCallback(streamName, id) {
|
|
205
|
+
const sub = this.streams.get(streamName);
|
|
206
|
+
if (!sub) return;
|
|
207
|
+
sub.callbacks.delete(id);
|
|
208
|
+
if (sub.callbacks.size === 0) {
|
|
209
|
+
this.streams.delete(streamName);
|
|
210
|
+
this.sendUnsubscribe([streamName]);
|
|
211
|
+
if (this.streams.size === 0 && this.ws) {
|
|
212
|
+
this.intentionalClose = true;
|
|
213
|
+
this.ws.close();
|
|
214
|
+
this.ws = null;
|
|
215
|
+
this.intentionalClose = false;
|
|
239
216
|
}
|
|
240
|
-
}
|
|
241
|
-
},
|
|
242
|
-
getToken: (address, chainId) => {
|
|
243
|
-
const key = symmAuthTokenKey(address, chainId);
|
|
244
|
-
return get().tokensByKey[key] ?? null;
|
|
245
|
-
},
|
|
246
|
-
clearToken: (address, chainId) => {
|
|
247
|
-
const key = symmAuthTokenKey(address, chainId);
|
|
248
|
-
set((state) => {
|
|
249
|
-
if (!(key in state.tokensByKey)) return state;
|
|
250
|
-
const next = { ...state.tokensByKey };
|
|
251
|
-
delete next[key];
|
|
252
|
-
return { tokensByKey: next };
|
|
253
|
-
});
|
|
254
|
-
},
|
|
255
|
-
clearAll: () => {
|
|
256
|
-
set({ tokensByKey: {} });
|
|
217
|
+
}
|
|
257
218
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
function useSymmAuth(params) {
|
|
262
|
-
const ctx = useSymmContext();
|
|
263
|
-
const address = params?.address ?? ctx.address;
|
|
264
|
-
const chainId = params?.chainId ?? ctx.chainId ?? 42161;
|
|
265
|
-
const walletClient = params?.walletClient ?? ctx.walletClient;
|
|
266
|
-
const siweDomain = params?.siweDomain;
|
|
267
|
-
const accessToken = useSymmAuthStore((state) => {
|
|
268
|
-
if (address) {
|
|
269
|
-
return state.tokensByKey[symmAuthTokenKey(address, chainId)] ?? null;
|
|
219
|
+
ensureConnected() {
|
|
220
|
+
if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {
|
|
221
|
+
return;
|
|
270
222
|
}
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if (
|
|
281
|
-
|
|
282
|
-
const inMemory = getToken(resolvedAccountAddress, chainId);
|
|
283
|
-
if (inMemory) {
|
|
284
|
-
return inMemory;
|
|
223
|
+
this.connect();
|
|
224
|
+
}
|
|
225
|
+
connect() {
|
|
226
|
+
if (typeof WebSocket === "undefined") return;
|
|
227
|
+
this.intentionalClose = false;
|
|
228
|
+
this.ws = new WebSocket(BINANCE_WS_URL);
|
|
229
|
+
this.ws.onopen = () => {
|
|
230
|
+
this.reconnectAttempt = 0;
|
|
231
|
+
const activeStreams = Array.from(this.streams.keys());
|
|
232
|
+
if (activeStreams.length > 0) {
|
|
233
|
+
this.sendSubscribe(activeStreams);
|
|
285
234
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
return cached;
|
|
235
|
+
if (this.pendingSubscribes.length > 0) {
|
|
236
|
+
this.sendSubscribe(this.pendingSubscribes);
|
|
237
|
+
this.pendingSubscribes = [];
|
|
290
238
|
}
|
|
239
|
+
};
|
|
240
|
+
this.ws.onmessage = (event) => {
|
|
291
241
|
try {
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
address,
|
|
295
|
-
resolvedAccountAddress,
|
|
296
|
-
chainId,
|
|
297
|
-
siweDomain
|
|
298
|
-
);
|
|
299
|
-
setToken(resolvedAccountAddress, chainId, token);
|
|
300
|
-
return token;
|
|
242
|
+
const data = JSON.parse(event.data);
|
|
243
|
+
this.handleMessage(data);
|
|
301
244
|
} catch {
|
|
302
|
-
clearToken(resolvedAccountAddress, chainId);
|
|
303
|
-
return null;
|
|
304
245
|
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const previousChainId = previousChainIdRef.current;
|
|
317
|
-
const addressChanged = previousAddress !== address;
|
|
318
|
-
const chainChanged = previousChainId !== chainId;
|
|
319
|
-
previousAddressRef.current = address;
|
|
320
|
-
previousChainIdRef.current = chainId;
|
|
321
|
-
if (!address || !walletClient) {
|
|
246
|
+
};
|
|
247
|
+
this.ws.onclose = () => {
|
|
248
|
+
if (this.intentionalClose) return;
|
|
249
|
+
this.scheduleReconnect();
|
|
250
|
+
};
|
|
251
|
+
this.ws.onerror = () => {
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
handleMessage(data) {
|
|
255
|
+
if (Array.isArray(data)) {
|
|
256
|
+
this.dispatchToStream("!markPrice@arr@1s", data);
|
|
322
257
|
return;
|
|
323
258
|
}
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
|
|
259
|
+
if (data.e === "kline") {
|
|
260
|
+
const k = data.k;
|
|
261
|
+
const streamName = `${data.s.toLowerCase()}@kline_${k.i}`;
|
|
262
|
+
this.dispatchToStream(streamName, data);
|
|
263
|
+
} else if (data.e === "markPriceUpdate") {
|
|
264
|
+
const streamName = `${data.s.toLowerCase()}@markPrice@1s`;
|
|
265
|
+
this.dispatchToStream(streamName, data);
|
|
327
266
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
267
|
+
}
|
|
268
|
+
dispatchToStream(streamName, data) {
|
|
269
|
+
const sub = this.streams.get(streamName);
|
|
270
|
+
if (!sub) return;
|
|
271
|
+
sub.callbacks.forEach((cb) => {
|
|
272
|
+
try {
|
|
273
|
+
cb(data);
|
|
274
|
+
} catch {
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
sendSubscribe(streams) {
|
|
279
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
280
|
+
this.pendingSubscribes.push(...streams);
|
|
281
|
+
return;
|
|
333
282
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
283
|
+
this.ws.send(JSON.stringify({
|
|
284
|
+
method: "SUBSCRIBE",
|
|
285
|
+
params: streams,
|
|
286
|
+
id: Date.now()
|
|
287
|
+
}));
|
|
288
|
+
}
|
|
289
|
+
sendUnsubscribe(streams) {
|
|
290
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
291
|
+
this.pendingSubscribes = this.pendingSubscribes.filter(
|
|
292
|
+
(s) => !streams.includes(s)
|
|
293
|
+
);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
this.ws.send(JSON.stringify({
|
|
297
|
+
method: "UNSUBSCRIBE",
|
|
298
|
+
params: streams,
|
|
299
|
+
id: Date.now()
|
|
300
|
+
}));
|
|
301
|
+
}
|
|
302
|
+
scheduleReconnect() {
|
|
303
|
+
if (this.reconnectTimer) return;
|
|
304
|
+
if (this.streams.size === 0) return;
|
|
305
|
+
const delay = RECONNECT_DELAYS[Math.min(this.reconnectAttempt, RECONNECT_DELAYS.length - 1)];
|
|
306
|
+
this.reconnectAttempt++;
|
|
307
|
+
this.reconnectTimer = setTimeout(() => {
|
|
308
|
+
this.reconnectTimer = null;
|
|
309
|
+
this.connect();
|
|
310
|
+
}, delay);
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
var _instance = null;
|
|
314
|
+
function getBinanceWsManager() {
|
|
315
|
+
if (!_instance) {
|
|
316
|
+
_instance = new BinanceWsManager();
|
|
317
|
+
}
|
|
318
|
+
return _instance;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/react/stores/use-binance-mark-price-store.ts
|
|
322
|
+
var refCounts = /* @__PURE__ */ new Map();
|
|
323
|
+
var streamSymbols = /* @__PURE__ */ new Map();
|
|
324
|
+
var allMarkPricesRefCount = 0;
|
|
325
|
+
var allMarkPricesUnsubscribe = null;
|
|
326
|
+
var STABLE_QUOTES2 = ["USDT0", "USDT", "USDC", "USDE", "USDH", "USD"];
|
|
327
|
+
function normalizeBinanceSymbol(symbol) {
|
|
328
|
+
const normalized = symbol.toUpperCase().trim();
|
|
329
|
+
for (const quote of STABLE_QUOTES2) {
|
|
330
|
+
if (normalized.endsWith(quote) && normalized.length > quote.length) {
|
|
331
|
+
return normalized.slice(0, -quote.length);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return normalized;
|
|
335
|
+
}
|
|
336
|
+
function getNextRefCount(binanceSymbol) {
|
|
337
|
+
return (refCounts.get(binanceSymbol) ?? 0) + 1;
|
|
338
|
+
}
|
|
339
|
+
function getPrevRefCount(binanceSymbol) {
|
|
340
|
+
return Math.max(0, (refCounts.get(binanceSymbol) ?? 0) - 1);
|
|
341
|
+
}
|
|
342
|
+
var useBinanceMarkPriceStore = create((set) => ({
|
|
343
|
+
markPrices: {},
|
|
344
|
+
subscribeSymbol: (symmSymbol, rawBinanceSymbol) => {
|
|
345
|
+
const binanceSymbol = normalizeBinanceSymbol(rawBinanceSymbol);
|
|
346
|
+
const nextRefCount = getNextRefCount(binanceSymbol);
|
|
347
|
+
refCounts.set(binanceSymbol, nextRefCount);
|
|
348
|
+
const symbols = streamSymbols.get(binanceSymbol) ?? /* @__PURE__ */ new Set();
|
|
349
|
+
symbols.add(symmSymbol);
|
|
350
|
+
streamSymbols.set(binanceSymbol, symbols);
|
|
351
|
+
if (allMarkPricesRefCount === 0) {
|
|
352
|
+
const wsManager = getBinanceWsManager();
|
|
353
|
+
allMarkPricesUnsubscribe = wsManager.subscribeAllMarkPrices((entries) => {
|
|
354
|
+
set((state) => {
|
|
355
|
+
let nextMarkPrices = null;
|
|
356
|
+
entries.forEach((entry) => {
|
|
357
|
+
const canonicalSymbol = normalizeBinanceSymbol(entry.symbol);
|
|
358
|
+
const mappedSymbols = streamSymbols.get(canonicalSymbol);
|
|
359
|
+
if (!mappedSymbols || mappedSymbols.size === 0) return;
|
|
360
|
+
nextMarkPrices ??= { ...state.markPrices };
|
|
361
|
+
mappedSymbols.forEach((mappedSymbol) => {
|
|
362
|
+
nextMarkPrices[mappedSymbol] = entry.markPrice;
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
return nextMarkPrices ? { markPrices: nextMarkPrices } : state;
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
allMarkPricesRefCount += 1;
|
|
370
|
+
},
|
|
371
|
+
unsubscribeSymbol: (symmSymbol, rawBinanceSymbol) => {
|
|
372
|
+
const binanceSymbol = normalizeBinanceSymbol(rawBinanceSymbol);
|
|
373
|
+
const symbols = streamSymbols.get(binanceSymbol);
|
|
374
|
+
if (symbols) {
|
|
375
|
+
symbols.delete(symmSymbol);
|
|
376
|
+
if (symbols.size === 0) {
|
|
377
|
+
streamSymbols.delete(binanceSymbol);
|
|
378
|
+
} else {
|
|
379
|
+
streamSymbols.set(binanceSymbol, symbols);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const nextRefCount = getPrevRefCount(binanceSymbol);
|
|
383
|
+
if (nextRefCount === 0) {
|
|
384
|
+
refCounts.delete(binanceSymbol);
|
|
385
|
+
} else {
|
|
386
|
+
refCounts.set(binanceSymbol, nextRefCount);
|
|
387
|
+
}
|
|
388
|
+
allMarkPricesRefCount = Math.max(0, allMarkPricesRefCount - 1);
|
|
389
|
+
if (allMarkPricesRefCount === 0) {
|
|
390
|
+
allMarkPricesUnsubscribe?.();
|
|
391
|
+
allMarkPricesUnsubscribe = null;
|
|
392
|
+
}
|
|
393
|
+
set((state) => {
|
|
394
|
+
if (state.markPrices[symmSymbol] == null) return state;
|
|
395
|
+
const nextMarkPrices = { ...state.markPrices };
|
|
396
|
+
delete nextMarkPrices[symmSymbol];
|
|
397
|
+
return { markPrices: nextMarkPrices };
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}));
|
|
401
|
+
|
|
402
|
+
// src/react/hooks/use-binance-ws.ts
|
|
403
|
+
function useBinanceWs(params) {
|
|
404
|
+
const { symmCoreClient, chainId } = params;
|
|
405
|
+
const subscribeSymbol = useBinanceMarkPriceStore((state) => state.subscribeSymbol);
|
|
406
|
+
const unsubscribeSymbol = useBinanceMarkPriceStore((state) => state.unsubscribeSymbol);
|
|
407
|
+
useEffect(() => {
|
|
408
|
+
if (!symmCoreClient) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
let cancelled = false;
|
|
412
|
+
let subscribedPairs = [];
|
|
413
|
+
const run = async () => {
|
|
414
|
+
try {
|
|
415
|
+
const result = await symmCoreClient.markets.listSymmHedger({ chainId });
|
|
416
|
+
if (cancelled) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const uniqueSymbols = Array.from(
|
|
420
|
+
new Set(
|
|
421
|
+
result.markets.map((market) => market.symbol).filter((symbol) => !!symbol)
|
|
422
|
+
)
|
|
423
|
+
);
|
|
424
|
+
subscribedPairs = uniqueSymbols.map((symbol) => {
|
|
425
|
+
const binanceSymbol = resolveBinanceSymbol(symbol).binanceSymbol;
|
|
426
|
+
if (!binanceSymbol) return null;
|
|
427
|
+
return [symbol, binanceSymbol];
|
|
428
|
+
}).filter((entry) => !!entry);
|
|
429
|
+
subscribedPairs.forEach(([symbol, binanceSymbol]) => {
|
|
430
|
+
subscribeSymbol(symbol, binanceSymbol);
|
|
431
|
+
});
|
|
432
|
+
} catch {
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
void run();
|
|
436
|
+
return () => {
|
|
437
|
+
cancelled = true;
|
|
438
|
+
subscribedPairs.forEach(([symbol, binanceSymbol]) => {
|
|
439
|
+
unsubscribeSymbol(symbol, binanceSymbol);
|
|
440
|
+
});
|
|
441
|
+
};
|
|
442
|
+
}, [symmCoreClient, chainId, subscribeSymbol, unsubscribeSymbol]);
|
|
443
|
+
}
|
|
444
|
+
function SymmProvider({
|
|
445
|
+
chainId = 42161,
|
|
446
|
+
address,
|
|
447
|
+
symmCoreConfig = {
|
|
448
|
+
apiUrl: "https://nginx-server-staging.up.railway.app",
|
|
449
|
+
wsUrl: "wss://nginx-server-staging.up.railway.app"
|
|
450
|
+
},
|
|
451
|
+
symmioConfig,
|
|
452
|
+
children
|
|
453
|
+
}) {
|
|
454
|
+
const symmCoreClient = useMemo(() => {
|
|
455
|
+
return createSymmSDK({
|
|
456
|
+
apiUrl: symmCoreConfig.apiUrl,
|
|
457
|
+
wsUrl: symmCoreConfig.wsUrl,
|
|
458
|
+
defaultChainId: chainId
|
|
459
|
+
});
|
|
460
|
+
}, [chainId, symmCoreConfig.apiUrl, symmCoreConfig.wsUrl]);
|
|
461
|
+
const value = useMemo(
|
|
462
|
+
() => ({
|
|
463
|
+
symmCoreClient,
|
|
464
|
+
chainId,
|
|
465
|
+
address,
|
|
466
|
+
symmioConfig
|
|
467
|
+
}),
|
|
468
|
+
[symmCoreClient, chainId, address, symmioConfig]
|
|
469
|
+
);
|
|
470
|
+
useBinanceWs({
|
|
471
|
+
symmCoreClient,
|
|
472
|
+
chainId
|
|
473
|
+
});
|
|
474
|
+
return /* @__PURE__ */ jsx(SymmContext.Provider, { value, children });
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// src/react/hooks/use-symm-core-client.ts
|
|
478
|
+
function useSymmCoreClient() {
|
|
479
|
+
return useSymmContext().symmCoreClient;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// src/constants/defaults.ts
|
|
483
|
+
var GAS_MARGIN_PERCENTAGE = 20n;
|
|
484
|
+
var MUON_BASE_URLS = [
|
|
485
|
+
"https://muon-oracle1.rasa.capital/v1/",
|
|
486
|
+
"https://muon-oracle2.rasa.capital/v1/",
|
|
487
|
+
"https://muon-oracle3.rasa.capital/v1/",
|
|
488
|
+
"https://muon-oracle4.rasa.capital/v1/"
|
|
489
|
+
];
|
|
490
|
+
var MUON_APP_NAME = "symmio";
|
|
491
|
+
var MUON_REQUEST_TIMEOUT = 15e3;
|
|
492
|
+
var HEDGER_BASE_URLS = {
|
|
493
|
+
[42161 /* ARBITRUM */]: "https://www.perps-streaming.com/v1/42161a/0x6273242a7E88b3De90822b31648C212215caaFE4",
|
|
494
|
+
[8453 /* BASE */]: "https://www.perps-streaming.com/v1/8453a/0x6273242a7E88b3De90822b31648C212215caaFE4"
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// src/actions/instant.ts
|
|
498
|
+
function getHedgerBaseUrl(chainId) {
|
|
499
|
+
const baseUrl = HEDGER_BASE_URLS[chainId];
|
|
500
|
+
if (!baseUrl) {
|
|
501
|
+
throw new Error(`No hedger base URL configured for chain ${chainId}.`);
|
|
502
|
+
}
|
|
503
|
+
return baseUrl;
|
|
504
|
+
}
|
|
505
|
+
function createSiweMessage(params) {
|
|
506
|
+
const version = params.version ?? "1";
|
|
507
|
+
const issuedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
508
|
+
const expirationTime = new Date(
|
|
509
|
+
Date.now() + 30 * 24 * 60 * 60 * 1e3
|
|
510
|
+
).toISOString();
|
|
511
|
+
const message = [
|
|
512
|
+
`${params.domain} wants you to sign in with your Ethereum account:`,
|
|
513
|
+
params.address,
|
|
514
|
+
"",
|
|
515
|
+
params.statement,
|
|
516
|
+
"",
|
|
517
|
+
`URI: ${params.uri}`,
|
|
518
|
+
`Version: ${version}`,
|
|
519
|
+
`Chain ID: ${params.chainId}`,
|
|
520
|
+
`Nonce: ${params.nonce}`,
|
|
521
|
+
`Issued At: ${issuedAt}`,
|
|
522
|
+
`Expiration Time: ${expirationTime}`
|
|
523
|
+
].join("\n");
|
|
524
|
+
return { message, issuedAt, expirationTime };
|
|
525
|
+
}
|
|
526
|
+
async function getNonce(chainId, subAccount) {
|
|
527
|
+
const hedgerBaseUrl = getHedgerBaseUrl(chainId);
|
|
528
|
+
const url = new URL(`nonce/${subAccount}`, hedgerBaseUrl).href;
|
|
529
|
+
const response = await fetch(url);
|
|
530
|
+
if (!response.ok) {
|
|
531
|
+
throw new Error(`Failed to fetch nonce: ${response.statusText}`);
|
|
532
|
+
}
|
|
533
|
+
const data = await response.json();
|
|
534
|
+
return data.nonce;
|
|
535
|
+
}
|
|
536
|
+
async function login(chainId, params) {
|
|
537
|
+
const hedgerBaseUrl = getHedgerBaseUrl(chainId);
|
|
538
|
+
const url = new URL("login", hedgerBaseUrl).href;
|
|
539
|
+
const body = {
|
|
540
|
+
account_address: params.accountAddress,
|
|
541
|
+
expiration_time: params.expirationTime,
|
|
542
|
+
issued_at: params.issuedAt,
|
|
543
|
+
signature: params.signature,
|
|
544
|
+
nonce: params.nonce
|
|
545
|
+
};
|
|
546
|
+
const response = await fetch(url, {
|
|
547
|
+
method: "POST",
|
|
548
|
+
headers: { "Content-Type": "application/json" },
|
|
549
|
+
body: JSON.stringify(body)
|
|
550
|
+
});
|
|
551
|
+
if (!response.ok) {
|
|
552
|
+
const errorData = await response.json().catch(() => null);
|
|
553
|
+
throw new Error(
|
|
554
|
+
errorData?.error_message ?? `Login failed: ${response.statusText}`
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
const data = await response.json();
|
|
558
|
+
if (!data.access_token) {
|
|
559
|
+
throw new Error("No access token received");
|
|
560
|
+
}
|
|
561
|
+
return {
|
|
562
|
+
accessToken: data.access_token,
|
|
563
|
+
expirationTime: params.expirationTime,
|
|
564
|
+
issuedAt: params.issuedAt
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// src/react/auth.ts
|
|
569
|
+
var TOKEN_STORAGE_PREFIX = "symm_access_token";
|
|
570
|
+
var TOKEN_STORAGE_VERSION = 1;
|
|
571
|
+
var tokenCache = /* @__PURE__ */ new Map();
|
|
572
|
+
function cacheKey(address, chainId) {
|
|
573
|
+
return `${address}:${chainId}`;
|
|
574
|
+
}
|
|
575
|
+
function storageKey(address, chainId) {
|
|
576
|
+
return `${TOKEN_STORAGE_PREFIX}:${TOKEN_STORAGE_VERSION}:${cacheKey(address, chainId)}`;
|
|
577
|
+
}
|
|
578
|
+
function readStoredToken(address, chainId) {
|
|
579
|
+
if (typeof window === "undefined") return null;
|
|
580
|
+
try {
|
|
581
|
+
const raw = window.localStorage.getItem(storageKey(address, chainId));
|
|
582
|
+
if (!raw) return null;
|
|
583
|
+
const parsed = JSON.parse(raw);
|
|
584
|
+
if (!parsed || typeof parsed.token !== "string" || typeof parsed.expiresAt !== "number") {
|
|
585
|
+
window.localStorage.removeItem(storageKey(address, chainId));
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
if (Date.now() >= parsed.expiresAt) {
|
|
589
|
+
window.localStorage.removeItem(storageKey(address, chainId));
|
|
590
|
+
return null;
|
|
591
|
+
}
|
|
592
|
+
return parsed;
|
|
593
|
+
} catch {
|
|
594
|
+
window.localStorage.removeItem(storageKey(address, chainId));
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function writeStoredToken(address, chainId, cached) {
|
|
599
|
+
if (typeof window === "undefined") return;
|
|
600
|
+
try {
|
|
601
|
+
window.localStorage.setItem(
|
|
602
|
+
storageKey(address, chainId),
|
|
603
|
+
JSON.stringify(cached)
|
|
604
|
+
);
|
|
605
|
+
} catch {
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
function getCachedToken(address, chainId) {
|
|
609
|
+
const cached = tokenCache.get(cacheKey(address, chainId));
|
|
610
|
+
if (cached && Date.now() < cached.expiresAt) {
|
|
611
|
+
return cached.token;
|
|
612
|
+
}
|
|
613
|
+
if (cached) {
|
|
614
|
+
tokenCache.delete(cacheKey(address, chainId));
|
|
615
|
+
}
|
|
616
|
+
const stored = readStoredToken(address, chainId);
|
|
617
|
+
if (!stored) return null;
|
|
618
|
+
tokenCache.set(cacheKey(address, chainId), stored);
|
|
619
|
+
return stored.token;
|
|
620
|
+
}
|
|
621
|
+
function clearCachedToken(address, chainId) {
|
|
622
|
+
tokenCache.delete(cacheKey(address, chainId));
|
|
623
|
+
if (typeof window !== "undefined") {
|
|
624
|
+
window.localStorage.removeItem(storageKey(address, chainId));
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
async function fetchAccessToken(walletClient, signerAddress, accountAddress, chainId, domain) {
|
|
628
|
+
const resolvedDomain = domain ?? (typeof window !== "undefined" ? window.location.host : "localhost");
|
|
629
|
+
const uri = typeof window !== "undefined" ? window.location.origin : `https://${resolvedDomain}`;
|
|
630
|
+
const nonce = await getNonce(chainId, accountAddress);
|
|
631
|
+
const { message, issuedAt, expirationTime } = createSiweMessage({
|
|
632
|
+
address: signerAddress,
|
|
633
|
+
statement: "Sign in to Symm Protocol",
|
|
634
|
+
chainId,
|
|
635
|
+
nonce,
|
|
636
|
+
domain: resolvedDomain,
|
|
637
|
+
uri
|
|
638
|
+
});
|
|
639
|
+
const signature = await walletClient.signMessage({
|
|
640
|
+
account: signerAddress,
|
|
641
|
+
message
|
|
642
|
+
});
|
|
643
|
+
const { accessToken } = await login(chainId, {
|
|
644
|
+
accountAddress,
|
|
645
|
+
signature,
|
|
646
|
+
expirationTime,
|
|
647
|
+
issuedAt,
|
|
648
|
+
nonce
|
|
649
|
+
});
|
|
650
|
+
const expiresAt = new Date(expirationTime).getTime();
|
|
651
|
+
const cachedToken = {
|
|
652
|
+
token: accessToken,
|
|
653
|
+
expiresAt: expiresAt - 6e4
|
|
654
|
+
};
|
|
655
|
+
tokenCache.set(cacheKey(accountAddress, chainId), cachedToken);
|
|
656
|
+
writeStoredToken(accountAddress, chainId, cachedToken);
|
|
657
|
+
return accessToken;
|
|
658
|
+
}
|
|
659
|
+
function symmAuthTokenKey(address, chainId) {
|
|
660
|
+
return `${address.toLowerCase()}:${chainId}`;
|
|
661
|
+
}
|
|
662
|
+
var useSymmAuthStore = create((set, get) => ({
|
|
663
|
+
tokensByKey: {},
|
|
664
|
+
setToken: (address, chainId, token) => {
|
|
665
|
+
const key = symmAuthTokenKey(address, chainId);
|
|
666
|
+
set((state) => ({
|
|
667
|
+
tokensByKey: {
|
|
668
|
+
...state.tokensByKey,
|
|
669
|
+
[key]: token
|
|
670
|
+
}
|
|
671
|
+
}));
|
|
672
|
+
},
|
|
673
|
+
getToken: (address, chainId) => {
|
|
674
|
+
const key = symmAuthTokenKey(address, chainId);
|
|
675
|
+
return get().tokensByKey[key] ?? null;
|
|
676
|
+
},
|
|
677
|
+
clearToken: (address, chainId) => {
|
|
678
|
+
const key = symmAuthTokenKey(address, chainId);
|
|
679
|
+
set((state) => {
|
|
680
|
+
if (!(key in state.tokensByKey)) return state;
|
|
681
|
+
const next = { ...state.tokensByKey };
|
|
682
|
+
delete next[key];
|
|
683
|
+
return { tokensByKey: next };
|
|
684
|
+
});
|
|
685
|
+
},
|
|
686
|
+
clearAll: () => {
|
|
687
|
+
set({ tokensByKey: {} });
|
|
688
|
+
}
|
|
689
|
+
}));
|
|
690
|
+
|
|
691
|
+
// src/react/hooks/use-symm-auth.ts
|
|
692
|
+
function useSymmAuth(params) {
|
|
693
|
+
const ctx = useSymmContext();
|
|
694
|
+
const address = params?.address ?? ctx.address;
|
|
695
|
+
const chainId = params?.chainId ?? ctx.chainId ?? 42161;
|
|
696
|
+
const walletClient = params?.walletClient ?? ctx.walletClient;
|
|
697
|
+
const siweDomain = params?.siweDomain;
|
|
698
|
+
const accessToken = useSymmAuthStore((state) => {
|
|
699
|
+
if (address) {
|
|
700
|
+
return state.tokensByKey[symmAuthTokenKey(address, chainId)] ?? null;
|
|
701
|
+
}
|
|
702
|
+
return ctx.accessToken ?? ctx.authToken ?? null;
|
|
703
|
+
});
|
|
704
|
+
const setToken = useSymmAuthStore((state) => state.setToken);
|
|
705
|
+
const getToken = useSymmAuthStore((state) => state.getToken);
|
|
706
|
+
const clearToken = useSymmAuthStore((state) => state.clearToken);
|
|
707
|
+
const previousAddressRef = useRef(address);
|
|
708
|
+
const previousChainIdRef = useRef(chainId);
|
|
709
|
+
const refreshAuth = useCallback(
|
|
710
|
+
async (accountAddress) => {
|
|
711
|
+
if (!walletClient || !address) return null;
|
|
712
|
+
const resolvedAccountAddress = accountAddress ?? address;
|
|
713
|
+
const inMemory = getToken(resolvedAccountAddress, chainId);
|
|
714
|
+
if (inMemory) {
|
|
715
|
+
return inMemory;
|
|
716
|
+
}
|
|
717
|
+
const cached = getCachedToken(resolvedAccountAddress, chainId);
|
|
718
|
+
if (cached) {
|
|
719
|
+
setToken(resolvedAccountAddress, chainId, cached);
|
|
720
|
+
return cached;
|
|
721
|
+
}
|
|
722
|
+
try {
|
|
723
|
+
const token = await fetchAccessToken(
|
|
724
|
+
walletClient,
|
|
725
|
+
address,
|
|
726
|
+
resolvedAccountAddress,
|
|
727
|
+
chainId,
|
|
728
|
+
siweDomain
|
|
729
|
+
);
|
|
730
|
+
setToken(resolvedAccountAddress, chainId, token);
|
|
731
|
+
return token;
|
|
732
|
+
} catch {
|
|
733
|
+
clearToken(resolvedAccountAddress, chainId);
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
[walletClient, address, chainId, siweDomain, getToken, setToken, clearToken]
|
|
738
|
+
);
|
|
739
|
+
const clearAuth = useCallback(() => {
|
|
740
|
+
if (address) {
|
|
741
|
+
clearCachedToken(address, chainId);
|
|
742
|
+
clearToken(address, chainId);
|
|
743
|
+
}
|
|
744
|
+
}, [address, chainId, clearToken]);
|
|
745
|
+
useEffect(() => {
|
|
746
|
+
const previousAddress = previousAddressRef.current;
|
|
747
|
+
const previousChainId = previousChainIdRef.current;
|
|
748
|
+
const addressChanged = previousAddress !== address;
|
|
749
|
+
const chainChanged = previousChainId !== chainId;
|
|
750
|
+
previousAddressRef.current = address;
|
|
751
|
+
previousChainIdRef.current = chainId;
|
|
752
|
+
if (!address || !walletClient) {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
if (previousAddress && (addressChanged || chainChanged)) {
|
|
756
|
+
clearCachedToken(previousAddress, previousChainId);
|
|
757
|
+
clearToken(previousAddress, previousChainId);
|
|
758
|
+
}
|
|
759
|
+
const cached = getCachedToken(address, chainId);
|
|
760
|
+
if (cached) {
|
|
761
|
+
setToken(address, chainId, cached);
|
|
762
|
+
} else {
|
|
763
|
+
clearToken(address, chainId);
|
|
764
|
+
}
|
|
765
|
+
}, [address, walletClient, chainId, setToken, clearToken]);
|
|
766
|
+
return {
|
|
767
|
+
accessToken,
|
|
768
|
+
authToken: accessToken,
|
|
769
|
+
isAuthenticated: !!accessToken,
|
|
770
|
+
refresh: refreshAuth,
|
|
771
|
+
refreshAuth,
|
|
772
|
+
clear: clearAuth
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// src/constants/selectors.ts
|
|
777
|
+
var SEND_QUOTE_WITH_AFFILIATE_SELECTOR = "0x40f1310c";
|
|
778
|
+
var CLOSE_QUOTE_SELECTOR = "0x501e891f";
|
|
779
|
+
var ALL_TRADING_SELECTORS = [
|
|
780
|
+
SEND_QUOTE_WITH_AFFILIATE_SELECTOR,
|
|
781
|
+
CLOSE_QUOTE_SELECTOR
|
|
782
|
+
];
|
|
783
|
+
|
|
353
784
|
// src/constants/addresses.ts
|
|
354
785
|
var MULTI_ACCOUNT_ADDRESS = {
|
|
355
786
|
[42161 /* ARBITRUM */]: "0x6273242a7E88b3De90822b31648C212215caaFE4",
|
|
@@ -24522,852 +24953,540 @@ function useSymmAccountSummary(params) {
|
|
|
24522
24953
|
userAddress,
|
|
24523
24954
|
chainId
|
|
24524
24955
|
}),
|
|
24525
|
-
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
24526
|
-
});
|
|
24527
|
-
}
|
|
24528
|
-
function useSymmAccountData(params) {
|
|
24529
|
-
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24530
|
-
const { address, upnl } = params;
|
|
24531
|
-
const chainId = params.chainId ?? ctxChainId;
|
|
24532
|
-
const internalEnabled = !!symmCoreClient && !!address;
|
|
24533
|
-
return useQuery({
|
|
24534
|
-
...params.query,
|
|
24535
|
-
queryKey: symmKeys.accountData(address, chainId, upnl),
|
|
24536
|
-
queryFn: () => symmCoreClient.accounts.getData({
|
|
24537
|
-
address,
|
|
24538
|
-
chainId,
|
|
24539
|
-
upnl
|
|
24540
|
-
}),
|
|
24541
|
-
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
24542
|
-
});
|
|
24543
|
-
}
|
|
24544
|
-
function useSymmBalances(params) {
|
|
24545
|
-
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24546
|
-
const { userAddress, multiAccountAddress } = params;
|
|
24547
|
-
const chainId = params.chainId ?? ctxChainId;
|
|
24548
|
-
const internalEnabled = !!symmCoreClient && !!userAddress;
|
|
24549
|
-
return useQuery({
|
|
24550
|
-
...params.query,
|
|
24551
|
-
queryKey: symmKeys.balances(userAddress, chainId),
|
|
24552
|
-
queryFn: () => symmCoreClient.accounts.getBalanceInfo({
|
|
24553
|
-
userAddress,
|
|
24554
|
-
chainId,
|
|
24555
|
-
multiAccountAddress
|
|
24556
|
-
}),
|
|
24557
|
-
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
24558
|
-
});
|
|
24559
|
-
}
|
|
24560
|
-
function useResolveTradeAuthToken() {
|
|
24561
|
-
const context = useSymmContext();
|
|
24562
|
-
const { address, chainId } = context;
|
|
24563
|
-
const { refreshAuth } = useSymmAuth({ address, chainId });
|
|
24564
|
-
const refreshAuthFromContext = context.refreshAuth;
|
|
24565
|
-
return useCallback(
|
|
24566
|
-
async (providedAuthToken, accountAddress) => {
|
|
24567
|
-
if (providedAuthToken) {
|
|
24568
|
-
return providedAuthToken;
|
|
24569
|
-
}
|
|
24570
|
-
const resolvedAccountAddress = accountAddress ?? address;
|
|
24571
|
-
if (!resolvedAccountAddress) {
|
|
24572
|
-
return null;
|
|
24573
|
-
}
|
|
24574
|
-
const inMemoryToken = useSymmAuthStore.getState().getToken(resolvedAccountAddress, chainId);
|
|
24575
|
-
if (inMemoryToken) {
|
|
24576
|
-
return inMemoryToken;
|
|
24577
|
-
}
|
|
24578
|
-
if (refreshAuthFromContext) {
|
|
24579
|
-
return refreshAuthFromContext(resolvedAccountAddress);
|
|
24580
|
-
}
|
|
24581
|
-
return refreshAuth(resolvedAccountAddress);
|
|
24582
|
-
},
|
|
24583
|
-
[address, chainId, refreshAuth, refreshAuthFromContext]
|
|
24584
|
-
);
|
|
24585
|
-
}
|
|
24586
|
-
function useSymmOpenBasketMutation(options) {
|
|
24587
|
-
const { symmCoreClient } = useSymmContext();
|
|
24588
|
-
const queryClient = useQueryClient();
|
|
24589
|
-
return useMutation({
|
|
24590
|
-
...withSymmMutationConfig(options?.mutation, {
|
|
24591
|
-
onSuccess: () => {
|
|
24592
|
-
invalidatePositions(queryClient);
|
|
24593
|
-
}
|
|
24594
|
-
}),
|
|
24595
|
-
mutationFn: async (request) => {
|
|
24596
|
-
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
24597
|
-
return symmCoreClient.positions.openBasket(request);
|
|
24598
|
-
}
|
|
24599
|
-
});
|
|
24600
|
-
}
|
|
24601
|
-
function useSymmClosePositionMutation(options) {
|
|
24602
|
-
const { symmCoreClient } = useSymmContext();
|
|
24603
|
-
const queryClient = useQueryClient();
|
|
24604
|
-
const resolveAuthToken = useResolveTradeAuthToken();
|
|
24605
|
-
return useMutation({
|
|
24606
|
-
...withSymmMutationConfig(options?.mutation, {
|
|
24607
|
-
onSuccess: () => {
|
|
24608
|
-
invalidatePositions(queryClient);
|
|
24609
|
-
}
|
|
24610
|
-
}),
|
|
24611
|
-
mutationFn: async (request) => {
|
|
24612
|
-
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
24613
|
-
const typedRequest = request;
|
|
24614
|
-
const authToken = await resolveAuthToken(
|
|
24615
|
-
typedRequest.authToken,
|
|
24616
|
-
typedRequest.accountAddress
|
|
24617
|
-
);
|
|
24618
|
-
if (!authToken) {
|
|
24619
|
-
throw new Error("auth token is required to close a position");
|
|
24620
|
-
}
|
|
24621
|
-
return symmCoreClient.positions.close({
|
|
24622
|
-
...request,
|
|
24623
|
-
authToken
|
|
24624
|
-
});
|
|
24625
|
-
}
|
|
24626
|
-
});
|
|
24627
|
-
}
|
|
24628
|
-
function useSymmCloseAllPositionsMutation(options) {
|
|
24629
|
-
const { symmCoreClient } = useSymmContext();
|
|
24630
|
-
const queryClient = useQueryClient();
|
|
24631
|
-
return useMutation({
|
|
24632
|
-
...withSymmMutationConfig(options?.mutation, {
|
|
24633
|
-
onSuccess: () => {
|
|
24634
|
-
invalidatePositions(queryClient);
|
|
24635
|
-
}
|
|
24636
|
-
}),
|
|
24637
|
-
mutationFn: async (request) => {
|
|
24638
|
-
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
24639
|
-
return symmCoreClient.positions.closeAll(request);
|
|
24640
|
-
}
|
|
24641
|
-
});
|
|
24642
|
-
}
|
|
24643
|
-
function useSymmCancelOpenMutation(options) {
|
|
24644
|
-
const { symmCoreClient } = useSymmContext();
|
|
24645
|
-
const queryClient = useQueryClient();
|
|
24646
|
-
return useMutation({
|
|
24647
|
-
...withSymmMutationConfig(options?.mutation, {
|
|
24648
|
-
onSuccess: () => {
|
|
24649
|
-
invalidatePositions(queryClient);
|
|
24650
|
-
}
|
|
24651
|
-
}),
|
|
24652
|
-
mutationFn: async (request) => {
|
|
24653
|
-
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
24654
|
-
return symmCoreClient.positions.cancelOpen(request);
|
|
24655
|
-
}
|
|
24656
|
-
});
|
|
24657
|
-
}
|
|
24658
|
-
function useSymmUpdatePositionMutation(options) {
|
|
24659
|
-
const { symmCoreClient } = useSymmContext();
|
|
24660
|
-
const queryClient = useQueryClient();
|
|
24661
|
-
const resolveAuthToken = useResolveTradeAuthToken();
|
|
24662
|
-
return useMutation({
|
|
24663
|
-
...withSymmMutationConfig(options?.mutation, {
|
|
24664
|
-
onSuccess: () => {
|
|
24665
|
-
invalidatePositions(queryClient);
|
|
24666
|
-
}
|
|
24667
|
-
}),
|
|
24668
|
-
mutationFn: async ({
|
|
24669
|
-
positionId,
|
|
24670
|
-
request
|
|
24671
|
-
}) => {
|
|
24672
|
-
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
24673
|
-
const typedRequest = request;
|
|
24674
|
-
const authToken = await resolveAuthToken(
|
|
24675
|
-
typedRequest.authToken,
|
|
24676
|
-
typedRequest.accountAddress
|
|
24677
|
-
);
|
|
24678
|
-
if (!authToken) {
|
|
24679
|
-
throw new Error("auth token is required to update a position");
|
|
24680
|
-
}
|
|
24681
|
-
return symmCoreClient.positions.update(positionId, {
|
|
24682
|
-
...request,
|
|
24683
|
-
authToken
|
|
24684
|
-
});
|
|
24685
|
-
}
|
|
24686
|
-
});
|
|
24687
|
-
}
|
|
24688
|
-
function useSymmPositions(params) {
|
|
24689
|
-
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24690
|
-
const { accountAddress, address } = params;
|
|
24691
|
-
const resolvedAddress = accountAddress ? void 0 : address;
|
|
24692
|
-
const chainId = params.chainId ?? ctxChainId;
|
|
24693
|
-
const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress);
|
|
24694
|
-
const enabled = internalEnabled && (params.query?.enabled ?? true);
|
|
24695
|
-
return useQuery({
|
|
24696
|
-
...params.query,
|
|
24697
|
-
queryKey: symmKeys.positions({
|
|
24698
|
-
accountAddress,
|
|
24699
|
-
address: resolvedAddress,
|
|
24700
|
-
chainId
|
|
24701
|
-
}),
|
|
24702
|
-
queryFn: () => symmCoreClient.positions.getOpen({
|
|
24703
|
-
accountAddress,
|
|
24704
|
-
address: resolvedAddress,
|
|
24705
|
-
chainId
|
|
24706
|
-
}),
|
|
24707
|
-
enabled
|
|
24956
|
+
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
24708
24957
|
});
|
|
24709
24958
|
}
|
|
24710
|
-
function
|
|
24959
|
+
function useSymmAccountData(params) {
|
|
24711
24960
|
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24712
|
-
const {
|
|
24713
|
-
const resolvedAddress = accountAddress ? void 0 : address;
|
|
24961
|
+
const { address, upnl } = params;
|
|
24714
24962
|
const chainId = params.chainId ?? ctxChainId;
|
|
24715
|
-
const internalEnabled = !!symmCoreClient && !!
|
|
24963
|
+
const internalEnabled = !!symmCoreClient && !!address;
|
|
24716
24964
|
return useQuery({
|
|
24717
24965
|
...params.query,
|
|
24718
|
-
queryKey: symmKeys.
|
|
24719
|
-
|
|
24720
|
-
address
|
|
24721
|
-
chainId
|
|
24722
|
-
|
|
24723
|
-
queryFn: () => symmCoreClient.orders.list({
|
|
24724
|
-
address: accountAddress ?? resolvedAddress,
|
|
24725
|
-
chainId
|
|
24966
|
+
queryKey: symmKeys.accountData(address, chainId, upnl),
|
|
24967
|
+
queryFn: () => symmCoreClient.accounts.getData({
|
|
24968
|
+
address,
|
|
24969
|
+
chainId,
|
|
24970
|
+
upnl
|
|
24726
24971
|
}),
|
|
24727
24972
|
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
24728
24973
|
});
|
|
24729
24974
|
}
|
|
24730
|
-
function
|
|
24975
|
+
function useSymmBalances(params) {
|
|
24731
24976
|
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24732
|
-
const {
|
|
24733
|
-
const resolvedAddress = accountAddress ? void 0 : address;
|
|
24977
|
+
const { userAddress, multiAccountAddress } = params;
|
|
24734
24978
|
const chainId = params.chainId ?? ctxChainId;
|
|
24735
|
-
const internalEnabled = !!symmCoreClient && !!
|
|
24979
|
+
const internalEnabled = !!symmCoreClient && !!userAddress;
|
|
24736
24980
|
return useQuery({
|
|
24737
24981
|
...params.query,
|
|
24738
|
-
queryKey: symmKeys.
|
|
24739
|
-
|
|
24740
|
-
|
|
24741
|
-
chainId
|
|
24982
|
+
queryKey: symmKeys.balances(userAddress, chainId),
|
|
24983
|
+
queryFn: () => symmCoreClient.accounts.getBalanceInfo({
|
|
24984
|
+
userAddress,
|
|
24985
|
+
chainId,
|
|
24986
|
+
multiAccountAddress
|
|
24742
24987
|
}),
|
|
24743
|
-
queryFn: () => {
|
|
24744
|
-
const request = {
|
|
24745
|
-
accountAddress,
|
|
24746
|
-
address: resolvedAddress,
|
|
24747
|
-
chainId
|
|
24748
|
-
};
|
|
24749
|
-
return symmCoreClient.positions.getTradeHistory(request);
|
|
24750
|
-
},
|
|
24751
24988
|
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
24752
24989
|
});
|
|
24753
24990
|
}
|
|
24754
|
-
function
|
|
24991
|
+
function useResolveTradeAuthToken() {
|
|
24992
|
+
const context = useSymmContext();
|
|
24993
|
+
const { address, chainId } = context;
|
|
24994
|
+
const { refreshAuth } = useSymmAuth({ address, chainId });
|
|
24995
|
+
const refreshAuthFromContext = context.refreshAuth;
|
|
24996
|
+
return useCallback(
|
|
24997
|
+
async (providedAuthToken, accountAddress) => {
|
|
24998
|
+
if (providedAuthToken) {
|
|
24999
|
+
return providedAuthToken;
|
|
25000
|
+
}
|
|
25001
|
+
const resolvedAccountAddress = accountAddress ?? address;
|
|
25002
|
+
if (!resolvedAccountAddress) {
|
|
25003
|
+
return null;
|
|
25004
|
+
}
|
|
25005
|
+
const inMemoryToken = useSymmAuthStore.getState().getToken(resolvedAccountAddress, chainId);
|
|
25006
|
+
if (inMemoryToken) {
|
|
25007
|
+
return inMemoryToken;
|
|
25008
|
+
}
|
|
25009
|
+
if (refreshAuthFromContext) {
|
|
25010
|
+
return refreshAuthFromContext(resolvedAccountAddress);
|
|
25011
|
+
}
|
|
25012
|
+
return refreshAuth(resolvedAccountAddress);
|
|
25013
|
+
},
|
|
25014
|
+
[address, chainId, refreshAuth, refreshAuthFromContext]
|
|
25015
|
+
);
|
|
25016
|
+
}
|
|
25017
|
+
function useSymmOpenBasketMutation(options) {
|
|
24755
25018
|
const { symmCoreClient } = useSymmContext();
|
|
24756
25019
|
const queryClient = useQueryClient();
|
|
24757
25020
|
return useMutation({
|
|
24758
25021
|
...withSymmMutationConfig(options?.mutation, {
|
|
24759
25022
|
onSuccess: () => {
|
|
24760
|
-
invalidateOrders(queryClient);
|
|
24761
25023
|
invalidatePositions(queryClient);
|
|
24762
25024
|
}
|
|
24763
25025
|
}),
|
|
24764
25026
|
mutationFn: async (request) => {
|
|
24765
25027
|
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
24766
|
-
return symmCoreClient.
|
|
25028
|
+
return symmCoreClient.positions.openBasket(request);
|
|
24767
25029
|
}
|
|
24768
25030
|
});
|
|
24769
25031
|
}
|
|
24770
|
-
function
|
|
25032
|
+
function useSymmClosePositionMutation(options) {
|
|
24771
25033
|
const { symmCoreClient } = useSymmContext();
|
|
24772
25034
|
const queryClient = useQueryClient();
|
|
25035
|
+
const resolveAuthToken = useResolveTradeAuthToken();
|
|
24773
25036
|
return useMutation({
|
|
24774
25037
|
...withSymmMutationConfig(options?.mutation, {
|
|
24775
25038
|
onSuccess: () => {
|
|
24776
|
-
invalidateOrders(queryClient);
|
|
24777
25039
|
invalidatePositions(queryClient);
|
|
24778
25040
|
}
|
|
24779
25041
|
}),
|
|
24780
25042
|
mutationFn: async (request) => {
|
|
24781
25043
|
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
24782
|
-
|
|
25044
|
+
const typedRequest = request;
|
|
25045
|
+
const authToken = await resolveAuthToken(
|
|
25046
|
+
typedRequest.authToken,
|
|
25047
|
+
typedRequest.accountAddress
|
|
25048
|
+
);
|
|
25049
|
+
if (!authToken) {
|
|
25050
|
+
throw new Error("auth token is required to close a position");
|
|
25051
|
+
}
|
|
25052
|
+
return symmCoreClient.positions.close({
|
|
25053
|
+
...request,
|
|
25054
|
+
authToken
|
|
25055
|
+
});
|
|
24783
25056
|
}
|
|
24784
25057
|
});
|
|
24785
25058
|
}
|
|
24786
|
-
function
|
|
24787
|
-
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24788
|
-
const { accountAddress, address, positionId, type, status } = params;
|
|
24789
|
-
const resolvedAddress = accountAddress ? void 0 : address;
|
|
24790
|
-
const chainId = params.chainId ?? ctxChainId;
|
|
24791
|
-
const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress || positionId);
|
|
24792
|
-
const request = {
|
|
24793
|
-
address: accountAddress ?? resolvedAddress,
|
|
24794
|
-
positionId,
|
|
24795
|
-
type,
|
|
24796
|
-
status,
|
|
24797
|
-
chainId
|
|
24798
|
-
};
|
|
24799
|
-
return useQuery({
|
|
24800
|
-
...params.query,
|
|
24801
|
-
queryKey: symmKeys.tpslOrdersList({
|
|
24802
|
-
accountAddress,
|
|
24803
|
-
address: resolvedAddress,
|
|
24804
|
-
positionId,
|
|
24805
|
-
type,
|
|
24806
|
-
status,
|
|
24807
|
-
chainId
|
|
24808
|
-
}),
|
|
24809
|
-
queryFn: () => symmCoreClient.orders.getTpslOrders(request),
|
|
24810
|
-
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
24811
|
-
});
|
|
24812
|
-
}
|
|
24813
|
-
function useResolvedTwapParams(params) {
|
|
24814
|
-
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24815
|
-
const { accountAddress, address } = params;
|
|
24816
|
-
const resolvedAddress = accountAddress ? void 0 : address;
|
|
24817
|
-
const chainId = params.chainId ?? ctxChainId;
|
|
24818
|
-
return { symmCoreClient, accountAddress, resolvedAddress, chainId, query: params.query };
|
|
24819
|
-
}
|
|
24820
|
-
function useSymmTwapOrdersQuery(params) {
|
|
24821
|
-
const { symmCoreClient, accountAddress, resolvedAddress, chainId, query } = useResolvedTwapParams(params);
|
|
24822
|
-
const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress);
|
|
24823
|
-
return useQuery({
|
|
24824
|
-
...query,
|
|
24825
|
-
queryKey: symmKeys.twapOrders(accountAddress ?? resolvedAddress, chainId),
|
|
24826
|
-
queryFn: () => symmCoreClient.orders.getTwapOrders({
|
|
24827
|
-
address: accountAddress ?? resolvedAddress,
|
|
24828
|
-
chainId
|
|
24829
|
-
}),
|
|
24830
|
-
enabled: internalEnabled && (query?.enabled ?? true)
|
|
24831
|
-
});
|
|
24832
|
-
}
|
|
24833
|
-
function useSymmCancelTwapOrderMutation(options) {
|
|
25059
|
+
function useSymmCloseAllPositionsMutation(options) {
|
|
24834
25060
|
const { symmCoreClient } = useSymmContext();
|
|
24835
25061
|
const queryClient = useQueryClient();
|
|
24836
25062
|
return useMutation({
|
|
24837
25063
|
...withSymmMutationConfig(options?.mutation, {
|
|
24838
25064
|
onSuccess: () => {
|
|
24839
|
-
|
|
25065
|
+
invalidatePositions(queryClient);
|
|
24840
25066
|
}
|
|
24841
25067
|
}),
|
|
24842
|
-
mutationFn: async (
|
|
25068
|
+
mutationFn: async (request) => {
|
|
24843
25069
|
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
24844
|
-
return symmCoreClient.
|
|
25070
|
+
return symmCoreClient.positions.closeAll(request);
|
|
24845
25071
|
}
|
|
24846
25072
|
});
|
|
24847
25073
|
}
|
|
24848
|
-
function
|
|
24849
|
-
const { symmCoreClient } = useSymmContext();
|
|
24850
|
-
const { orderId } = params;
|
|
24851
|
-
const internalEnabled = !!symmCoreClient && !!orderId;
|
|
24852
|
-
return useQuery({
|
|
24853
|
-
...params.query,
|
|
24854
|
-
queryKey: symmKeys.triggerConfig(orderId),
|
|
24855
|
-
queryFn: () => symmCoreClient.orders.getTriggerConfig(orderId),
|
|
24856
|
-
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
24857
|
-
});
|
|
24858
|
-
}
|
|
24859
|
-
function useSymmSetTriggerConfigMutation(params, options) {
|
|
25074
|
+
function useSymmCancelOpenMutation(options) {
|
|
24860
25075
|
const { symmCoreClient } = useSymmContext();
|
|
24861
|
-
const { orderId } = params;
|
|
24862
25076
|
const queryClient = useQueryClient();
|
|
24863
25077
|
return useMutation({
|
|
24864
25078
|
...withSymmMutationConfig(options?.mutation, {
|
|
24865
25079
|
onSuccess: () => {
|
|
24866
|
-
queryClient
|
|
24867
|
-
queryKey: symmKeys.triggerConfig(orderId)
|
|
24868
|
-
});
|
|
24869
|
-
invalidateOrders(queryClient);
|
|
25080
|
+
invalidatePositions(queryClient);
|
|
24870
25081
|
}
|
|
24871
25082
|
}),
|
|
24872
25083
|
mutationFn: async (request) => {
|
|
24873
|
-
if (!symmCoreClient
|
|
24874
|
-
|
|
24875
|
-
}
|
|
24876
|
-
return symmCoreClient.orders.setTriggerConfig(orderId, request);
|
|
25084
|
+
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
25085
|
+
return symmCoreClient.positions.cancelOpen(request);
|
|
24877
25086
|
}
|
|
24878
25087
|
});
|
|
24879
25088
|
}
|
|
24880
|
-
function
|
|
25089
|
+
function useSymmUpdatePositionMutation(options) {
|
|
24881
25090
|
const { symmCoreClient } = useSymmContext();
|
|
24882
|
-
const { orderId } = params;
|
|
24883
25091
|
const queryClient = useQueryClient();
|
|
25092
|
+
const resolveAuthToken = useResolveTradeAuthToken();
|
|
24884
25093
|
return useMutation({
|
|
24885
25094
|
...withSymmMutationConfig(options?.mutation, {
|
|
24886
25095
|
onSuccess: () => {
|
|
24887
|
-
queryClient
|
|
24888
|
-
queryKey: symmKeys.triggerConfig(orderId)
|
|
24889
|
-
});
|
|
24890
|
-
invalidateOrders(queryClient);
|
|
24891
|
-
}
|
|
24892
|
-
}),
|
|
24893
|
-
mutationFn: async () => {
|
|
24894
|
-
if (!symmCoreClient || !orderId) {
|
|
24895
|
-
throw new Error("symm-core client or orderId not available");
|
|
25096
|
+
invalidatePositions(queryClient);
|
|
24896
25097
|
}
|
|
24897
|
-
return symmCoreClient.orders.clearTriggerConfig(orderId);
|
|
24898
|
-
}
|
|
24899
|
-
});
|
|
24900
|
-
}
|
|
24901
|
-
function useSymmTriggerOrders(params) {
|
|
24902
|
-
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24903
|
-
const { accountAddress, address, status, limit, offset } = params;
|
|
24904
|
-
const resolvedAddress = accountAddress ? void 0 : address;
|
|
24905
|
-
const chainId = params.chainId ?? ctxChainId;
|
|
24906
|
-
const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress);
|
|
24907
|
-
const request = {
|
|
24908
|
-
address: accountAddress ?? resolvedAddress,
|
|
24909
|
-
chainId,
|
|
24910
|
-
status,
|
|
24911
|
-
limit,
|
|
24912
|
-
offset
|
|
24913
|
-
};
|
|
24914
|
-
return useQuery({
|
|
24915
|
-
...params.query,
|
|
24916
|
-
queryKey: symmKeys.triggerOrders({
|
|
24917
|
-
accountAddress,
|
|
24918
|
-
address: resolvedAddress,
|
|
24919
|
-
chainId,
|
|
24920
|
-
status,
|
|
24921
|
-
limit,
|
|
24922
|
-
offset
|
|
24923
25098
|
}),
|
|
24924
|
-
|
|
24925
|
-
|
|
24926
|
-
|
|
24927
|
-
}
|
|
24928
|
-
|
|
24929
|
-
|
|
24930
|
-
|
|
24931
|
-
|
|
24932
|
-
|
|
24933
|
-
|
|
24934
|
-
|
|
24935
|
-
|
|
24936
|
-
|
|
24937
|
-
|
|
24938
|
-
|
|
24939
|
-
|
|
24940
|
-
|
|
24941
|
-
}
|
|
24942
|
-
enabled: internalEnabled && (params?.query?.enabled ?? true)
|
|
24943
|
-
});
|
|
24944
|
-
}
|
|
24945
|
-
function useSymmHedgerMarketById(params) {
|
|
24946
|
-
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24947
|
-
const { id } = params;
|
|
24948
|
-
const chainId = params.chainId ?? ctxChainId;
|
|
24949
|
-
const internalEnabled = !!symmCoreClient && id != null;
|
|
24950
|
-
return useQuery({
|
|
24951
|
-
...params.query,
|
|
24952
|
-
queryKey: symmKeys.hedgerMarketById(id, chainId),
|
|
24953
|
-
queryFn: () => symmCoreClient.markets.getById(id, chainId),
|
|
24954
|
-
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
25099
|
+
mutationFn: async ({
|
|
25100
|
+
positionId,
|
|
25101
|
+
request
|
|
25102
|
+
}) => {
|
|
25103
|
+
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
25104
|
+
const typedRequest = request;
|
|
25105
|
+
const authToken = await resolveAuthToken(
|
|
25106
|
+
typedRequest.authToken,
|
|
25107
|
+
typedRequest.accountAddress
|
|
25108
|
+
);
|
|
25109
|
+
if (!authToken) {
|
|
25110
|
+
throw new Error("auth token is required to update a position");
|
|
25111
|
+
}
|
|
25112
|
+
return symmCoreClient.positions.update(positionId, {
|
|
25113
|
+
...request,
|
|
25114
|
+
authToken
|
|
25115
|
+
});
|
|
25116
|
+
}
|
|
24955
25117
|
});
|
|
24956
25118
|
}
|
|
24957
|
-
function
|
|
25119
|
+
function useSymmPositions(params) {
|
|
24958
25120
|
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24959
|
-
const {
|
|
25121
|
+
const { accountAddress, address } = params;
|
|
25122
|
+
const resolvedAddress = accountAddress ? void 0 : address;
|
|
24960
25123
|
const chainId = params.chainId ?? ctxChainId;
|
|
24961
|
-
const internalEnabled = !!symmCoreClient && !!
|
|
25124
|
+
const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress);
|
|
25125
|
+
const enabled = internalEnabled && (params.query?.enabled ?? true);
|
|
24962
25126
|
return useQuery({
|
|
24963
25127
|
...params.query,
|
|
24964
|
-
queryKey: symmKeys.
|
|
24965
|
-
|
|
24966
|
-
|
|
25128
|
+
queryKey: symmKeys.positions({
|
|
25129
|
+
accountAddress,
|
|
25130
|
+
address: resolvedAddress,
|
|
25131
|
+
chainId
|
|
25132
|
+
}),
|
|
25133
|
+
queryFn: () => symmCoreClient.positions.getOpen({
|
|
25134
|
+
accountAddress,
|
|
25135
|
+
address: resolvedAddress,
|
|
25136
|
+
chainId
|
|
25137
|
+
}),
|
|
25138
|
+
enabled
|
|
24967
25139
|
});
|
|
24968
25140
|
}
|
|
24969
|
-
function
|
|
25141
|
+
function useSymmOpenOrders(params) {
|
|
24970
25142
|
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24971
|
-
const {
|
|
25143
|
+
const { accountAddress, address } = params;
|
|
25144
|
+
const resolvedAddress = accountAddress ? void 0 : address;
|
|
24972
25145
|
const chainId = params.chainId ?? ctxChainId;
|
|
24973
|
-
const internalEnabled = !!symmCoreClient && !!
|
|
25146
|
+
const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress);
|
|
24974
25147
|
return useQuery({
|
|
24975
25148
|
...params.query,
|
|
24976
|
-
queryKey: symmKeys.
|
|
24977
|
-
|
|
24978
|
-
|
|
24979
|
-
|
|
25149
|
+
queryKey: symmKeys.openOrders({
|
|
25150
|
+
accountAddress,
|
|
25151
|
+
address: resolvedAddress,
|
|
25152
|
+
chainId
|
|
25153
|
+
}),
|
|
25154
|
+
queryFn: () => symmCoreClient.orders.list({
|
|
25155
|
+
address: accountAddress ?? resolvedAddress,
|
|
24980
25156
|
chainId
|
|
24981
25157
|
}),
|
|
24982
25158
|
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
24983
|
-
});
|
|
24984
|
-
}
|
|
24985
|
-
function
|
|
24986
|
-
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
24987
|
-
const
|
|
24988
|
-
const
|
|
24989
|
-
const
|
|
24990
|
-
const
|
|
24991
|
-
|
|
24992
|
-
...
|
|
24993
|
-
|
|
24994
|
-
|
|
24995
|
-
|
|
24996
|
-
|
|
24997
|
-
|
|
24998
|
-
|
|
24999
|
-
|
|
25000
|
-
|
|
25001
|
-
|
|
25002
|
-
|
|
25003
|
-
}
|
|
25004
|
-
|
|
25005
|
-
|
|
25006
|
-
|
|
25007
|
-
|
|
25008
|
-
|
|
25009
|
-
|
|
25010
|
-
|
|
25011
|
-
|
|
25012
|
-
|
|
25013
|
-
|
|
25014
|
-
|
|
25015
|
-
|
|
25016
|
-
|
|
25017
|
-
throw new Error(`Binance markPriceKlines failed: ${response.status}`);
|
|
25018
|
-
}
|
|
25019
|
-
const data = await response.json();
|
|
25020
|
-
return data.map((k) => ({
|
|
25021
|
-
openTime: Number(k[0]),
|
|
25022
|
-
open: parseFloat(k[1]),
|
|
25023
|
-
high: parseFloat(k[2]),
|
|
25024
|
-
low: parseFloat(k[3]),
|
|
25025
|
-
close: parseFloat(k[4]),
|
|
25026
|
-
volume: parseFloat(k[5]),
|
|
25027
|
-
closeTime: Number(k[6])
|
|
25028
|
-
}));
|
|
25029
|
-
}
|
|
25030
|
-
async function fetch24hrTicker(symbol) {
|
|
25031
|
-
const params = new URLSearchParams({ symbol });
|
|
25032
|
-
const response = await fetch(`${BINANCE_FAPI_BASE}/fapi/v1/ticker/24hr?${params}`);
|
|
25033
|
-
if (!response.ok) return null;
|
|
25034
|
-
const data = await response.json();
|
|
25035
|
-
return {
|
|
25036
|
-
lastPrice: parseFloat(data.lastPrice),
|
|
25037
|
-
prevClosePrice: parseFloat(data.prevClosePrice),
|
|
25038
|
-
priceChangePercent: parseFloat(data.priceChangePercent)
|
|
25039
|
-
};
|
|
25040
|
-
}
|
|
25041
|
-
|
|
25042
|
-
// src/utils/binance-symbol-map.ts
|
|
25043
|
-
var SYMBOL_OVERRIDES = {
|
|
25044
|
-
// Add overrides here as needed for SYMM markets that don't map 1:1 to Binance
|
|
25045
|
-
// e.g., 'SOME_SYMM_SYMBOL': 'BINANCE_SYMBOL',
|
|
25046
|
-
};
|
|
25047
|
-
var UNSUPPORTED_SYMBOLS = /* @__PURE__ */ new Set([
|
|
25048
|
-
// Add symbols here that have no Binance equivalent
|
|
25049
|
-
]);
|
|
25050
|
-
function resolveBinanceSymbol(symmSymbol) {
|
|
25051
|
-
if (!symmSymbol || !symmSymbol.trim()) {
|
|
25052
|
-
return {
|
|
25053
|
-
symmSymbol,
|
|
25054
|
-
normalizedSymbol: "",
|
|
25055
|
-
binanceSymbol: null,
|
|
25056
|
-
supported: false,
|
|
25057
|
-
reason: "missing_symbol"
|
|
25058
|
-
};
|
|
25059
|
-
}
|
|
25060
|
-
const normalized = symmSymbol.toUpperCase().trim();
|
|
25061
|
-
if (!/^[A-Z0-9]+$/.test(normalized)) {
|
|
25062
|
-
return {
|
|
25063
|
-
symmSymbol,
|
|
25064
|
-
normalizedSymbol: normalized,
|
|
25065
|
-
binanceSymbol: null,
|
|
25066
|
-
supported: false,
|
|
25067
|
-
reason: "invalid_symbol"
|
|
25068
|
-
};
|
|
25069
|
-
}
|
|
25070
|
-
if (UNSUPPORTED_SYMBOLS.has(normalized)) {
|
|
25071
|
-
return {
|
|
25072
|
-
symmSymbol,
|
|
25073
|
-
normalizedSymbol: normalized,
|
|
25074
|
-
binanceSymbol: null,
|
|
25075
|
-
supported: false,
|
|
25076
|
-
reason: "unsupported_symbol"
|
|
25077
|
-
};
|
|
25078
|
-
}
|
|
25079
|
-
const binanceSymbol = SYMBOL_OVERRIDES[normalized] ?? (normalized.endsWith("USDT") ? normalized : `${normalized}USDT`);
|
|
25080
|
-
return {
|
|
25081
|
-
symmSymbol,
|
|
25082
|
-
normalizedSymbol: normalized,
|
|
25083
|
-
binanceSymbol,
|
|
25084
|
-
supported: true,
|
|
25085
|
-
reason: null
|
|
25086
|
-
};
|
|
25087
|
-
}
|
|
25088
|
-
function getUnsupportedBinanceSymbols(symbols) {
|
|
25089
|
-
return symbols.filter((symbol) => !resolveBinanceSymbol(symbol).supported);
|
|
25090
|
-
}
|
|
25091
|
-
function toBinanceSymbol(symmSymbol) {
|
|
25092
|
-
return resolveBinanceSymbol(symmSymbol).binanceSymbol;
|
|
25093
|
-
}
|
|
25094
|
-
|
|
25095
|
-
// src/utils/binance-ws.ts
|
|
25096
|
-
var BINANCE_WS_URL = "wss://fstream.binance.com/ws";
|
|
25097
|
-
var RECONNECT_DELAYS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
|
|
25098
|
-
var BinanceWsManager = class {
|
|
25099
|
-
ws = null;
|
|
25100
|
-
streams = /* @__PURE__ */ new Map();
|
|
25101
|
-
reconnectAttempt = 0;
|
|
25102
|
-
reconnectTimer = null;
|
|
25103
|
-
intentionalClose = false;
|
|
25104
|
-
pendingSubscribes = [];
|
|
25105
|
-
idCounter = 0;
|
|
25106
|
-
/**
|
|
25107
|
-
* Subscribe to a kline stream. Returns an unsubscribe function.
|
|
25108
|
-
*/
|
|
25109
|
-
subscribeKline(symbol, interval, cb) {
|
|
25110
|
-
const streamName = `${symbol.toLowerCase()}@kline_${interval}`;
|
|
25111
|
-
const id = this.generateId();
|
|
25112
|
-
const wrappedCb = (raw) => {
|
|
25113
|
-
const k = raw.k;
|
|
25114
|
-
if (!k) return;
|
|
25115
|
-
cb({
|
|
25116
|
-
symbol: raw.s,
|
|
25117
|
-
interval: k.i,
|
|
25118
|
-
openTime: k.t,
|
|
25119
|
-
closeTime: k.T,
|
|
25120
|
-
open: parseFloat(k.o),
|
|
25121
|
-
high: parseFloat(k.h),
|
|
25122
|
-
low: parseFloat(k.l),
|
|
25123
|
-
close: parseFloat(k.c),
|
|
25124
|
-
volume: parseFloat(k.v),
|
|
25125
|
-
isFinal: k.x
|
|
25126
|
-
});
|
|
25127
|
-
};
|
|
25128
|
-
this.addStreamCallback(streamName, id, wrappedCb);
|
|
25129
|
-
return () => this.removeStreamCallback(streamName, id);
|
|
25130
|
-
}
|
|
25131
|
-
/**
|
|
25132
|
-
* Subscribe to a mark price stream (1s updates). Returns an unsubscribe function.
|
|
25133
|
-
*/
|
|
25134
|
-
subscribeMarkPrice(symbol, cb) {
|
|
25135
|
-
const streamName = `${symbol.toLowerCase()}@markPrice@1s`;
|
|
25136
|
-
const id = this.generateId();
|
|
25137
|
-
const wrappedCb = (raw) => {
|
|
25138
|
-
cb({
|
|
25139
|
-
symbol: raw.s,
|
|
25140
|
-
markPrice: parseFloat(raw.p),
|
|
25141
|
-
indexPrice: parseFloat(raw.i),
|
|
25142
|
-
time: raw.E
|
|
25143
|
-
});
|
|
25144
|
-
};
|
|
25145
|
-
this.addStreamCallback(streamName, id, wrappedCb);
|
|
25146
|
-
return () => this.removeStreamCallback(streamName, id);
|
|
25147
|
-
}
|
|
25148
|
-
/**
|
|
25149
|
-
* Destroy the manager and close the connection.
|
|
25150
|
-
*/
|
|
25151
|
-
destroy() {
|
|
25152
|
-
this.intentionalClose = true;
|
|
25153
|
-
if (this.reconnectTimer) {
|
|
25154
|
-
clearTimeout(this.reconnectTimer);
|
|
25155
|
-
this.reconnectTimer = null;
|
|
25156
|
-
}
|
|
25157
|
-
if (this.ws) {
|
|
25158
|
-
this.ws.close();
|
|
25159
|
-
this.ws = null;
|
|
25160
|
-
}
|
|
25161
|
-
this.streams.clear();
|
|
25162
|
-
}
|
|
25163
|
-
// --- Private ---
|
|
25164
|
-
generateId() {
|
|
25165
|
-
return `sub_${++this.idCounter}_${Date.now()}`;
|
|
25166
|
-
}
|
|
25167
|
-
addStreamCallback(streamName, id, cb) {
|
|
25168
|
-
let sub = this.streams.get(streamName);
|
|
25169
|
-
const isNew = !sub;
|
|
25170
|
-
if (!sub) {
|
|
25171
|
-
sub = { callbacks: /* @__PURE__ */ new Map() };
|
|
25172
|
-
this.streams.set(streamName, sub);
|
|
25173
|
-
}
|
|
25174
|
-
sub.callbacks.set(id, cb);
|
|
25175
|
-
if (isNew) {
|
|
25176
|
-
this.ensureConnected();
|
|
25177
|
-
this.sendSubscribe([streamName]);
|
|
25178
|
-
}
|
|
25179
|
-
}
|
|
25180
|
-
removeStreamCallback(streamName, id) {
|
|
25181
|
-
const sub = this.streams.get(streamName);
|
|
25182
|
-
if (!sub) return;
|
|
25183
|
-
sub.callbacks.delete(id);
|
|
25184
|
-
if (sub.callbacks.size === 0) {
|
|
25185
|
-
this.streams.delete(streamName);
|
|
25186
|
-
this.sendUnsubscribe([streamName]);
|
|
25187
|
-
if (this.streams.size === 0 && this.ws) {
|
|
25188
|
-
this.intentionalClose = true;
|
|
25189
|
-
this.ws.close();
|
|
25190
|
-
this.ws = null;
|
|
25191
|
-
this.intentionalClose = false;
|
|
25159
|
+
});
|
|
25160
|
+
}
|
|
25161
|
+
function useSymmTradeHistory(params) {
|
|
25162
|
+
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
25163
|
+
const { accountAddress, address } = params;
|
|
25164
|
+
const resolvedAddress = accountAddress ? void 0 : address;
|
|
25165
|
+
const chainId = params.chainId ?? ctxChainId;
|
|
25166
|
+
const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress);
|
|
25167
|
+
return useQuery({
|
|
25168
|
+
...params.query,
|
|
25169
|
+
queryKey: symmKeys.tradeHistory({
|
|
25170
|
+
accountAddress,
|
|
25171
|
+
address: resolvedAddress,
|
|
25172
|
+
chainId
|
|
25173
|
+
}),
|
|
25174
|
+
queryFn: () => {
|
|
25175
|
+
const request = {
|
|
25176
|
+
accountAddress,
|
|
25177
|
+
address: resolvedAddress,
|
|
25178
|
+
chainId
|
|
25179
|
+
};
|
|
25180
|
+
return symmCoreClient.positions.getTradeHistory(request);
|
|
25181
|
+
},
|
|
25182
|
+
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
25183
|
+
});
|
|
25184
|
+
}
|
|
25185
|
+
function useSymmSetTpslMutation(options) {
|
|
25186
|
+
const { symmCoreClient } = useSymmContext();
|
|
25187
|
+
const queryClient = useQueryClient();
|
|
25188
|
+
return useMutation({
|
|
25189
|
+
...withSymmMutationConfig(options?.mutation, {
|
|
25190
|
+
onSuccess: () => {
|
|
25191
|
+
invalidateOrders(queryClient);
|
|
25192
|
+
invalidatePositions(queryClient);
|
|
25192
25193
|
}
|
|
25194
|
+
}),
|
|
25195
|
+
mutationFn: async (request) => {
|
|
25196
|
+
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
25197
|
+
return symmCoreClient.orders.setTpsl(request);
|
|
25193
25198
|
}
|
|
25194
|
-
}
|
|
25195
|
-
|
|
25196
|
-
|
|
25197
|
-
|
|
25199
|
+
});
|
|
25200
|
+
}
|
|
25201
|
+
function useSymmCancelTpslMutation(options) {
|
|
25202
|
+
const { symmCoreClient } = useSymmContext();
|
|
25203
|
+
const queryClient = useQueryClient();
|
|
25204
|
+
return useMutation({
|
|
25205
|
+
...withSymmMutationConfig(options?.mutation, {
|
|
25206
|
+
onSuccess: () => {
|
|
25207
|
+
invalidateOrders(queryClient);
|
|
25208
|
+
invalidatePositions(queryClient);
|
|
25209
|
+
}
|
|
25210
|
+
}),
|
|
25211
|
+
mutationFn: async (request) => {
|
|
25212
|
+
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
25213
|
+
return symmCoreClient.orders.cancelTpsl(request);
|
|
25198
25214
|
}
|
|
25199
|
-
|
|
25200
|
-
|
|
25201
|
-
|
|
25202
|
-
|
|
25203
|
-
|
|
25204
|
-
|
|
25205
|
-
|
|
25206
|
-
|
|
25207
|
-
|
|
25208
|
-
|
|
25209
|
-
|
|
25215
|
+
});
|
|
25216
|
+
}
|
|
25217
|
+
function useSymmTpslOrders(params) {
|
|
25218
|
+
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
25219
|
+
const { accountAddress, address, positionId, type, status } = params;
|
|
25220
|
+
const resolvedAddress = accountAddress ? void 0 : address;
|
|
25221
|
+
const chainId = params.chainId ?? ctxChainId;
|
|
25222
|
+
const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress || positionId);
|
|
25223
|
+
const request = {
|
|
25224
|
+
address: accountAddress ?? resolvedAddress,
|
|
25225
|
+
positionId,
|
|
25226
|
+
type,
|
|
25227
|
+
status,
|
|
25228
|
+
chainId
|
|
25229
|
+
};
|
|
25230
|
+
return useQuery({
|
|
25231
|
+
...params.query,
|
|
25232
|
+
queryKey: symmKeys.tpslOrdersList({
|
|
25233
|
+
accountAddress,
|
|
25234
|
+
address: resolvedAddress,
|
|
25235
|
+
positionId,
|
|
25236
|
+
type,
|
|
25237
|
+
status,
|
|
25238
|
+
chainId
|
|
25239
|
+
}),
|
|
25240
|
+
queryFn: () => symmCoreClient.orders.getTpslOrders(request),
|
|
25241
|
+
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
25242
|
+
});
|
|
25243
|
+
}
|
|
25244
|
+
function useResolvedTwapParams(params) {
|
|
25245
|
+
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
25246
|
+
const { accountAddress, address } = params;
|
|
25247
|
+
const resolvedAddress = accountAddress ? void 0 : address;
|
|
25248
|
+
const chainId = params.chainId ?? ctxChainId;
|
|
25249
|
+
return { symmCoreClient, accountAddress, resolvedAddress, chainId, query: params.query };
|
|
25250
|
+
}
|
|
25251
|
+
function useSymmTwapOrdersQuery(params) {
|
|
25252
|
+
const { symmCoreClient, accountAddress, resolvedAddress, chainId, query } = useResolvedTwapParams(params);
|
|
25253
|
+
const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress);
|
|
25254
|
+
return useQuery({
|
|
25255
|
+
...query,
|
|
25256
|
+
queryKey: symmKeys.twapOrders(accountAddress ?? resolvedAddress, chainId),
|
|
25257
|
+
queryFn: () => symmCoreClient.orders.getTwapOrders({
|
|
25258
|
+
address: accountAddress ?? resolvedAddress,
|
|
25259
|
+
chainId
|
|
25260
|
+
}),
|
|
25261
|
+
enabled: internalEnabled && (query?.enabled ?? true)
|
|
25262
|
+
});
|
|
25263
|
+
}
|
|
25264
|
+
function useSymmCancelTwapOrderMutation(options) {
|
|
25265
|
+
const { symmCoreClient } = useSymmContext();
|
|
25266
|
+
const queryClient = useQueryClient();
|
|
25267
|
+
return useMutation({
|
|
25268
|
+
...withSymmMutationConfig(options?.mutation, {
|
|
25269
|
+
onSuccess: () => {
|
|
25270
|
+
invalidateOrders(queryClient);
|
|
25210
25271
|
}
|
|
25211
|
-
|
|
25212
|
-
|
|
25213
|
-
|
|
25272
|
+
}),
|
|
25273
|
+
mutationFn: async (orderId) => {
|
|
25274
|
+
if (!symmCoreClient) throw new Error("symm-core client not available");
|
|
25275
|
+
return symmCoreClient.orders.cancelTwapOrder(orderId);
|
|
25276
|
+
}
|
|
25277
|
+
});
|
|
25278
|
+
}
|
|
25279
|
+
function useSymmTriggerConfigQuery(params) {
|
|
25280
|
+
const { symmCoreClient } = useSymmContext();
|
|
25281
|
+
const { orderId } = params;
|
|
25282
|
+
const internalEnabled = !!symmCoreClient && !!orderId;
|
|
25283
|
+
return useQuery({
|
|
25284
|
+
...params.query,
|
|
25285
|
+
queryKey: symmKeys.triggerConfig(orderId),
|
|
25286
|
+
queryFn: () => symmCoreClient.orders.getTriggerConfig(orderId),
|
|
25287
|
+
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
25288
|
+
});
|
|
25289
|
+
}
|
|
25290
|
+
function useSymmSetTriggerConfigMutation(params, options) {
|
|
25291
|
+
const { symmCoreClient } = useSymmContext();
|
|
25292
|
+
const { orderId } = params;
|
|
25293
|
+
const queryClient = useQueryClient();
|
|
25294
|
+
return useMutation({
|
|
25295
|
+
...withSymmMutationConfig(options?.mutation, {
|
|
25296
|
+
onSuccess: () => {
|
|
25297
|
+
queryClient.invalidateQueries({
|
|
25298
|
+
queryKey: symmKeys.triggerConfig(orderId)
|
|
25299
|
+
});
|
|
25300
|
+
invalidateOrders(queryClient);
|
|
25214
25301
|
}
|
|
25215
|
-
}
|
|
25216
|
-
|
|
25217
|
-
|
|
25218
|
-
|
|
25219
|
-
this.handleMessage(data);
|
|
25220
|
-
} catch {
|
|
25302
|
+
}),
|
|
25303
|
+
mutationFn: async (request) => {
|
|
25304
|
+
if (!symmCoreClient || !orderId) {
|
|
25305
|
+
throw new Error("symm-core client or orderId not available");
|
|
25221
25306
|
}
|
|
25222
|
-
|
|
25223
|
-
this.ws.onclose = () => {
|
|
25224
|
-
if (this.intentionalClose) return;
|
|
25225
|
-
this.scheduleReconnect();
|
|
25226
|
-
};
|
|
25227
|
-
this.ws.onerror = () => {
|
|
25228
|
-
};
|
|
25229
|
-
}
|
|
25230
|
-
handleMessage(data) {
|
|
25231
|
-
if (data.e === "kline") {
|
|
25232
|
-
const k = data.k;
|
|
25233
|
-
const streamName = `${data.s.toLowerCase()}@kline_${k.i}`;
|
|
25234
|
-
this.dispatchToStream(streamName, data);
|
|
25235
|
-
} else if (data.e === "markPriceUpdate") {
|
|
25236
|
-
const streamName = `${data.s.toLowerCase()}@markPrice@1s`;
|
|
25237
|
-
this.dispatchToStream(streamName, data);
|
|
25307
|
+
return symmCoreClient.orders.setTriggerConfig(orderId, request);
|
|
25238
25308
|
}
|
|
25239
|
-
}
|
|
25240
|
-
|
|
25241
|
-
|
|
25242
|
-
|
|
25243
|
-
|
|
25244
|
-
|
|
25245
|
-
|
|
25246
|
-
|
|
25309
|
+
});
|
|
25310
|
+
}
|
|
25311
|
+
function useSymmClearTriggerConfigMutation(params, options) {
|
|
25312
|
+
const { symmCoreClient } = useSymmContext();
|
|
25313
|
+
const { orderId } = params;
|
|
25314
|
+
const queryClient = useQueryClient();
|
|
25315
|
+
return useMutation({
|
|
25316
|
+
...withSymmMutationConfig(options?.mutation, {
|
|
25317
|
+
onSuccess: () => {
|
|
25318
|
+
queryClient.invalidateQueries({
|
|
25319
|
+
queryKey: symmKeys.triggerConfig(orderId)
|
|
25320
|
+
});
|
|
25321
|
+
invalidateOrders(queryClient);
|
|
25247
25322
|
}
|
|
25248
|
-
})
|
|
25249
|
-
|
|
25250
|
-
|
|
25251
|
-
|
|
25252
|
-
|
|
25253
|
-
return;
|
|
25254
|
-
}
|
|
25255
|
-
this.ws.send(JSON.stringify({
|
|
25256
|
-
method: "SUBSCRIBE",
|
|
25257
|
-
params: streams,
|
|
25258
|
-
id: Date.now()
|
|
25259
|
-
}));
|
|
25260
|
-
}
|
|
25261
|
-
sendUnsubscribe(streams) {
|
|
25262
|
-
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
25263
|
-
this.pendingSubscribes = this.pendingSubscribes.filter(
|
|
25264
|
-
(s) => !streams.includes(s)
|
|
25265
|
-
);
|
|
25266
|
-
return;
|
|
25323
|
+
}),
|
|
25324
|
+
mutationFn: async () => {
|
|
25325
|
+
if (!symmCoreClient || !orderId) {
|
|
25326
|
+
throw new Error("symm-core client or orderId not available");
|
|
25327
|
+
}
|
|
25328
|
+
return symmCoreClient.orders.clearTriggerConfig(orderId);
|
|
25267
25329
|
}
|
|
25268
|
-
|
|
25269
|
-
|
|
25270
|
-
|
|
25271
|
-
|
|
25272
|
-
|
|
25273
|
-
|
|
25274
|
-
|
|
25275
|
-
|
|
25276
|
-
|
|
25277
|
-
|
|
25278
|
-
|
|
25279
|
-
|
|
25280
|
-
|
|
25281
|
-
|
|
25282
|
-
|
|
25283
|
-
|
|
25284
|
-
|
|
25285
|
-
|
|
25286
|
-
|
|
25287
|
-
|
|
25288
|
-
|
|
25289
|
-
|
|
25290
|
-
|
|
25330
|
+
});
|
|
25331
|
+
}
|
|
25332
|
+
function useSymmTriggerOrders(params) {
|
|
25333
|
+
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
25334
|
+
const { accountAddress, address, status, limit, offset } = params;
|
|
25335
|
+
const resolvedAddress = accountAddress ? void 0 : address;
|
|
25336
|
+
const chainId = params.chainId ?? ctxChainId;
|
|
25337
|
+
const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress);
|
|
25338
|
+
const request = {
|
|
25339
|
+
address: accountAddress ?? resolvedAddress,
|
|
25340
|
+
chainId,
|
|
25341
|
+
status,
|
|
25342
|
+
limit,
|
|
25343
|
+
offset
|
|
25344
|
+
};
|
|
25345
|
+
return useQuery({
|
|
25346
|
+
...params.query,
|
|
25347
|
+
queryKey: symmKeys.triggerOrders({
|
|
25348
|
+
accountAddress,
|
|
25349
|
+
address: resolvedAddress,
|
|
25350
|
+
chainId,
|
|
25351
|
+
status,
|
|
25352
|
+
limit,
|
|
25353
|
+
offset
|
|
25354
|
+
}),
|
|
25355
|
+
queryFn: () => symmCoreClient.orders.listTriggerOrders(request),
|
|
25356
|
+
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
25357
|
+
});
|
|
25291
25358
|
}
|
|
25292
|
-
|
|
25293
|
-
|
|
25294
|
-
|
|
25295
|
-
|
|
25296
|
-
|
|
25297
|
-
|
|
25298
|
-
|
|
25359
|
+
function useSymmMarkets(params) {
|
|
25360
|
+
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
25361
|
+
const chainId = params?.chainId ?? ctxChainId;
|
|
25362
|
+
const searchText = params?.searchText;
|
|
25363
|
+
const internalEnabled = !!symmCoreClient;
|
|
25364
|
+
return useQuery({
|
|
25365
|
+
...params?.query,
|
|
25366
|
+
queryKey: symmKeys.markets(chainId, searchText),
|
|
25367
|
+
queryFn: () => {
|
|
25368
|
+
if (searchText) {
|
|
25369
|
+
return symmCoreClient.markets.search(searchText, { chainId });
|
|
25370
|
+
}
|
|
25371
|
+
return symmCoreClient.markets.list({ pageSize: "1000", chainId });
|
|
25372
|
+
},
|
|
25373
|
+
enabled: internalEnabled && (params?.query?.enabled ?? true)
|
|
25374
|
+
});
|
|
25299
25375
|
}
|
|
25300
|
-
function
|
|
25301
|
-
|
|
25376
|
+
function useSymmHedgerMarketById(params) {
|
|
25377
|
+
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
25378
|
+
const { id } = params;
|
|
25379
|
+
const chainId = params.chainId ?? ctxChainId;
|
|
25380
|
+
const internalEnabled = !!symmCoreClient && id != null;
|
|
25381
|
+
return useQuery({
|
|
25382
|
+
...params.query,
|
|
25383
|
+
queryKey: symmKeys.hedgerMarketById(id, chainId),
|
|
25384
|
+
queryFn: () => symmCoreClient.markets.getById(id, chainId),
|
|
25385
|
+
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
25386
|
+
});
|
|
25302
25387
|
}
|
|
25303
|
-
function
|
|
25304
|
-
|
|
25388
|
+
function useSymmHedgerMarketBySymbol(params) {
|
|
25389
|
+
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
25390
|
+
const { symbol } = params;
|
|
25391
|
+
const chainId = params.chainId ?? ctxChainId;
|
|
25392
|
+
const internalEnabled = !!symmCoreClient && !!symbol;
|
|
25393
|
+
return useQuery({
|
|
25394
|
+
...params.query,
|
|
25395
|
+
queryKey: symmKeys.hedgerMarketBySymbol(symbol, chainId),
|
|
25396
|
+
queryFn: () => symmCoreClient.markets.getBySymbol(symbol, chainId),
|
|
25397
|
+
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
25398
|
+
});
|
|
25399
|
+
}
|
|
25400
|
+
function useSymmLockedParams(params) {
|
|
25401
|
+
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
25402
|
+
const { marketName, leverage } = params;
|
|
25403
|
+
const chainId = params.chainId ?? ctxChainId;
|
|
25404
|
+
const internalEnabled = !!symmCoreClient && !!marketName && leverage != null;
|
|
25405
|
+
return useQuery({
|
|
25406
|
+
...params.query,
|
|
25407
|
+
queryKey: symmKeys.lockedParams(marketName, leverage, chainId),
|
|
25408
|
+
queryFn: () => symmCoreClient.markets.getLockedParams({
|
|
25409
|
+
marketName,
|
|
25410
|
+
leverage,
|
|
25411
|
+
chainId
|
|
25412
|
+
}),
|
|
25413
|
+
enabled: internalEnabled && (params.query?.enabled ?? true)
|
|
25414
|
+
});
|
|
25415
|
+
}
|
|
25416
|
+
function useSymmHedgerMarkets(params) {
|
|
25417
|
+
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
25418
|
+
const chainId = params?.chainId ?? ctxChainId;
|
|
25419
|
+
const searchText = params?.searchText?.trim();
|
|
25420
|
+
const consumerEnabled = params?.query?.enabled ?? params?.enabled ?? true;
|
|
25421
|
+
const { enabled: _, query: __, ...restParams } = params ?? {};
|
|
25422
|
+
const request = {
|
|
25423
|
+
...restParams,
|
|
25424
|
+
chainId,
|
|
25425
|
+
searchText: searchText || void 0
|
|
25426
|
+
};
|
|
25427
|
+
const internalEnabled = !!symmCoreClient;
|
|
25428
|
+
return useQuery({
|
|
25429
|
+
...params?.query,
|
|
25430
|
+
queryKey: symmKeys.hedgerMarkets(request),
|
|
25431
|
+
queryFn: () => symmCoreClient.markets.listSymmHedger(request),
|
|
25432
|
+
enabled: internalEnabled && consumerEnabled
|
|
25433
|
+
});
|
|
25305
25434
|
}
|
|
25306
|
-
var useBinanceMarkPriceStore = create((set) => ({
|
|
25307
|
-
markPrices: {},
|
|
25308
|
-
subscribeSymbol: (symmSymbol, rawBinanceSymbol) => {
|
|
25309
|
-
const binanceSymbol = normalizeBinanceSymbol(rawBinanceSymbol);
|
|
25310
|
-
const nextRefCount = getNextRefCount(binanceSymbol);
|
|
25311
|
-
refCounts.set(binanceSymbol, nextRefCount);
|
|
25312
|
-
const symbols = streamSymbols.get(binanceSymbol) ?? /* @__PURE__ */ new Set();
|
|
25313
|
-
symbols.add(symmSymbol);
|
|
25314
|
-
streamSymbols.set(binanceSymbol, symbols);
|
|
25315
|
-
if (nextRefCount === 1) {
|
|
25316
|
-
const wsManager = getBinanceWsManager();
|
|
25317
|
-
const unsubscribe = wsManager.subscribeMarkPrice(binanceSymbol, (data) => {
|
|
25318
|
-
const canonicalSymbol = normalizeBinanceSymbol(data.symbol);
|
|
25319
|
-
const mappedSymbols = streamSymbols.get(canonicalSymbol);
|
|
25320
|
-
if (!mappedSymbols || mappedSymbols.size === 0) return;
|
|
25321
|
-
set((state) => {
|
|
25322
|
-
const nextMarkPrices = { ...state.markPrices };
|
|
25323
|
-
mappedSymbols.forEach((mappedSymbol) => {
|
|
25324
|
-
nextMarkPrices[mappedSymbol] = data.markPrice;
|
|
25325
|
-
});
|
|
25326
|
-
return { markPrices: nextMarkPrices };
|
|
25327
|
-
});
|
|
25328
|
-
});
|
|
25329
|
-
streamUnsubs.set(binanceSymbol, unsubscribe);
|
|
25330
|
-
}
|
|
25331
|
-
},
|
|
25332
|
-
unsubscribeSymbol: (symmSymbol, rawBinanceSymbol) => {
|
|
25333
|
-
const binanceSymbol = normalizeBinanceSymbol(rawBinanceSymbol);
|
|
25334
|
-
const symbols = streamSymbols.get(binanceSymbol);
|
|
25335
|
-
if (symbols) {
|
|
25336
|
-
symbols.delete(symmSymbol);
|
|
25337
|
-
if (symbols.size === 0) {
|
|
25338
|
-
streamSymbols.delete(binanceSymbol);
|
|
25339
|
-
} else {
|
|
25340
|
-
streamSymbols.set(binanceSymbol, symbols);
|
|
25341
|
-
}
|
|
25342
|
-
}
|
|
25343
|
-
const nextRefCount = getPrevRefCount(binanceSymbol);
|
|
25344
|
-
if (nextRefCount === 0) {
|
|
25345
|
-
const unsubscribe = streamUnsubs.get(binanceSymbol);
|
|
25346
|
-
if (unsubscribe) unsubscribe();
|
|
25347
|
-
streamUnsubs.delete(binanceSymbol);
|
|
25348
|
-
refCounts.delete(binanceSymbol);
|
|
25349
|
-
} else {
|
|
25350
|
-
refCounts.set(binanceSymbol, nextRefCount);
|
|
25351
|
-
}
|
|
25352
|
-
set((state) => {
|
|
25353
|
-
if (state.markPrices[symmSymbol] == null) return state;
|
|
25354
|
-
const nextMarkPrices = { ...state.markPrices };
|
|
25355
|
-
delete nextMarkPrices[symmSymbol];
|
|
25356
|
-
return { markPrices: nextMarkPrices };
|
|
25357
|
-
});
|
|
25358
|
-
}
|
|
25359
|
-
}));
|
|
25360
25435
|
|
|
25361
|
-
// src/
|
|
25362
|
-
|
|
25363
|
-
|
|
25364
|
-
|
|
25365
|
-
|
|
25366
|
-
|
|
25436
|
+
// src/utils/binance-api.ts
|
|
25437
|
+
var BINANCE_FAPI_BASE = "https://fapi.binance.com";
|
|
25438
|
+
async function fetchMarkPriceKlines(symbol, interval, startTime, endTime, limit = 1500) {
|
|
25439
|
+
const params = new URLSearchParams({
|
|
25440
|
+
symbol,
|
|
25441
|
+
interval,
|
|
25442
|
+
startTime: String(startTime),
|
|
25443
|
+
endTime: String(endTime),
|
|
25444
|
+
limit: String(Math.min(limit, 1500))
|
|
25445
|
+
});
|
|
25446
|
+
const response = await fetch(`${BINANCE_FAPI_BASE}/fapi/v1/markPriceKlines?${params}`);
|
|
25447
|
+
if (!response.ok) {
|
|
25448
|
+
throw new Error(`Binance markPriceKlines failed: ${response.status}`);
|
|
25449
|
+
}
|
|
25450
|
+
const data = await response.json();
|
|
25451
|
+
return data.map((k) => ({
|
|
25452
|
+
openTime: Number(k[0]),
|
|
25453
|
+
open: parseFloat(k[1]),
|
|
25454
|
+
high: parseFloat(k[2]),
|
|
25455
|
+
low: parseFloat(k[3]),
|
|
25456
|
+
close: parseFloat(k[4]),
|
|
25457
|
+
volume: parseFloat(k[5]),
|
|
25458
|
+
closeTime: Number(k[6])
|
|
25459
|
+
}));
|
|
25460
|
+
}
|
|
25461
|
+
async function fetch24hrTicker(symbol) {
|
|
25462
|
+
const params = new URLSearchParams({ symbol });
|
|
25463
|
+
const response = await fetch(`${BINANCE_FAPI_BASE}/fapi/v1/ticker/24hr?${params}`);
|
|
25464
|
+
if (!response.ok) return null;
|
|
25465
|
+
const data = await response.json();
|
|
25367
25466
|
return {
|
|
25368
|
-
|
|
25467
|
+
lastPrice: parseFloat(data.lastPrice),
|
|
25468
|
+
prevClosePrice: parseFloat(data.prevClosePrice),
|
|
25469
|
+
priceChangePercent: parseFloat(data.priceChangePercent)
|
|
25369
25470
|
};
|
|
25370
25471
|
}
|
|
25472
|
+
async function fetch24hrTickers() {
|
|
25473
|
+
const response = await fetch(`${BINANCE_FAPI_BASE}/fapi/v1/ticker/24hr`);
|
|
25474
|
+
if (!response.ok) {
|
|
25475
|
+
throw new Error(`Binance 24hr tickers failed: ${response.status}`);
|
|
25476
|
+
}
|
|
25477
|
+
const data = await response.json();
|
|
25478
|
+
const result = {};
|
|
25479
|
+
for (const item of data) {
|
|
25480
|
+
result[item.symbol] = {
|
|
25481
|
+
lastPrice: parseFloat(item.lastPrice),
|
|
25482
|
+
prevClosePrice: parseFloat(item.prevClosePrice),
|
|
25483
|
+
priceChangePercent: parseFloat(item.priceChangePercent)
|
|
25484
|
+
};
|
|
25485
|
+
}
|
|
25486
|
+
return result;
|
|
25487
|
+
}
|
|
25488
|
+
|
|
25489
|
+
// src/react/hooks/use-symm-token-selection-markets.ts
|
|
25371
25490
|
function useSymmTokenSelectionMarkets(params) {
|
|
25372
25491
|
const query = useSymmHedgerMarkets(params);
|
|
25373
25492
|
const baseMarkets = query.data?.filteredMarkets ?? query.data?.markets ?? [];
|
|
@@ -25383,48 +25502,27 @@ function useSymmTokenSelectionMarkets(params) {
|
|
|
25383
25502
|
() => [...marketSymbols].sort().join(","),
|
|
25384
25503
|
[marketSymbols]
|
|
25385
25504
|
);
|
|
25386
|
-
const symbolToBinanceMap = useMemo(
|
|
25387
|
-
() => new Map(
|
|
25388
|
-
marketSymbols.map((symbol) => {
|
|
25389
|
-
const binanceSymbol = resolveBinanceSymbol(symbol).binanceSymbol;
|
|
25390
|
-
if (!binanceSymbol) return null;
|
|
25391
|
-
return [symbol, binanceSymbol];
|
|
25392
|
-
}).filter((entry) => !!entry)
|
|
25393
|
-
),
|
|
25394
|
-
[marketSymbols]
|
|
25395
|
-
);
|
|
25396
25505
|
const liveMarkPrices = useBinanceMarkPriceStore((state) => state.markPrices);
|
|
25397
|
-
const subscribeSymbol = useBinanceMarkPriceStore((state) => state.subscribeSymbol);
|
|
25398
|
-
const unsubscribeSymbol = useBinanceMarkPriceStore((state) => state.unsubscribeSymbol);
|
|
25399
25506
|
const priceQuery = useQuery({
|
|
25400
25507
|
queryKey: ["symm", "token-selection-markets-price", symbolsKey],
|
|
25401
25508
|
queryFn: async () => {
|
|
25509
|
+
const allTickers = await fetch24hrTickers();
|
|
25402
25510
|
const tickerSnapshots = {};
|
|
25403
|
-
|
|
25404
|
-
|
|
25405
|
-
|
|
25406
|
-
|
|
25407
|
-
|
|
25511
|
+
marketSymbols.forEach((symbol) => {
|
|
25512
|
+
const binanceSymbol = resolveBinanceSymbol(symbol).binanceSymbol;
|
|
25513
|
+
if (!binanceSymbol) {
|
|
25514
|
+
tickerSnapshots[symbol] = null;
|
|
25515
|
+
return;
|
|
25516
|
+
}
|
|
25517
|
+
const ticker = allTickers[binanceSymbol];
|
|
25518
|
+
tickerSnapshots[symbol] = ticker ? { prevClosePrice: ticker.prevClosePrice } : null;
|
|
25519
|
+
});
|
|
25408
25520
|
return { tickerSnapshots };
|
|
25409
25521
|
},
|
|
25410
25522
|
enabled: query.isSuccess && marketSymbols.length > 0,
|
|
25411
25523
|
staleTime: 6e4,
|
|
25412
25524
|
gcTime: 5 * 6e4
|
|
25413
25525
|
});
|
|
25414
|
-
useEffect(() => {
|
|
25415
|
-
if (!query.isSuccess || symbolToBinanceMap.size === 0) {
|
|
25416
|
-
return;
|
|
25417
|
-
}
|
|
25418
|
-
const symbolEntries = Array.from(symbolToBinanceMap.entries());
|
|
25419
|
-
symbolEntries.forEach(
|
|
25420
|
-
([symbol, binanceSymbol]) => subscribeSymbol(symbol, binanceSymbol)
|
|
25421
|
-
);
|
|
25422
|
-
return () => {
|
|
25423
|
-
symbolEntries.forEach(
|
|
25424
|
-
([symbol, binanceSymbol]) => unsubscribeSymbol(symbol, binanceSymbol)
|
|
25425
|
-
);
|
|
25426
|
-
};
|
|
25427
|
-
}, [query.isSuccess, symbolsKey, symbolToBinanceMap, subscribeSymbol, unsubscribeSymbol]);
|
|
25428
25526
|
const markets = useMemo(() => {
|
|
25429
25527
|
const snapshots = priceQuery.data?.tickerSnapshots ?? {};
|
|
25430
25528
|
return baseMarkets.map((market) => {
|
|
@@ -25453,6 +25551,61 @@ function useSymmTokenSelectionMarkets(params) {
|
|
|
25453
25551
|
() => new Map(markets.map((market) => [market.id, market])),
|
|
25454
25552
|
[markets]
|
|
25455
25553
|
);
|
|
25554
|
+
useEffect(() => {
|
|
25555
|
+
console.debug("[useSymmTokenSelectionMarkets] data flow", {
|
|
25556
|
+
params,
|
|
25557
|
+
query: {
|
|
25558
|
+
status: query.status,
|
|
25559
|
+
fetchStatus: query.fetchStatus,
|
|
25560
|
+
isLoading: query.isLoading,
|
|
25561
|
+
isSuccess: query.isSuccess,
|
|
25562
|
+
isError: query.isError,
|
|
25563
|
+
error: query.error
|
|
25564
|
+
},
|
|
25565
|
+
priceQuery: {
|
|
25566
|
+
status: priceQuery.status,
|
|
25567
|
+
fetchStatus: priceQuery.fetchStatus,
|
|
25568
|
+
isLoading: priceQuery.isLoading,
|
|
25569
|
+
isSuccess: priceQuery.isSuccess,
|
|
25570
|
+
isError: priceQuery.isError,
|
|
25571
|
+
error: priceQuery.error
|
|
25572
|
+
},
|
|
25573
|
+
marketSymbols,
|
|
25574
|
+
symbolsKey,
|
|
25575
|
+
liveMarkPrices,
|
|
25576
|
+
tickerSnapshots: priceQuery.data?.tickerSnapshots ?? {},
|
|
25577
|
+
result: {
|
|
25578
|
+
marketCount: markets.length,
|
|
25579
|
+
markets: markets.map((market) => ({
|
|
25580
|
+
id: market.id,
|
|
25581
|
+
symbol: market.symbol,
|
|
25582
|
+
markPrice: market.markPrice,
|
|
25583
|
+
prevDayPrice: market.prevDayPrice,
|
|
25584
|
+
priceChange24h: market.priceChange24h,
|
|
25585
|
+
priceChange24hPercent: market.priceChange24hPercent
|
|
25586
|
+
}))
|
|
25587
|
+
}
|
|
25588
|
+
});
|
|
25589
|
+
}, [
|
|
25590
|
+
liveMarkPrices,
|
|
25591
|
+
marketSymbols,
|
|
25592
|
+
markets,
|
|
25593
|
+
params,
|
|
25594
|
+
priceQuery.data,
|
|
25595
|
+
priceQuery.error,
|
|
25596
|
+
priceQuery.fetchStatus,
|
|
25597
|
+
priceQuery.isError,
|
|
25598
|
+
priceQuery.isLoading,
|
|
25599
|
+
priceQuery.isSuccess,
|
|
25600
|
+
priceQuery.status,
|
|
25601
|
+
query.error,
|
|
25602
|
+
query.fetchStatus,
|
|
25603
|
+
query.isError,
|
|
25604
|
+
query.isLoading,
|
|
25605
|
+
query.isSuccess,
|
|
25606
|
+
query.status,
|
|
25607
|
+
symbolsKey
|
|
25608
|
+
]);
|
|
25456
25609
|
return {
|
|
25457
25610
|
query,
|
|
25458
25611
|
priceQuery,
|
|
@@ -25463,6 +25616,22 @@ function useSymmTokenSelectionMarkets(params) {
|
|
|
25463
25616
|
isPriceLoading: priceQuery.isLoading
|
|
25464
25617
|
};
|
|
25465
25618
|
}
|
|
25619
|
+
function useSymmTokenMarkPrice(symbol) {
|
|
25620
|
+
const normalizedSymbol = symbol?.trim().toUpperCase() || null;
|
|
25621
|
+
const resolution = resolveBinanceSymbol(normalizedSymbol ?? "");
|
|
25622
|
+
const liveMarkPrices = useBinanceMarkPriceStore((state) => state.markPrices);
|
|
25623
|
+
const markPrice = useMemo(() => {
|
|
25624
|
+
if (!normalizedSymbol) return null;
|
|
25625
|
+
return liveMarkPrices[normalizedSymbol] ?? null;
|
|
25626
|
+
}, [liveMarkPrices, normalizedSymbol]);
|
|
25627
|
+
return {
|
|
25628
|
+
symbol: normalizedSymbol,
|
|
25629
|
+
binanceSymbol: resolution.binanceSymbol,
|
|
25630
|
+
markPrice,
|
|
25631
|
+
isSupported: resolution.supported,
|
|
25632
|
+
reason: resolution.reason
|
|
25633
|
+
};
|
|
25634
|
+
}
|
|
25466
25635
|
function useSymmFunding(params) {
|
|
25467
25636
|
const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
|
|
25468
25637
|
const chainId = params?.chainId ?? ctxChainId;
|
|
@@ -25971,7 +26140,7 @@ function computeNetFundingSum({
|
|
|
25971
26140
|
}
|
|
25972
26141
|
|
|
25973
26142
|
// src/react/hooks/use-symm-token-selection-metadata.ts
|
|
25974
|
-
async function
|
|
26143
|
+
async function fetchTickerSnapshot(symbol) {
|
|
25975
26144
|
const resolution = resolveBinanceSymbol(symbol);
|
|
25976
26145
|
if (!resolution.binanceSymbol) return null;
|
|
25977
26146
|
const ticker = await fetch24hrTicker(resolution.binanceSymbol);
|
|
@@ -26003,17 +26172,7 @@ function useSymmTokenSelectionMetadata(selection, options = {}) {
|
|
|
26003
26172
|
const isUnsupported = unsupportedSymbols.length > 0;
|
|
26004
26173
|
const unavailableReason = isUnsupported ? `Binance market data is unavailable for ${unsupportedSymbols.join(", ")}.` : null;
|
|
26005
26174
|
const symbolsKey = [...selectedSymbols].sort().join(",");
|
|
26006
|
-
const symbolToBinanceMap = useMemo(
|
|
26007
|
-
() => new Map(
|
|
26008
|
-
selectedSymbols.map(
|
|
26009
|
-
(symbol) => [symbol, resolveBinanceSymbol(symbol).binanceSymbol]
|
|
26010
|
-
).filter((entry) => !!entry[1])
|
|
26011
|
-
),
|
|
26012
|
-
[selectedSymbols]
|
|
26013
|
-
);
|
|
26014
26175
|
const liveMarkPrices = useBinanceMarkPriceStore((state) => state.markPrices);
|
|
26015
|
-
const subscribeSymbol = useBinanceMarkPriceStore((state) => state.subscribeSymbol);
|
|
26016
|
-
const unsubscribeSymbol = useBinanceMarkPriceStore((state) => state.unsubscribeSymbol);
|
|
26017
26176
|
const query = useQuery({
|
|
26018
26177
|
queryKey: ["symm", "chart-metadata", symbolsKey],
|
|
26019
26178
|
queryFn: async () => {
|
|
@@ -26027,7 +26186,7 @@ function useSymmTokenSelectionMetadata(selection, options = {}) {
|
|
|
26027
26186
|
const results = await Promise.all(
|
|
26028
26187
|
allSymbols.map(async ({ symbol }) => ({
|
|
26029
26188
|
symbol,
|
|
26030
|
-
ticker: await
|
|
26189
|
+
ticker: await fetchTickerSnapshot(symbol)
|
|
26031
26190
|
}))
|
|
26032
26191
|
);
|
|
26033
26192
|
const tickerSnapshots = {};
|
|
@@ -26039,28 +26198,7 @@ function useSymmTokenSelectionMetadata(selection, options = {}) {
|
|
|
26039
26198
|
enabled: enabled && selectedSymbols.length > 0 && !isUnsupported,
|
|
26040
26199
|
gcTime: 5 * 6e4
|
|
26041
26200
|
});
|
|
26042
|
-
|
|
26043
|
-
if (!enabled || isUnsupported || selectedSymbols.length === 0) {
|
|
26044
|
-
return;
|
|
26045
|
-
}
|
|
26046
|
-
const symbolEntries = Array.from(symbolToBinanceMap.entries());
|
|
26047
|
-
symbolEntries.forEach(
|
|
26048
|
-
([symbol, binanceSymbol]) => subscribeSymbol(symbol, binanceSymbol)
|
|
26049
|
-
);
|
|
26050
|
-
return () => {
|
|
26051
|
-
symbolEntries.forEach(
|
|
26052
|
-
([symbol, binanceSymbol]) => unsubscribeSymbol(symbol, binanceSymbol)
|
|
26053
|
-
);
|
|
26054
|
-
};
|
|
26055
|
-
}, [
|
|
26056
|
-
enabled,
|
|
26057
|
-
isUnsupported,
|
|
26058
|
-
selectedSymbols.length,
|
|
26059
|
-
symbolToBinanceMap,
|
|
26060
|
-
subscribeSymbol,
|
|
26061
|
-
unsubscribeSymbol
|
|
26062
|
-
]);
|
|
26063
|
-
return useMemo(() => {
|
|
26201
|
+
const result = useMemo(() => {
|
|
26064
26202
|
const tickerSnapshots = query.data?.tickerSnapshots ?? {};
|
|
26065
26203
|
const longMeta = {};
|
|
26066
26204
|
const shortMeta = {};
|
|
@@ -26119,6 +26257,53 @@ function useSymmTokenSelectionMetadata(selection, options = {}) {
|
|
|
26119
26257
|
selectedSymbols.length,
|
|
26120
26258
|
liveMarkPrices
|
|
26121
26259
|
]);
|
|
26260
|
+
useEffect(() => {
|
|
26261
|
+
console.debug("[useSymmTokenSelectionMetadata] data flow", {
|
|
26262
|
+
selection,
|
|
26263
|
+
options,
|
|
26264
|
+
query: {
|
|
26265
|
+
status: query.status,
|
|
26266
|
+
fetchStatus: query.fetchStatus,
|
|
26267
|
+
isLoading: query.isLoading,
|
|
26268
|
+
isSuccess: query.isSuccess,
|
|
26269
|
+
isError: query.isError,
|
|
26270
|
+
error: query.error
|
|
26271
|
+
},
|
|
26272
|
+
selectedSymbols,
|
|
26273
|
+
unsupportedSymbols,
|
|
26274
|
+
unavailableReason,
|
|
26275
|
+
liveMarkPrices,
|
|
26276
|
+
tickerSnapshots: query.data?.tickerSnapshots ?? {},
|
|
26277
|
+
result: {
|
|
26278
|
+
isLoading: result.isLoading,
|
|
26279
|
+
isPriceDataReady: result.isPriceDataReady,
|
|
26280
|
+
isUnsupported: result.isUnsupported,
|
|
26281
|
+
longTokensMetadata: result.longTokensMetadata,
|
|
26282
|
+
shortTokensMetadata: result.shortTokensMetadata,
|
|
26283
|
+
weightedRatio: result.weightedRatio,
|
|
26284
|
+
weightedRatio24h: result.weightedRatio24h,
|
|
26285
|
+
priceRatio: result.priceRatio,
|
|
26286
|
+
priceRatio24h: result.priceRatio24h,
|
|
26287
|
+
sumNetFunding: result.sumNetFunding
|
|
26288
|
+
}
|
|
26289
|
+
});
|
|
26290
|
+
}, [
|
|
26291
|
+
liveMarkPrices,
|
|
26292
|
+
options,
|
|
26293
|
+
query.data,
|
|
26294
|
+
query.error,
|
|
26295
|
+
query.fetchStatus,
|
|
26296
|
+
query.isError,
|
|
26297
|
+
query.isLoading,
|
|
26298
|
+
query.isSuccess,
|
|
26299
|
+
query.status,
|
|
26300
|
+
result,
|
|
26301
|
+
selectedSymbols,
|
|
26302
|
+
selection,
|
|
26303
|
+
unavailableReason,
|
|
26304
|
+
unsupportedSymbols
|
|
26305
|
+
]);
|
|
26306
|
+
return result;
|
|
26122
26307
|
}
|
|
26123
26308
|
|
|
26124
26309
|
// src/utils/binance-intervals.ts
|
|
@@ -26500,6 +26685,6 @@ function getSymmErrorMessage(error) {
|
|
|
26500
26685
|
return "An unexpected error occurred.";
|
|
26501
26686
|
}
|
|
26502
26687
|
|
|
26503
|
-
export { SymmProvider, getSymmErrorMessage, symmKeys, useBinanceMarkPriceStore, useSymmAccountData, useSymmAccountSummary, useSymmAccountsApi, useSymmAccountsLength, useSymmAccountsQuery, useSymmAccountsWithPositions, useSymmAllocateCollateralMutation, useSymmApprovalQuery, useSymmApproveMutation, useSymmAuth, useSymmAuthStore, useSymmAvailableMargin, useSymmBalances, useSymmCancelClose, useSymmCancelOpenMutation, useSymmCancelTpslMutation, useSymmCancelTwapOrderMutation, useSymmChartCandles, useSymmChartSelection, useSymmClearTriggerConfigMutation, useSymmCloseAllPositionsMutation, useSymmCloseOrder, useSymmClosePositionMutation, useSymmContext, useSymmCoreClient, useSymmCreateAccountMutation, useSymmDeallocateCollateralMutation, useSymmDelegation, useSymmDepositAndAllocateMutation, useSymmDepositMutation, useSymmEditAccountNameMutation, useSymmFunding, useSymmFundingHistory, useSymmFundingPayments, useSymmHedgerMarketById, useSymmHedgerMarketBySymbol, useSymmHedgerMarkets, useSymmInstantTradeEnsureReadyMutation, useSymmInstantTradeExecuteMutation, useSymmInternalTransferCollateralMutation, useSymmLockedParams, useSymmMarkReadNotificationMutation, useSymmMarkets, useSymmNotificationsQuery, useSymmOpenBasketMutation, useSymmOpenOrders, useSymmPendingIds, useSymmPendingInstantOpens, useSymmPerformanceOverlays, useSymmPortfolio, useSymmPositions, useSymmSetTpslMutation, useSymmSetTriggerConfigMutation, useSymmSignTermsMutation, useSymmSignatureQuery, useSymmTokenSelectionMarkets, useSymmTokenSelectionMetadata, useSymmTpslOrders, useSymmTradeHistory, useSymmTriggerConfigQuery, useSymmTriggerOrders, useSymmTwapOrder, useSymmTwapOrdersQuery, useSymmUnreadCountQuery, useSymmUpdatePositionMutation, useSymmWithdraw, useSymmWs, useSymmWsStore };
|
|
26688
|
+
export { SymmProvider, getSymmErrorMessage, symmKeys, useBinanceMarkPriceStore, useSymmAccountData, useSymmAccountSummary, useSymmAccountsApi, useSymmAccountsLength, useSymmAccountsQuery, useSymmAccountsWithPositions, useSymmAllocateCollateralMutation, useSymmApprovalQuery, useSymmApproveMutation, useSymmAuth, useSymmAuthStore, useSymmAvailableMargin, useSymmBalances, useSymmCancelClose, useSymmCancelOpenMutation, useSymmCancelTpslMutation, useSymmCancelTwapOrderMutation, useSymmChartCandles, useSymmChartSelection, useSymmClearTriggerConfigMutation, useSymmCloseAllPositionsMutation, useSymmCloseOrder, useSymmClosePositionMutation, useSymmContext, useSymmCoreClient, useSymmCreateAccountMutation, useSymmDeallocateCollateralMutation, useSymmDelegation, useSymmDepositAndAllocateMutation, useSymmDepositMutation, useSymmEditAccountNameMutation, useSymmFunding, useSymmFundingHistory, useSymmFundingPayments, useSymmHedgerMarketById, useSymmHedgerMarketBySymbol, useSymmHedgerMarkets, useSymmInstantTradeEnsureReadyMutation, useSymmInstantTradeExecuteMutation, useSymmInternalTransferCollateralMutation, useSymmLockedParams, useSymmMarkReadNotificationMutation, useSymmMarkets, useSymmNotificationsQuery, useSymmOpenBasketMutation, useSymmOpenOrders, useSymmPendingIds, useSymmPendingInstantOpens, useSymmPerformanceOverlays, useSymmPortfolio, useSymmPositions, useSymmSetTpslMutation, useSymmSetTriggerConfigMutation, useSymmSignTermsMutation, useSymmSignatureQuery, useSymmTokenMarkPrice, useSymmTokenSelectionMarkets, useSymmTokenSelectionMetadata, useSymmTpslOrders, useSymmTradeHistory, useSymmTriggerConfigQuery, useSymmTriggerOrders, useSymmTwapOrder, useSymmTwapOrdersQuery, useSymmUnreadCountQuery, useSymmUpdatePositionMutation, useSymmWithdraw, useSymmWs, useSymmWsStore };
|
|
26504
26689
|
//# sourceMappingURL=index.mjs.map
|
|
26505
26690
|
//# sourceMappingURL=index.mjs.map
|