@n1xyz/nord-ts 0.1.6 → 0.1.7
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/actions.d.ts +57 -0
- package/dist/actions.js +229 -0
- package/dist/client/Nord.d.ts +379 -0
- package/dist/client/Nord.js +718 -0
- package/dist/client/NordAdmin.d.ts +225 -0
- package/dist/client/NordAdmin.js +394 -0
- package/dist/client/NordUser.d.ts +350 -0
- package/dist/client/NordUser.js +743 -0
- package/dist/error.d.ts +35 -0
- package/dist/error.js +49 -0
- package/dist/gen/openapi.d.ts +40 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +29 -1
- package/dist/nord/client/NordAdmin.js +2 -0
- package/dist/types.d.ts +4 -50
- package/dist/types.js +1 -24
- package/dist/utils.d.ts +8 -11
- package/dist/utils.js +54 -41
- package/dist/websocket/Subscriber.d.ts +37 -0
- package/dist/websocket/Subscriber.js +25 -0
- package/dist/websocket/index.d.ts +19 -2
- package/dist/websocket/index.js +82 -2
- package/package.json +1 -1
- package/src/actions.ts +333 -0
- package/src/{nord/client → client}/Nord.ts +207 -210
- package/src/{nord/client → client}/NordAdmin.ts +123 -153
- package/src/{nord/client → client}/NordUser.ts +216 -305
- package/src/gen/openapi.ts +40 -0
- package/src/index.ts +7 -1
- package/src/types.ts +4 -54
- package/src/utils.ts +44 -47
- package/src/{nord/models → websocket}/Subscriber.ts +2 -2
- package/src/websocket/index.ts +105 -2
- package/src/nord/api/actions.ts +0 -648
- package/src/nord/api/core.ts +0 -96
- package/src/nord/api/metrics.ts +0 -269
- package/src/nord/client/NordClient.ts +0 -79
- package/src/nord/index.ts +0 -25
- /package/src/{nord/utils/NordError.ts → error.ts} +0 -0
package/src/gen/openapi.ts
CHANGED
|
@@ -1232,6 +1232,44 @@ export interface paths {
|
|
|
1232
1232
|
patch?: never;
|
|
1233
1233
|
trace?: never;
|
|
1234
1234
|
};
|
|
1235
|
+
"/admin": {
|
|
1236
|
+
parameters: {
|
|
1237
|
+
query?: never;
|
|
1238
|
+
header?: never;
|
|
1239
|
+
path?: never;
|
|
1240
|
+
cookie?: never;
|
|
1241
|
+
};
|
|
1242
|
+
/** @description List of assigned admins. */
|
|
1243
|
+
get: {
|
|
1244
|
+
parameters: {
|
|
1245
|
+
query?: never;
|
|
1246
|
+
header?: never;
|
|
1247
|
+
path?: never;
|
|
1248
|
+
cookie?: never;
|
|
1249
|
+
};
|
|
1250
|
+
requestBody?: never;
|
|
1251
|
+
responses: {
|
|
1252
|
+
200: {
|
|
1253
|
+
headers: {
|
|
1254
|
+
[name: string]: unknown;
|
|
1255
|
+
};
|
|
1256
|
+
content: {
|
|
1257
|
+
"application/json": [
|
|
1258
|
+
string,
|
|
1259
|
+
components["schemas"]["AclRole"]
|
|
1260
|
+
][];
|
|
1261
|
+
};
|
|
1262
|
+
};
|
|
1263
|
+
};
|
|
1264
|
+
};
|
|
1265
|
+
put?: never;
|
|
1266
|
+
post?: never;
|
|
1267
|
+
delete?: never;
|
|
1268
|
+
options?: never;
|
|
1269
|
+
head?: never;
|
|
1270
|
+
patch?: never;
|
|
1271
|
+
trace?: never;
|
|
1272
|
+
};
|
|
1235
1273
|
"/tv": {
|
|
1236
1274
|
parameters: {
|
|
1237
1275
|
query?: never;
|
|
@@ -2689,6 +2727,8 @@ export interface components {
|
|
|
2689
2727
|
accountId: number;
|
|
2690
2728
|
feeTier: components["schemas"]["FeeTierId"];
|
|
2691
2729
|
};
|
|
2730
|
+
/** Format: uint32 */
|
|
2731
|
+
AclRole: number;
|
|
2692
2732
|
/** @description TV config query response https://www.tradingview.com/charting-library-docs/latest/connecting_data/UDF/#data-feed-configuration-data */
|
|
2693
2733
|
TvConfigResponse: {
|
|
2694
2734
|
supported_resolutions: components["schemas"]["Resolution"][];
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export * from "./types";
|
|
2
2
|
export * from "./utils";
|
|
3
3
|
export * from "./const";
|
|
4
|
-
export * from "./
|
|
4
|
+
export * from "./error";
|
|
5
5
|
export * from "./websocket/index";
|
|
6
|
+
export * from "./client/Nord";
|
|
7
|
+
export * from "./client/NordUser";
|
|
8
|
+
export * from "./client/NordAdmin";
|
|
9
|
+
|
|
10
|
+
export * as proto from "./gen/nord_pb";
|
|
11
|
+
export * as openapi from "./gen/openapi";
|
package/src/types.ts
CHANGED
|
@@ -2,23 +2,7 @@ import * as proto from "./gen/nord_pb";
|
|
|
2
2
|
import type { components } from "./gen/openapi.ts";
|
|
3
3
|
import Decimal from "decimal.js";
|
|
4
4
|
import { toScaledU64 } from "./utils";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* The peak TPS rate is queried over the specified period.
|
|
8
|
-
* The period is specified in units of: {hour, day, week, month, year}.
|
|
9
|
-
* Example inputs:
|
|
10
|
-
* 1. AggregateMetrics.txPeakTpsPeriod = 3,
|
|
11
|
-
* AggregateMetrics.txPeakTpsPeriodUnit = "d" => Peak TPS over last 3 days.
|
|
12
|
-
* 1. AggregateMetrics.txPeakTpsPeriod = 1,
|
|
13
|
-
* AggregateMetrics.txPeakTpsPeriodUnit = "w" => Peak TPS over last week.
|
|
14
|
-
*/
|
|
15
|
-
export enum PeakTpsPeriodUnit {
|
|
16
|
-
Hour = "h",
|
|
17
|
-
Day = "d",
|
|
18
|
-
Week = "w",
|
|
19
|
-
Month = "m",
|
|
20
|
-
Year = "y",
|
|
21
|
-
}
|
|
5
|
+
import { Connection } from "@solana/web3.js";
|
|
22
6
|
|
|
23
7
|
/**
|
|
24
8
|
* Nord subscription type for trades or deltas
|
|
@@ -40,8 +24,8 @@ export interface NordConfig {
|
|
|
40
24
|
webServerUrl: string;
|
|
41
25
|
/** App address */
|
|
42
26
|
app: string;
|
|
43
|
-
/** Solana
|
|
44
|
-
|
|
27
|
+
/** Solana connection */
|
|
28
|
+
solanaConnection: Connection;
|
|
45
29
|
/** Proton URL, defaults to webServerUrl */
|
|
46
30
|
// TODO: this is ass. move to NordUser.
|
|
47
31
|
protonUrl?: string;
|
|
@@ -124,12 +108,6 @@ export interface Order {
|
|
|
124
108
|
marketId: number;
|
|
125
109
|
}
|
|
126
110
|
|
|
127
|
-
export enum KeyType {
|
|
128
|
-
Ed25519,
|
|
129
|
-
Secp256k1,
|
|
130
|
-
Bls12_381,
|
|
131
|
-
}
|
|
132
|
-
|
|
133
111
|
export enum Side {
|
|
134
112
|
Ask = "ask",
|
|
135
113
|
Bid = "bid",
|
|
@@ -200,34 +178,6 @@ export interface ActionResponse {
|
|
|
200
178
|
physicalExecTime: Date;
|
|
201
179
|
}
|
|
202
180
|
|
|
203
|
-
/**
|
|
204
|
-
* Block summary.
|
|
205
|
-
* block_number Block number.
|
|
206
|
-
* from_action_id First action_id in the block.
|
|
207
|
-
* to_action_id Last action_id in the block.
|
|
208
|
-
*/
|
|
209
|
-
export interface BlockSummary {
|
|
210
|
-
block_number: number;
|
|
211
|
-
from_action_id: number;
|
|
212
|
-
to_action_id: number;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Aggregate metrics
|
|
217
|
-
* blocks_total: Total number of L2 blocks.
|
|
218
|
-
* tx_total: Total number of transactions.
|
|
219
|
-
* tx_tps: Transaction throughput.
|
|
220
|
-
* tx_tps_peak: Peak transaction throughput.
|
|
221
|
-
* request_latency_average: Average request latency.
|
|
222
|
-
*/
|
|
223
|
-
export interface AggregateMetrics {
|
|
224
|
-
blocks_total: number;
|
|
225
|
-
tx_total: number;
|
|
226
|
-
tx_tps: number;
|
|
227
|
-
tx_tps_peak: number;
|
|
228
|
-
request_latency_average: number;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
181
|
/**
|
|
232
182
|
* Converts a `FillMode` enum to its corresponding protobuf representation.
|
|
233
183
|
*
|
|
@@ -261,7 +211,7 @@ export interface OrderbookEntry {
|
|
|
261
211
|
*/
|
|
262
212
|
export interface OrderbookQuery {
|
|
263
213
|
symbol?: string;
|
|
264
|
-
|
|
214
|
+
marketId?: number;
|
|
265
215
|
}
|
|
266
216
|
|
|
267
217
|
/**
|
package/src/utils.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { Decimal } from "decimal.js";
|
|
2
|
-
import {
|
|
3
|
-
import { bls12_381 as bls } from "@noble/curves/bls12-381";
|
|
4
|
-
import { secp256k1 as secp } from "@noble/curves/secp256k1";
|
|
5
|
-
import { sha256 } from "@noble/hashes/sha256";
|
|
6
|
-
import { KeyType, type Market, type Token } from "./types";
|
|
2
|
+
import { type Market, type Token } from "./types";
|
|
7
3
|
import { sizeDelimitedPeek } from "@bufbuild/protobuf/wire";
|
|
8
4
|
import { fromBinary, type Message } from "@bufbuild/protobuf";
|
|
9
5
|
import type { GenMessage } from "@bufbuild/protobuf/codegenv2";
|
|
@@ -12,6 +8,7 @@ import fetch from "node-fetch";
|
|
|
12
8
|
import { RequestInfo, RequestInit, Response } from "node-fetch";
|
|
13
9
|
import { Keypair } from "@solana/web3.js";
|
|
14
10
|
import bs58 from "bs58";
|
|
11
|
+
import * as solana from "@solana/web3.js";
|
|
15
12
|
|
|
16
13
|
export const SESSION_TTL: bigint = 60n * 60n * 24n * 30n;
|
|
17
14
|
export const ZERO_DECIMAL = new Decimal(0);
|
|
@@ -33,7 +30,10 @@ export function isRfc3339(s: string): boolean {
|
|
|
33
30
|
return REGEX.test(s);
|
|
34
31
|
}
|
|
35
32
|
|
|
36
|
-
export function assert(
|
|
33
|
+
export function assert(
|
|
34
|
+
predicate: boolean,
|
|
35
|
+
message?: string,
|
|
36
|
+
): asserts predicate {
|
|
37
37
|
if (!predicate) panic(message ?? "Assertion violated");
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
@@ -62,31 +62,6 @@ export async function checkedFetch(
|
|
|
62
62
|
return resp;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
/**
|
|
66
|
-
* Signs an action using the specified secret key and key type.
|
|
67
|
-
* @param action - The action data to be signed.
|
|
68
|
-
* @param sk - Secret key used for signing the action.
|
|
69
|
-
* @param keyType - Type of the key used for signing.
|
|
70
|
-
* @returns A new Uint8Array containing the action followed by its signature.
|
|
71
|
-
*/
|
|
72
|
-
export function signAction(
|
|
73
|
-
action: Uint8Array,
|
|
74
|
-
sk: Uint8Array,
|
|
75
|
-
keyType: KeyType,
|
|
76
|
-
): Uint8Array {
|
|
77
|
-
let sig: Uint8Array;
|
|
78
|
-
if (keyType === KeyType.Ed25519) {
|
|
79
|
-
sig = ed25519.sign(action, sk);
|
|
80
|
-
} else if (keyType === KeyType.Bls12_381) {
|
|
81
|
-
sig = bls.sign(action, sk);
|
|
82
|
-
} else if (keyType === KeyType.Secp256k1) {
|
|
83
|
-
sig = secp.sign(sha256(action), sk).toCompactRawBytes();
|
|
84
|
-
} else {
|
|
85
|
-
throw new Error("Invalid key type");
|
|
86
|
-
}
|
|
87
|
-
return new Uint8Array([...action, ...sig]);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
65
|
/**
|
|
91
66
|
* Constructs wallet signing function, usable with `NordUser` type
|
|
92
67
|
*
|
|
@@ -217,22 +192,6 @@ export function decodeLengthDelimited<T extends Message>(
|
|
|
217
192
|
);
|
|
218
193
|
}
|
|
219
194
|
|
|
220
|
-
export function checkPubKeyLength(keyType: KeyType, len: number): void {
|
|
221
|
-
if (keyType === KeyType.Bls12_381) {
|
|
222
|
-
throw new Error(
|
|
223
|
-
"Cannot create a user using Bls12_381, use Ed25119 or Secp256k1 instead.",
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (len !== 32 && keyType === KeyType.Ed25519) {
|
|
228
|
-
throw new Error("Ed25519 pubkeys must be 32 length.");
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (len !== 33 && keyType === KeyType.Secp256k1) {
|
|
232
|
-
throw new Error("Secp256k1 pubkeys must be 33 length.");
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
195
|
export function decodeHex(value: string): Uint8Array {
|
|
237
196
|
const hex = value.startsWith("0x") ? value.slice(2) : value;
|
|
238
197
|
return Uint8Array.from(Buffer.from(hex, "hex"));
|
|
@@ -267,3 +226,41 @@ export function keypairFromPrivateKey(
|
|
|
267
226
|
}
|
|
268
227
|
return Keypair.fromSecretKey(privateKey);
|
|
269
228
|
}
|
|
229
|
+
|
|
230
|
+
export async function signUserPayload({
|
|
231
|
+
payload,
|
|
232
|
+
user,
|
|
233
|
+
signTransaction,
|
|
234
|
+
}: Readonly<{
|
|
235
|
+
payload: Uint8Array;
|
|
236
|
+
user: solana.PublicKey;
|
|
237
|
+
signTransaction: (tx: solana.Transaction) => Promise<solana.Transaction>;
|
|
238
|
+
}>): Promise<Uint8Array> {
|
|
239
|
+
const tx = new solana.Transaction({
|
|
240
|
+
blockhash: bs58.encode(new Uint8Array(32)),
|
|
241
|
+
lastValidBlockHeight: 0,
|
|
242
|
+
feePayer: user,
|
|
243
|
+
});
|
|
244
|
+
tx.add(
|
|
245
|
+
new solana.TransactionInstruction({
|
|
246
|
+
keys: [],
|
|
247
|
+
programId: user,
|
|
248
|
+
data: Buffer.from(payload),
|
|
249
|
+
}),
|
|
250
|
+
);
|
|
251
|
+
const signedTx = await signTransaction(tx);
|
|
252
|
+
const sig = signedTx.signatures[0];
|
|
253
|
+
assert(
|
|
254
|
+
sig.signature !== null,
|
|
255
|
+
"signature must be non-null; check your signTransaction function",
|
|
256
|
+
);
|
|
257
|
+
assert(
|
|
258
|
+
sig.signature.length === 64, //.
|
|
259
|
+
"signature must be 64 bytes",
|
|
260
|
+
);
|
|
261
|
+
assert(
|
|
262
|
+
sig.publicKey.equals(user),
|
|
263
|
+
`signature is for ${sig.publicKey}, expected ${user}`,
|
|
264
|
+
);
|
|
265
|
+
return sig.signature;
|
|
266
|
+
}
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
SubscriberConfig,
|
|
7
7
|
StreamTrade,
|
|
8
8
|
Trades,
|
|
9
|
-
} from "
|
|
10
|
-
import { MAX_BUFFER_LEN } from "
|
|
9
|
+
} from "../types";
|
|
10
|
+
import { MAX_BUFFER_LEN } from "../utils";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Subscriber class for handling WebSocket subscriptions
|
package/src/websocket/index.ts
CHANGED
|
@@ -1,2 +1,105 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { NordWebSocketClient } from "./NordWebSocketClient";
|
|
2
|
+
import { NordError } from "../error";
|
|
3
|
+
import type { SubscriptionPattern } from "../types";
|
|
4
|
+
import type { NordWebSocketEvents, NordWebSocketClientEvents } from "./events";
|
|
5
|
+
import { Subscriber } from "./Subscriber";
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
NordWebSocketClient,
|
|
9
|
+
NordWebSocketEvents,
|
|
10
|
+
NordWebSocketClientEvents,
|
|
11
|
+
Subscriber,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Initialize a WebSocket client for Nord
|
|
16
|
+
*
|
|
17
|
+
* Connects to the Nord WebSocket endpoint with support for multiple subscription types:
|
|
18
|
+
* - trades@SYMBOL - For trade updates
|
|
19
|
+
* - deltas@SYMBOL - For orderbook delta updates
|
|
20
|
+
* - account@ACCOUNT_ID - For user-specific updates
|
|
21
|
+
*
|
|
22
|
+
* @param webServerUrl - Base URL for the Nord web server
|
|
23
|
+
* @param subscriptions - Array of subscriptions (e.g., ["trades@BTCUSDC", "deltas@BTCUSDC", "account@42"])
|
|
24
|
+
* @returns WebSocket client
|
|
25
|
+
* @throws {NordError} If initialization fails or invalid subscription is provided
|
|
26
|
+
*/
|
|
27
|
+
export function initWebSocketClient(
|
|
28
|
+
webServerUrl: string,
|
|
29
|
+
subscriptions?: SubscriptionPattern[] | "trades" | "delta" | "account",
|
|
30
|
+
): NordWebSocketClient {
|
|
31
|
+
try {
|
|
32
|
+
// Determine URL and subscriptions based on parameters
|
|
33
|
+
let wsUrl = webServerUrl.replace(/^http/, "ws") + `/ws`;
|
|
34
|
+
|
|
35
|
+
// Validate subscriptions parameter
|
|
36
|
+
if (typeof subscriptions === "string") {
|
|
37
|
+
// Legacy mode - handle endpoint string
|
|
38
|
+
if (
|
|
39
|
+
subscriptions === "trades" ||
|
|
40
|
+
subscriptions === "delta" ||
|
|
41
|
+
subscriptions === "account"
|
|
42
|
+
) {
|
|
43
|
+
wsUrl += `/${subscriptions}`;
|
|
44
|
+
} else {
|
|
45
|
+
throw new NordError(
|
|
46
|
+
`Invalid endpoint: ${subscriptions}. Must be "trades", "deltas", or "account".`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
} else if (Array.isArray(subscriptions) && subscriptions.length > 0) {
|
|
50
|
+
// New mode - validate and combine subscriptions in URL
|
|
51
|
+
subscriptions.forEach(validateSubscription);
|
|
52
|
+
wsUrl += `/${subscriptions.join("&")}`;
|
|
53
|
+
} else {
|
|
54
|
+
// Default to trades endpoint if no subscriptions specified
|
|
55
|
+
wsUrl += `/trades`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log(`Initializing WebSocket client with URL: ${wsUrl}`);
|
|
59
|
+
|
|
60
|
+
// Create and connect the WebSocket client
|
|
61
|
+
const ws = new NordWebSocketClient(wsUrl);
|
|
62
|
+
|
|
63
|
+
// Add error handler
|
|
64
|
+
ws.on("error", (error) => {
|
|
65
|
+
console.error("Nord WebSocket error:", error);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Add connected handler for debugging
|
|
69
|
+
ws.on("connected", () => {
|
|
70
|
+
console.log("Nord WebSocket connected successfully");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Connect the WebSocket
|
|
74
|
+
ws.connect();
|
|
75
|
+
return ws;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error("Failed to initialize WebSocket client:", error);
|
|
78
|
+
throw new NordError("Failed to initialize WebSocket client", {
|
|
79
|
+
cause: error,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Validates a subscription string follows the correct format
|
|
86
|
+
*
|
|
87
|
+
* @param subscription - The subscription to validate
|
|
88
|
+
* @throws {NordError} If the subscription format is invalid
|
|
89
|
+
*/
|
|
90
|
+
function validateSubscription(subscription: string): void {
|
|
91
|
+
const [type, param] = subscription.split("@");
|
|
92
|
+
|
|
93
|
+
if (!type || !param || !["trades", "deltas", "account"].includes(type)) {
|
|
94
|
+
throw new NordError(
|
|
95
|
+
`Invalid subscription format: ${subscription}. Expected format: "trades@SYMBOL", "deltas@SYMBOL", or "account@ID"`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Additional validation for account subscriptions
|
|
100
|
+
if (type === "account" && isNaN(Number(param))) {
|
|
101
|
+
throw new NordError(
|
|
102
|
+
`Invalid account ID in subscription: ${subscription}. Account ID must be a number.`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|