@n1xyz/nord-ts 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/Nord.js +1 -1
- package/dist/client/NordUser.d.ts +3 -0
- package/dist/client/NordUser.js +3 -0
- package/dist/gen/nord_pb.d.ts +12 -5
- package/dist/gen/nord_pb.js +12 -5
- package/dist/gen/openapi.d.ts +118 -66
- package/dist/nord/api/actions.d.ts +128 -0
- package/dist/nord/api/actions.js +396 -0
- package/dist/nord/api/core.d.ts +16 -0
- package/dist/nord/api/core.js +81 -0
- package/dist/nord/api/metrics.d.ts +67 -0
- package/dist/nord/api/metrics.js +229 -0
- package/dist/nord/api/triggers.d.ts +7 -0
- package/dist/nord/api/triggers.js +38 -0
- package/dist/nord/client/Nord.d.ts +387 -0
- package/dist/nord/client/Nord.js +747 -0
- package/dist/nord/client/NordAdmin.d.ts +226 -0
- package/dist/nord/client/NordAdmin.js +410 -0
- package/dist/nord/client/NordClient.d.ts +16 -0
- package/dist/nord/client/NordClient.js +28 -0
- package/dist/nord/client/NordUser.d.ts +379 -0
- package/dist/nord/client/NordUser.js +787 -0
- package/dist/nord/index.d.ts +8 -0
- package/dist/nord/index.js +34 -0
- package/dist/nord/models/Subscriber.d.ts +37 -0
- package/dist/nord/models/Subscriber.js +25 -0
- package/dist/nord/utils/NordError.d.ts +35 -0
- package/dist/nord/utils/NordError.js +49 -0
- package/dist/types.d.ts +26 -15
- package/dist/websocket/Subscriber.d.ts +2 -2
- package/package.json +1 -1
- package/dist/bundle.js +0 -79181
|
@@ -0,0 +1,747 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.Nord = void 0;
|
|
40
|
+
const proton_1 = require("@n1xyz/proton");
|
|
41
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
42
|
+
const events_1 = require("events");
|
|
43
|
+
const openapi_fetch_1 = __importDefault(require("openapi-fetch"));
|
|
44
|
+
const proto = __importStar(require("../../gen/nord_pb"));
|
|
45
|
+
const types_1 = require("../../types");
|
|
46
|
+
const utils = __importStar(require("../../utils"));
|
|
47
|
+
const core = __importStar(require("../api/core"));
|
|
48
|
+
const metrics = __importStar(require("../api/metrics"));
|
|
49
|
+
const NordError_1 = require("../utils/NordError");
|
|
50
|
+
/**
|
|
51
|
+
* Main Nord client class for interacting with the Nord API
|
|
52
|
+
*/
|
|
53
|
+
class Nord {
|
|
54
|
+
/**
|
|
55
|
+
* Create a new Nord client
|
|
56
|
+
*
|
|
57
|
+
* @param config - Configuration options for the Nord client
|
|
58
|
+
* @param config.webServerUrl - Base URL for the Nord web server
|
|
59
|
+
* @param config.solanaUrl - Solana cluster URL
|
|
60
|
+
* @throws {Error} If required configuration is missing
|
|
61
|
+
*/
|
|
62
|
+
constructor({ solanaUrl, webServerUrl, protonClient, }) {
|
|
63
|
+
/** Available markets */
|
|
64
|
+
this.markets = [];
|
|
65
|
+
/** Available tokens */
|
|
66
|
+
this.tokens = [];
|
|
67
|
+
/** Map of symbol to market_id */
|
|
68
|
+
this.symbolToMarketId = new Map();
|
|
69
|
+
this.webServerUrl = webServerUrl;
|
|
70
|
+
this.solanaUrl = solanaUrl;
|
|
71
|
+
this.protonClient = protonClient;
|
|
72
|
+
this.client = (0, openapi_fetch_1.default)({ baseUrl: webServerUrl });
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Create a WebSocket client with specific subscriptions
|
|
76
|
+
*
|
|
77
|
+
* @param options - Subscription options that specify which data streams to subscribe to
|
|
78
|
+
* @returns A new WebSocket client with the requested subscriptions
|
|
79
|
+
* @throws {NordError} If invalid subscription options are provided
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* // Create a client for trades and deltas from one market and an account
|
|
83
|
+
* const wsClient = nord.createWebSocketClient({
|
|
84
|
+
* trades: ["BTCUSDC"],
|
|
85
|
+
* deltas: ["BTCUSDC"],
|
|
86
|
+
* accounts: [123]
|
|
87
|
+
* });
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* // Create a client for trades from multiple markets
|
|
91
|
+
* const tradesClient = nord.createWebSocketClient({
|
|
92
|
+
* trades: ["BTCUSDC", "ETHUSDC"]
|
|
93
|
+
* });
|
|
94
|
+
*/
|
|
95
|
+
createWebSocketClient(options) {
|
|
96
|
+
const subscriptions = [];
|
|
97
|
+
// Add trade subscriptions
|
|
98
|
+
if (options.trades && options.trades.length > 0) {
|
|
99
|
+
options.trades.forEach((symbol) => {
|
|
100
|
+
subscriptions.push(`trades@${symbol}`);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// Add delta subscriptions
|
|
104
|
+
if (options.deltas && options.deltas.length > 0) {
|
|
105
|
+
options.deltas.forEach((symbol) => {
|
|
106
|
+
subscriptions.push(`deltas@${symbol}`);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// Add account subscriptions
|
|
110
|
+
if (options.accounts && options.accounts.length > 0) {
|
|
111
|
+
options.accounts.forEach((accountId) => {
|
|
112
|
+
if (isNaN(accountId) || accountId <= 0) {
|
|
113
|
+
throw new NordError_1.NordError(`Invalid account ID: ${accountId}. Must be a positive number.`);
|
|
114
|
+
}
|
|
115
|
+
subscriptions.push(`account@${accountId}`);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
// Validate that at least one subscription was provided
|
|
119
|
+
if (subscriptions.length === 0) {
|
|
120
|
+
throw new NordError_1.NordError("At least one subscription must be provided");
|
|
121
|
+
}
|
|
122
|
+
// Create and return a new WebSocket client
|
|
123
|
+
return core.initWebSocketClient(this.webServerUrl, subscriptions);
|
|
124
|
+
}
|
|
125
|
+
async GET(path, options) {
|
|
126
|
+
const r = await this.client.GET(path, options);
|
|
127
|
+
if (r.error) {
|
|
128
|
+
throw new NordError_1.NordError(`failed to GET ${path}`, { cause: r.error });
|
|
129
|
+
}
|
|
130
|
+
if (r.data === undefined) {
|
|
131
|
+
// this should never happen, but the type checker seems unhappy.
|
|
132
|
+
// if we catch this we'll need to debug accordingly.
|
|
133
|
+
throw new NordError_1.NordError("internal assertion violation", { cause: r });
|
|
134
|
+
}
|
|
135
|
+
return r.data;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get the current timestamp from the Nord server
|
|
139
|
+
*
|
|
140
|
+
* @returns Current timestamp as a bigint
|
|
141
|
+
* @throws {NordError} If the request fails
|
|
142
|
+
*/
|
|
143
|
+
async getTimestamp() {
|
|
144
|
+
return BigInt(await this.GET("/timestamp", {}));
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get the last event nonce from the Nord server
|
|
148
|
+
*
|
|
149
|
+
* @returns Next action nonce
|
|
150
|
+
* @throws {NordError} If the request fails
|
|
151
|
+
*/
|
|
152
|
+
async getActionNonce() {
|
|
153
|
+
return await this.GET("/event/last-acked-nonce", {});
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Fetch information about Nord markets and tokens
|
|
157
|
+
*
|
|
158
|
+
* @throws {NordError} If the request fails
|
|
159
|
+
*/
|
|
160
|
+
async fetchNordInfo() {
|
|
161
|
+
try {
|
|
162
|
+
const info = await this.GET("/info", {});
|
|
163
|
+
this.markets = info.markets;
|
|
164
|
+
this.tokens = info.tokens;
|
|
165
|
+
// Populate the symbolToMarketId map
|
|
166
|
+
this.symbolToMarketId.clear();
|
|
167
|
+
info.markets.forEach((market) => {
|
|
168
|
+
this.symbolToMarketId.set(market.symbol, market.marketId);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
throw new NordError_1.NordError("Failed to fetch Nord info", { cause: error });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Initialize a new Nord client
|
|
177
|
+
*
|
|
178
|
+
* @param nordConfig - Configuration options for the Nord client
|
|
179
|
+
* @param nordConfig.webServerUrl - Base URL for the Nord web server
|
|
180
|
+
* @param nordConfig.app - App address
|
|
181
|
+
* @param nordConfig.solanaUrl - Solana cluster URL
|
|
182
|
+
* @returns Initialized Nord client
|
|
183
|
+
* @throws {NordError} If initialization fails
|
|
184
|
+
*/
|
|
185
|
+
static async initNord({ app, solanaUrl, webServerUrl, protonUrl, }) {
|
|
186
|
+
// TODO: we should parametrize the connectionn not have it done here.
|
|
187
|
+
// this is a dogshit api, only here to be compatible with the shitty
|
|
188
|
+
// vibecoded code and not break zero one team's workflow.
|
|
189
|
+
const connection = new web3_js_1.Connection(solanaUrl, { commitment: "confirmed" });
|
|
190
|
+
const protonClient = await proton_1.ProtonClient.init({
|
|
191
|
+
protonUrl: protonUrl ?? webServerUrl,
|
|
192
|
+
app: new web3_js_1.PublicKey(app),
|
|
193
|
+
solConn: connection,
|
|
194
|
+
});
|
|
195
|
+
const nord = new Nord({
|
|
196
|
+
protonClient,
|
|
197
|
+
solanaUrl,
|
|
198
|
+
webServerUrl,
|
|
199
|
+
});
|
|
200
|
+
await nord.init();
|
|
201
|
+
return nord;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Initialize the Nord client
|
|
205
|
+
* @private
|
|
206
|
+
*/
|
|
207
|
+
async init() {
|
|
208
|
+
await this.fetchNordInfo();
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Query a specific action
|
|
212
|
+
*
|
|
213
|
+
* @param query - Action query parameters
|
|
214
|
+
* @returns Action response
|
|
215
|
+
* @throws {NordError} If the request fails
|
|
216
|
+
*/
|
|
217
|
+
async queryAction({ action_id, }) {
|
|
218
|
+
return ((await this.queryRecentActions({
|
|
219
|
+
from: action_id,
|
|
220
|
+
to: action_id,
|
|
221
|
+
}))[0] ?? null);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Query recent actions
|
|
225
|
+
*
|
|
226
|
+
* @param from - Starting action index
|
|
227
|
+
* @param to - Ending action index
|
|
228
|
+
* @returns Actions response
|
|
229
|
+
* @throws {NordError} If the request fails
|
|
230
|
+
*/
|
|
231
|
+
async queryRecentActions(query) {
|
|
232
|
+
const xs = await this.GET("/action", {
|
|
233
|
+
params: {
|
|
234
|
+
query,
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
return xs.map((x) => ({
|
|
238
|
+
actionId: x.actionId,
|
|
239
|
+
action: utils.decodeLengthDelimited(Buffer.from(x.payload, "base64"), proto.ActionSchema),
|
|
240
|
+
physicalExecTime: new Date(x.physicalTime),
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get the last action ID
|
|
245
|
+
*
|
|
246
|
+
* @returns Last action ID
|
|
247
|
+
* @throws {NordError} If the request fails
|
|
248
|
+
*/
|
|
249
|
+
async getLastActionId() {
|
|
250
|
+
return await this.GET("/action/last-executed-id", {});
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Fetch aggregate metrics from the Nord API
|
|
254
|
+
*
|
|
255
|
+
* @param txPeakTpsPeriod - Period for peak TPS calculation
|
|
256
|
+
* @param txPeakTpsPeriodUnit - Unit for peak TPS period
|
|
257
|
+
* @returns Aggregate metrics
|
|
258
|
+
* @throws {NordError} If the request fails
|
|
259
|
+
*/
|
|
260
|
+
async aggregateMetrics(txPeakTpsPeriod = 1, txPeakTpsPeriodUnit = types_1.PeakTpsPeriodUnit.Day) {
|
|
261
|
+
return metrics.aggregateMetrics(this.webServerUrl, txPeakTpsPeriod, txPeakTpsPeriodUnit);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Get current transactions per second
|
|
265
|
+
*
|
|
266
|
+
* @param period - Time period for the query
|
|
267
|
+
* @returns Current TPS value
|
|
268
|
+
* @throws {NordError} If the request fails
|
|
269
|
+
*/
|
|
270
|
+
async getCurrentTps(period = "1m") {
|
|
271
|
+
return metrics.getCurrentTps(this.webServerUrl, period);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Get peak transactions per second
|
|
275
|
+
*
|
|
276
|
+
* @param period - Time period for the query
|
|
277
|
+
* @returns Peak TPS value
|
|
278
|
+
* @throws {NordError} If the request fails
|
|
279
|
+
*/
|
|
280
|
+
async getPeakTps(period = "24h") {
|
|
281
|
+
return metrics.getPeakTps(this.webServerUrl, period);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Get median transaction latency
|
|
285
|
+
*
|
|
286
|
+
* @param period - Time period for the query
|
|
287
|
+
* @returns Median latency in milliseconds
|
|
288
|
+
* @throws {NordError} If the request fails
|
|
289
|
+
*/
|
|
290
|
+
async getMedianLatency(period = "1m") {
|
|
291
|
+
return metrics.getMedianLatency(this.webServerUrl, period);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Get total transaction count
|
|
295
|
+
*
|
|
296
|
+
* @returns Total transaction count
|
|
297
|
+
* @throws {NordError} If the request fails
|
|
298
|
+
*/
|
|
299
|
+
async getTotalTransactions() {
|
|
300
|
+
return metrics.getTotalTransactions(this.webServerUrl);
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Query Prometheus metrics
|
|
304
|
+
*
|
|
305
|
+
* @param params - Prometheus query parameters
|
|
306
|
+
* @returns Query result as a number
|
|
307
|
+
* @throws {NordError} If the request fails
|
|
308
|
+
*/
|
|
309
|
+
async queryPrometheus(params) {
|
|
310
|
+
return metrics.queryPrometheus(this.webServerUrl, params);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Subscribe to orderbook updates for a market
|
|
314
|
+
*
|
|
315
|
+
* @param symbol - Market symbol
|
|
316
|
+
* @returns Orderbook subscription
|
|
317
|
+
* @throws {NordError} If symbol is invalid
|
|
318
|
+
*/
|
|
319
|
+
subscribeOrderbook(symbol) {
|
|
320
|
+
if (!symbol || typeof symbol !== "string") {
|
|
321
|
+
throw new NordError_1.NordError("Invalid market symbol");
|
|
322
|
+
}
|
|
323
|
+
const subscription = new events_1.EventEmitter();
|
|
324
|
+
const wsClient = this.createWebSocketClient({
|
|
325
|
+
deltas: [symbol],
|
|
326
|
+
});
|
|
327
|
+
const handleDelta = (update) => {
|
|
328
|
+
if (update.symbol !== symbol) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
subscription.emit("message", update);
|
|
332
|
+
};
|
|
333
|
+
wsClient.on("delta", handleDelta);
|
|
334
|
+
subscription.close = () => {
|
|
335
|
+
wsClient.removeListener("delta", handleDelta);
|
|
336
|
+
subscription.removeAllListeners();
|
|
337
|
+
};
|
|
338
|
+
return subscription;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Subscribe to trade updates for a market
|
|
342
|
+
*
|
|
343
|
+
* @param symbol - Market symbol
|
|
344
|
+
* @returns Trade subscription
|
|
345
|
+
* @throws {NordError} If symbol is invalid
|
|
346
|
+
*/
|
|
347
|
+
subscribeTrades(symbol) {
|
|
348
|
+
if (!symbol || typeof symbol !== "string") {
|
|
349
|
+
throw new NordError_1.NordError("Invalid market symbol");
|
|
350
|
+
}
|
|
351
|
+
const subscription = new events_1.EventEmitter();
|
|
352
|
+
const wsClient = this.createWebSocketClient({
|
|
353
|
+
trades: [symbol],
|
|
354
|
+
});
|
|
355
|
+
const handleTrade = (update) => {
|
|
356
|
+
if (update.symbol !== symbol) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
subscription.emit("message", update);
|
|
360
|
+
};
|
|
361
|
+
wsClient.on("trades", handleTrade);
|
|
362
|
+
subscription.close = () => {
|
|
363
|
+
wsClient.removeListener("trades", handleTrade);
|
|
364
|
+
subscription.removeAllListeners();
|
|
365
|
+
};
|
|
366
|
+
return subscription;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Subscribe to account updates
|
|
370
|
+
*
|
|
371
|
+
* @param accountId - Account ID to subscribe to
|
|
372
|
+
* @returns User subscription
|
|
373
|
+
* @throws {NordError} If accountId is invalid
|
|
374
|
+
*/
|
|
375
|
+
subscribeAccount(accountId) {
|
|
376
|
+
if (isNaN(accountId) || accountId <= 0) {
|
|
377
|
+
throw new NordError_1.NordError("Invalid account ID");
|
|
378
|
+
}
|
|
379
|
+
const subscription = new events_1.EventEmitter();
|
|
380
|
+
const wsClient = this.createWebSocketClient({
|
|
381
|
+
accounts: [accountId],
|
|
382
|
+
});
|
|
383
|
+
const handleAccountUpdate = (update) => {
|
|
384
|
+
if (update.account_id !== accountId) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
subscription.emit("message", update);
|
|
388
|
+
};
|
|
389
|
+
wsClient.on("account", handleAccountUpdate);
|
|
390
|
+
subscription.close = () => {
|
|
391
|
+
wsClient.removeListener("account", handleAccountUpdate);
|
|
392
|
+
subscription.removeAllListeners();
|
|
393
|
+
};
|
|
394
|
+
return subscription;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Get trades for a market
|
|
398
|
+
*
|
|
399
|
+
* @param query - Trades query parameters
|
|
400
|
+
* @returns Trades response
|
|
401
|
+
* @throws {NordError} If the request fails
|
|
402
|
+
*/
|
|
403
|
+
async getTrades(query) {
|
|
404
|
+
if (query.sinceRcf3339 && !utils.isRfc3339(query.sinceRcf3339)) {
|
|
405
|
+
throw new NordError_1.NordError(`Invalid RFC3339 timestamp: ${query.sinceRcf3339}`);
|
|
406
|
+
}
|
|
407
|
+
if (query.untilRfc3339 && !utils.isRfc3339(query.untilRfc3339)) {
|
|
408
|
+
throw new NordError_1.NordError(`Invalid RFC3339 timestamp: ${query.untilRfc3339}`);
|
|
409
|
+
}
|
|
410
|
+
return await this.GET("/trades", {
|
|
411
|
+
params: {
|
|
412
|
+
query: {
|
|
413
|
+
takerId: query.takerId,
|
|
414
|
+
makerId: query.makerId,
|
|
415
|
+
marketId: query.marketId,
|
|
416
|
+
pageSize: query.pageSize,
|
|
417
|
+
takerSide: query.takerSide,
|
|
418
|
+
since: query.sinceRcf3339,
|
|
419
|
+
until: query.untilRfc3339,
|
|
420
|
+
startInclusive: query.pageId,
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Get user account IDs
|
|
427
|
+
*
|
|
428
|
+
* @param query - User account IDs query parameters
|
|
429
|
+
* @returns User account IDs response
|
|
430
|
+
* @throws {NordError} If the request fails
|
|
431
|
+
*/
|
|
432
|
+
async getUser(query) {
|
|
433
|
+
const r = await this.client.GET("/user/{pubkey}", {
|
|
434
|
+
params: {
|
|
435
|
+
path: { pubkey: query.pubkey.toString() },
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
if (r.response.status === 404) {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
return r.data;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Get orderbook for a market
|
|
445
|
+
*
|
|
446
|
+
* @param query - Orderbook query parameters (either market_id or symbol must be provided)
|
|
447
|
+
* @returns Orderbook response
|
|
448
|
+
* @throws {NordError} If the request fails or if the market symbol is unknown
|
|
449
|
+
* @remarks It's recommended to initialize the Nord client using the static `initNord` method
|
|
450
|
+
* to ensure market information is properly loaded before calling this method.
|
|
451
|
+
*/
|
|
452
|
+
async getOrderbook(query) {
|
|
453
|
+
// If only symbol is provided, convert it to market_id
|
|
454
|
+
let marketId;
|
|
455
|
+
if (query.symbol && query.market_id === undefined) {
|
|
456
|
+
// If the map is empty, try to fetch market information first
|
|
457
|
+
if (this.symbolToMarketId.size === 0) {
|
|
458
|
+
await this.fetchNordInfo();
|
|
459
|
+
}
|
|
460
|
+
const id = this.symbolToMarketId.get(query.symbol);
|
|
461
|
+
if (id === undefined) {
|
|
462
|
+
throw new NordError_1.NordError(`Unknown market symbol: ${query.symbol}`);
|
|
463
|
+
}
|
|
464
|
+
marketId = id;
|
|
465
|
+
}
|
|
466
|
+
else if (query.market_id !== undefined) {
|
|
467
|
+
marketId = query.market_id;
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
throw new NordError_1.NordError("Either symbol or market_id must be provided for orderbook query");
|
|
471
|
+
}
|
|
472
|
+
return await this.GET("/market/{market_id}/orderbook", {
|
|
473
|
+
params: {
|
|
474
|
+
path: { market_id: marketId },
|
|
475
|
+
},
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Get information about the Nord server
|
|
480
|
+
*
|
|
481
|
+
* @returns Information about markets and tokens
|
|
482
|
+
* @throws {NordError} If the request fails
|
|
483
|
+
*/
|
|
484
|
+
async getInfo() {
|
|
485
|
+
return await this.GET("/info", {});
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Fetch the current fee tier brackets configured on Nord.
|
|
489
|
+
*
|
|
490
|
+
* @returns Array of fee tier identifiers paired with their configuration
|
|
491
|
+
* @throws {NordError} If the request fails
|
|
492
|
+
*/
|
|
493
|
+
async getFeeBrackets() {
|
|
494
|
+
return await this.GET("/fee/brackets/info", {});
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Retrieve the fee tier assigned to a specific account.
|
|
498
|
+
*
|
|
499
|
+
* @param accountId - Account identifier to query
|
|
500
|
+
* @returns Fee tier details for the requested account
|
|
501
|
+
* @throws {NordError} If the request fails
|
|
502
|
+
*/
|
|
503
|
+
async getAccountFeeTier(accountId) {
|
|
504
|
+
return await this.GET("/account/{account_id}/fee/tier", {
|
|
505
|
+
params: {
|
|
506
|
+
path: { account_id: accountId },
|
|
507
|
+
},
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Get account information
|
|
512
|
+
*
|
|
513
|
+
* @param accountId - Account ID to get information for
|
|
514
|
+
* @returns Account information
|
|
515
|
+
* @throws {NordError} If the request fails
|
|
516
|
+
*/
|
|
517
|
+
async getAccount(accountId) {
|
|
518
|
+
return await this.GET("/account/{account_id}", {
|
|
519
|
+
params: {
|
|
520
|
+
path: { account_id: accountId },
|
|
521
|
+
},
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Get the public key associated with an account id.
|
|
526
|
+
*
|
|
527
|
+
* @param accountId - Account id to query
|
|
528
|
+
* @returns Base58-encoded account public key
|
|
529
|
+
* @throws {NordError} If the request fails
|
|
530
|
+
*/
|
|
531
|
+
async getAccountPubkey(accountId) {
|
|
532
|
+
return await this.GET("/account/{account_id}/pubkey", {
|
|
533
|
+
params: {
|
|
534
|
+
path: { account_id: accountId },
|
|
535
|
+
},
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Get the withdrawal fee charged for an account.
|
|
540
|
+
*
|
|
541
|
+
* @param accountId - Account id to query
|
|
542
|
+
* @returns Withdrawal fee quoted in quote token units
|
|
543
|
+
* @throws {NordError} If the request fails
|
|
544
|
+
*/
|
|
545
|
+
async getAccountWithdrawalFee(accountId) {
|
|
546
|
+
return await this.GET("/account/{account_id}/fees/withdrawal", {
|
|
547
|
+
params: {
|
|
548
|
+
path: { account_id: accountId },
|
|
549
|
+
},
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Get open orders for an account.
|
|
554
|
+
*
|
|
555
|
+
* @param accountId - Account id to query
|
|
556
|
+
* @param query - Optional pagination parameters
|
|
557
|
+
* @returns Page of orders keyed by client order id
|
|
558
|
+
* @throws {NordError} If the request fails
|
|
559
|
+
*/
|
|
560
|
+
async getAccountOrders(accountId, query) {
|
|
561
|
+
return await this.GET("/account/{account_id}/orders", {
|
|
562
|
+
params: {
|
|
563
|
+
path: { account_id: accountId },
|
|
564
|
+
query: {
|
|
565
|
+
startInclusive: query?.startInclusive,
|
|
566
|
+
pageSize: query?.pageSize,
|
|
567
|
+
},
|
|
568
|
+
},
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* List account fee tiers with pagination support.
|
|
573
|
+
*/
|
|
574
|
+
async getAccountsFeeTiers(query) {
|
|
575
|
+
return await this.GET("/accounts/fee-tiers", {
|
|
576
|
+
params: {
|
|
577
|
+
query: {
|
|
578
|
+
startInclusive: query?.startInclusive ?? undefined,
|
|
579
|
+
pageSize: query?.pageSize ?? undefined,
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Get profit and loss history for an account
|
|
586
|
+
*
|
|
587
|
+
* @param accountId - Account ID to query
|
|
588
|
+
* @param query - Optional time and pagination filters
|
|
589
|
+
* @returns Page of PnL entries ordered from latest to oldest
|
|
590
|
+
* @throws {NordError} If the request fails
|
|
591
|
+
*/
|
|
592
|
+
async getAccountPnl(accountId, query) {
|
|
593
|
+
return await this.GET("/account/{account_id}/pnl", {
|
|
594
|
+
params: {
|
|
595
|
+
path: { account_id: accountId },
|
|
596
|
+
query: {
|
|
597
|
+
since: query?.since,
|
|
598
|
+
until: query?.until,
|
|
599
|
+
startInclusive: query?.startInclusive,
|
|
600
|
+
pageSize: query?.pageSize,
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Get market statistics (alias for marketsStats for backward compatibility)
|
|
607
|
+
*
|
|
608
|
+
* @returns Market statistics response
|
|
609
|
+
*/
|
|
610
|
+
async getMarketStats({ marketId, }) {
|
|
611
|
+
return await this.GET("/market/{market_id}/stats", {
|
|
612
|
+
params: {
|
|
613
|
+
path: { market_id: marketId },
|
|
614
|
+
},
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Fetch the per-market fee quote for an account.
|
|
619
|
+
*
|
|
620
|
+
* @param params - Market id, fee kind, and account id to quote
|
|
621
|
+
* @returns Fee in quote token units (negative means fee is charged)
|
|
622
|
+
* @throws {NordError} If the request fails
|
|
623
|
+
*/
|
|
624
|
+
async getMarketFee({ marketId, feeKind, accountId, }) {
|
|
625
|
+
return await this.GET("/market/{market_id}/fees/{fee_kind}/{account_id}", {
|
|
626
|
+
params: {
|
|
627
|
+
path: {
|
|
628
|
+
market_id: marketId,
|
|
629
|
+
fee_kind: feeKind,
|
|
630
|
+
account_id: accountId,
|
|
631
|
+
},
|
|
632
|
+
},
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Fetch token statistics such as index price and oracle metadata.
|
|
637
|
+
*
|
|
638
|
+
* @param tokenId - Token identifier
|
|
639
|
+
* @returns Token stats
|
|
640
|
+
* @throws {NordError} If the request fails
|
|
641
|
+
*/
|
|
642
|
+
async getTokenStats(tokenId) {
|
|
643
|
+
return await this.GET("/tokens/{token_id}/stats", {
|
|
644
|
+
params: {
|
|
645
|
+
path: { token_id: tokenId },
|
|
646
|
+
},
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Get order summary by order id.
|
|
651
|
+
*
|
|
652
|
+
* @param orderId - Order identifier
|
|
653
|
+
* @returns Order information
|
|
654
|
+
* @throws {NordError} If the request fails
|
|
655
|
+
*/
|
|
656
|
+
async getOrder(orderId) {
|
|
657
|
+
return await this.GET("/order/{order_id}", {
|
|
658
|
+
params: {
|
|
659
|
+
path: { order_id: orderId },
|
|
660
|
+
},
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Get trade history for a specific order.
|
|
665
|
+
*
|
|
666
|
+
* @param orderId - Order identifier
|
|
667
|
+
* @param query - Optional pagination parameters
|
|
668
|
+
* @returns Page of trades associated with the order
|
|
669
|
+
* @throws {NordError} If the request fails
|
|
670
|
+
*/
|
|
671
|
+
async getOrderTrades(orderId, query) {
|
|
672
|
+
return await this.GET("/order/{order_id}/trades", {
|
|
673
|
+
params: {
|
|
674
|
+
path: { order_id: orderId },
|
|
675
|
+
query: {
|
|
676
|
+
startInclusive: query?.startInclusive,
|
|
677
|
+
pageSize: query?.pageSize,
|
|
678
|
+
},
|
|
679
|
+
},
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Check if an account exists for the given address
|
|
684
|
+
*
|
|
685
|
+
* @param address - The public key address to check
|
|
686
|
+
* @returns True if the account exists, false otherwise
|
|
687
|
+
* @deprecated use getUser instead
|
|
688
|
+
*/
|
|
689
|
+
async accountExists(pubkey) {
|
|
690
|
+
return !!(await this.getUser({ pubkey }));
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Fetch active triggers for an account.
|
|
694
|
+
*
|
|
695
|
+
* @param params Optional parameters containing an explicit account id.
|
|
696
|
+
* @throws {NordError} If no account can be resolved or the request fails.
|
|
697
|
+
*/
|
|
698
|
+
async getAccountTriggers(params) {
|
|
699
|
+
const accountId = params?.accountId;
|
|
700
|
+
if (accountId == null) {
|
|
701
|
+
throw new NordError_1.NordError("Account ID is undefined. Make sure to call updateAccountId() before requesting triggers.");
|
|
702
|
+
}
|
|
703
|
+
try {
|
|
704
|
+
const triggers = await this.GET("/account/{account_id}/triggers", {
|
|
705
|
+
params: {
|
|
706
|
+
path: { account_id: accountId },
|
|
707
|
+
},
|
|
708
|
+
});
|
|
709
|
+
return triggers ?? [];
|
|
710
|
+
}
|
|
711
|
+
catch (error) {
|
|
712
|
+
throw new NordError_1.NordError("Failed to fetch account triggers", { cause: error });
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Fetch trigger history for an account.
|
|
717
|
+
*
|
|
718
|
+
* @param params Optional parameters with account id and history query filters.
|
|
719
|
+
* @throws {NordError} If no account can be resolved or the request fails.
|
|
720
|
+
*/
|
|
721
|
+
async getAccountTriggerHistory(params) {
|
|
722
|
+
const accountId = params?.accountId;
|
|
723
|
+
if (accountId == null) {
|
|
724
|
+
throw new NordError_1.NordError("Account ID is undefined. Make sure to call updateAccountId() before requesting trigger history.");
|
|
725
|
+
}
|
|
726
|
+
const { accountId: _, ...query } = params;
|
|
727
|
+
try {
|
|
728
|
+
return await this.GET("/account/{account_id}/triggers/history", {
|
|
729
|
+
params: {
|
|
730
|
+
path: { account_id: accountId },
|
|
731
|
+
query: {
|
|
732
|
+
since: query.since,
|
|
733
|
+
until: query.until,
|
|
734
|
+
pageSize: query.pageSize,
|
|
735
|
+
startInclusive: query.startInclusive,
|
|
736
|
+
},
|
|
737
|
+
},
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
catch (error) {
|
|
741
|
+
throw new NordError_1.NordError("Failed to fetch account trigger history", {
|
|
742
|
+
cause: error,
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
exports.Nord = Nord;
|