@n1xyz/nord-ts 0.0.20 → 0.0.22
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/gen/nord_pb.d.ts +3651 -0
- package/dist/gen/nord_pb.js +892 -0
- package/dist/gen/openapi.d.ts +241 -2
- package/dist/nord/api/actions.d.ts +30 -72
- package/dist/nord/api/actions.js +179 -200
- package/dist/nord/api/core.d.ts +1 -1
- package/dist/nord/api/core.js +1 -13
- package/dist/nord/client/Nord.d.ts +3 -3
- package/dist/nord/client/Nord.js +6 -9
- package/dist/nord/client/NordUser.d.ts +26 -13
- package/dist/nord/client/NordUser.js +13 -10
- package/dist/types.d.ts +13 -11
- package/dist/types.js +29 -4
- package/dist/utils.d.ts +6 -20
- package/dist/utils.js +17 -35
- package/dist/websocket/NordWebSocketClient.d.ts +0 -11
- package/dist/websocket/NordWebSocketClient.js +2 -98
- package/package.json +27 -24
- package/src/gen/nord_pb.ts +4172 -0
- package/src/gen/openapi.ts +241 -2
- package/src/nord/api/actions.ts +249 -370
- package/src/nord/api/core.ts +1 -16
- package/src/nord/client/Nord.ts +9 -13
- package/src/nord/client/NordUser.ts +40 -19
- package/src/types.ts +32 -12
- package/src/utils.ts +24 -43
- package/src/websocket/NordWebSocketClient.ts +2 -121
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Connection, PublicKey, Transaction } from "@solana/web3.js";
|
|
1
|
+
import { Connection, PublicKey, Transaction, SendOptions } from "@solana/web3.js";
|
|
2
2
|
import Decimal from "decimal.js";
|
|
3
|
-
import { FillMode, Side, SPLTokenInfo } from "../../types";
|
|
4
|
-
import * as proto from "../../gen/
|
|
3
|
+
import { FillMode, Side, SPLTokenInfo, QuoteSize } from "../../types";
|
|
4
|
+
import * as proto from "../../gen/nord_pb";
|
|
5
5
|
import { BigIntValue } from "../../utils";
|
|
6
6
|
import { Nord } from "./Nord";
|
|
7
7
|
/**
|
|
@@ -43,8 +43,8 @@ export interface PlaceOrderParams {
|
|
|
43
43
|
size?: Decimal.Value;
|
|
44
44
|
/** Order price */
|
|
45
45
|
price?: Decimal.Value;
|
|
46
|
-
/** Quote size (
|
|
47
|
-
quoteSize?:
|
|
46
|
+
/** Quote size object (requires non-zero price and size) */
|
|
47
|
+
quoteSize?: QuoteSize;
|
|
48
48
|
/** Account ID to place the order from */
|
|
49
49
|
accountId?: number;
|
|
50
50
|
}
|
|
@@ -83,8 +83,8 @@ export interface UserAtomicSubaction {
|
|
|
83
83
|
size?: Decimal.Value;
|
|
84
84
|
/** Order price */
|
|
85
85
|
price?: Decimal.Value;
|
|
86
|
-
/** Quote size (for market
|
|
87
|
-
quoteSize?:
|
|
86
|
+
/** Quote size object (for market-style placement) */
|
|
87
|
+
quoteSize?: QuoteSize;
|
|
88
88
|
/** The client order ID of the order. */
|
|
89
89
|
clientOrderId?: BigIntValue;
|
|
90
90
|
}
|
|
@@ -203,13 +203,15 @@ export declare class NordUser {
|
|
|
203
203
|
* @param amount - Amount to deposit
|
|
204
204
|
* @param tokenId - Token ID
|
|
205
205
|
* @param recipient - Recipient address; defaults to the user's address
|
|
206
|
+
* @param sendOptions - Send options for .sendTransaction
|
|
206
207
|
* @returns Transaction signature
|
|
207
208
|
* @throws {NordError} If required parameters are missing or operation fails
|
|
208
209
|
*/
|
|
209
|
-
deposit({ amount, tokenId, recipient, }: Readonly<{
|
|
210
|
+
deposit({ amount, tokenId, recipient, sendOptions, }: Readonly<{
|
|
210
211
|
amount: number;
|
|
211
212
|
tokenId: number;
|
|
212
213
|
recipient?: PublicKey;
|
|
214
|
+
sendOptions?: SendOptions;
|
|
213
215
|
}>): Promise<string>;
|
|
214
216
|
/**
|
|
215
217
|
* Get a new nonce for actions
|
|
@@ -265,19 +267,27 @@ export declare class NordUser {
|
|
|
265
267
|
* Place an order on the exchange
|
|
266
268
|
*
|
|
267
269
|
* @param params - Order parameters
|
|
268
|
-
* @returns
|
|
270
|
+
* @returns Object containing actionId, orderId (if posted), fills, and clientOrderId
|
|
269
271
|
* @throws {NordError} If the operation fails
|
|
270
272
|
*/
|
|
271
|
-
placeOrder(params: PlaceOrderParams): Promise<
|
|
273
|
+
placeOrder(params: PlaceOrderParams): Promise<{
|
|
274
|
+
actionId: bigint;
|
|
275
|
+
orderId?: bigint;
|
|
276
|
+
fills: proto.Receipt_Trade[];
|
|
277
|
+
}>;
|
|
272
278
|
/**
|
|
273
279
|
* Cancel an order
|
|
274
280
|
*
|
|
275
281
|
* @param orderId - Order ID to cancel
|
|
276
282
|
* @param providedAccountId - Account ID that placed the order
|
|
277
|
-
* @returns
|
|
283
|
+
* @returns Object containing actionId, cancelled orderId, and accountId
|
|
278
284
|
* @throws {NordError} If the operation fails
|
|
279
285
|
*/
|
|
280
|
-
cancelOrder(orderId: BigIntValue, providedAccountId?: number): Promise<
|
|
286
|
+
cancelOrder(orderId: BigIntValue, providedAccountId?: number): Promise<{
|
|
287
|
+
actionId: bigint;
|
|
288
|
+
orderId: bigint;
|
|
289
|
+
accountId: number;
|
|
290
|
+
}>;
|
|
281
291
|
/**
|
|
282
292
|
* Transfer tokens to another account
|
|
283
293
|
*
|
|
@@ -297,7 +307,10 @@ export declare class NordUser {
|
|
|
297
307
|
* @param userActions array of user-friendly subactions
|
|
298
308
|
* @param providedAccountId optional account performing the action (defaults to first account)
|
|
299
309
|
*/
|
|
300
|
-
atomic(userActions: UserAtomicSubaction[], providedAccountId?: number): Promise<
|
|
310
|
+
atomic(userActions: UserAtomicSubaction[], providedAccountId?: number): Promise<{
|
|
311
|
+
actionId: bigint;
|
|
312
|
+
results: proto.Receipt_AtomicSubactionResultKind[];
|
|
313
|
+
}>;
|
|
301
314
|
/**
|
|
302
315
|
* Helper function to retry a promise with exponential backoff
|
|
303
316
|
*
|
|
@@ -242,10 +242,11 @@ class NordUser {
|
|
|
242
242
|
* @param amount - Amount to deposit
|
|
243
243
|
* @param tokenId - Token ID
|
|
244
244
|
* @param recipient - Recipient address; defaults to the user's address
|
|
245
|
+
* @param sendOptions - Send options for .sendTransaction
|
|
245
246
|
* @returns Transaction signature
|
|
246
247
|
* @throws {NordError} If required parameters are missing or operation fails
|
|
247
248
|
*/
|
|
248
|
-
async deposit({ amount, tokenId, recipient, }) {
|
|
249
|
+
async deposit({ amount, tokenId, recipient, sendOptions, }) {
|
|
249
250
|
try {
|
|
250
251
|
// Find the token info
|
|
251
252
|
const tokenInfo = this.splTokenInfos.find((t) => t.tokenId === tokenId);
|
|
@@ -262,14 +263,14 @@ class NordUser {
|
|
|
262
263
|
mint,
|
|
263
264
|
sourceTokenAccount: fromAccount,
|
|
264
265
|
});
|
|
265
|
-
const { blockhash } = await this.connection.getLatestBlockhash(
|
|
266
|
+
const { blockhash } = await this.connection.getLatestBlockhash();
|
|
266
267
|
const tx = new web3_js_1.Transaction();
|
|
267
268
|
tx.add(ix);
|
|
268
269
|
tx.recentBlockhash = blockhash;
|
|
269
270
|
tx.feePayer = payer;
|
|
270
271
|
const signedTx = await this.transactionSignFn(tx);
|
|
271
272
|
signedTx.partialSign(extraSigner);
|
|
272
|
-
const signature = await this.connection.sendRawTransaction(signedTx.serialize());
|
|
273
|
+
const signature = await this.connection.sendRawTransaction(signedTx.serialize(), sendOptions);
|
|
273
274
|
return signature;
|
|
274
275
|
}
|
|
275
276
|
catch (error) {
|
|
@@ -345,10 +346,11 @@ class NordUser {
|
|
|
345
346
|
* @throws {NordError} If the operation fails
|
|
346
347
|
*/
|
|
347
348
|
async refreshSession() {
|
|
348
|
-
|
|
349
|
+
const result = await (0, actions_1.createSession)(this.nord.webServerUrl, this.walletSignFn, await this.nord.getTimestamp(), this.getNonce(), {
|
|
349
350
|
userPubkey: (0, utils_1.optExpect)(this.publicKey.toBytes(), "No user's public key"),
|
|
350
351
|
sessionPubkey: this.sessionPubKey,
|
|
351
352
|
});
|
|
353
|
+
this.sessionId = result.sessionId;
|
|
352
354
|
}
|
|
353
355
|
/**
|
|
354
356
|
* Revoke a session
|
|
@@ -404,7 +406,7 @@ class NordUser {
|
|
|
404
406
|
* Place an order on the exchange
|
|
405
407
|
*
|
|
406
408
|
* @param params - Order parameters
|
|
407
|
-
* @returns
|
|
409
|
+
* @returns Object containing actionId, orderId (if posted), fills, and clientOrderId
|
|
408
410
|
* @throws {NordError} If the operation fails
|
|
409
411
|
*/
|
|
410
412
|
async placeOrder(params) {
|
|
@@ -414,7 +416,7 @@ class NordUser {
|
|
|
414
416
|
if (!market) {
|
|
415
417
|
throw new NordError_1.NordError(`Market with ID ${params.marketId} not found`);
|
|
416
418
|
}
|
|
417
|
-
|
|
419
|
+
const result = await (0, actions_1.placeOrder)(this.nord.webServerUrl, this.sessionSignFn, await this.nord.getTimestamp(), this.getNonce(), {
|
|
418
420
|
sessionId: (0, utils_1.optExpect)(this.sessionId, "No session"),
|
|
419
421
|
senderId: params.accountId,
|
|
420
422
|
sizeDecimals: market.sizeDecimals,
|
|
@@ -427,6 +429,7 @@ class NordUser {
|
|
|
427
429
|
price: params.price,
|
|
428
430
|
quoteSize: params.quoteSize,
|
|
429
431
|
});
|
|
432
|
+
return result;
|
|
430
433
|
}
|
|
431
434
|
catch (error) {
|
|
432
435
|
throw new NordError_1.NordError("Failed to place order", { cause: error });
|
|
@@ -437,18 +440,19 @@ class NordUser {
|
|
|
437
440
|
*
|
|
438
441
|
* @param orderId - Order ID to cancel
|
|
439
442
|
* @param providedAccountId - Account ID that placed the order
|
|
440
|
-
* @returns
|
|
443
|
+
* @returns Object containing actionId, cancelled orderId, and accountId
|
|
441
444
|
* @throws {NordError} If the operation fails
|
|
442
445
|
*/
|
|
443
446
|
async cancelOrder(orderId, providedAccountId) {
|
|
444
447
|
const accountId = providedAccountId != null ? providedAccountId : this.accountIds?.[0];
|
|
445
448
|
try {
|
|
446
449
|
this.checkSessionValidity();
|
|
447
|
-
|
|
450
|
+
const result = await (0, actions_1.cancelOrder)(this.nord.webServerUrl, this.sessionSignFn, await this.nord.getTimestamp(), this.getNonce(), {
|
|
448
451
|
sessionId: (0, utils_1.optExpect)(this.sessionId, "No session"),
|
|
449
452
|
senderId: accountId,
|
|
450
453
|
orderId,
|
|
451
454
|
});
|
|
455
|
+
return result;
|
|
452
456
|
}
|
|
453
457
|
catch (error) {
|
|
454
458
|
throw new NordError_1.NordError(`Failed to cancel order ${orderId}`, {
|
|
@@ -514,8 +518,7 @@ class NordUser {
|
|
|
514
518
|
priceDecimals: market.priceDecimals,
|
|
515
519
|
size: act.size,
|
|
516
520
|
price: act.price,
|
|
517
|
-
|
|
518
|
-
quoteSizePrice: undefined,
|
|
521
|
+
quoteSize: act.quoteSize,
|
|
519
522
|
clientOrderId: act.clientOrderId,
|
|
520
523
|
};
|
|
521
524
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import * as proto from "./gen/
|
|
1
|
+
import * as proto from "./gen/nord_pb";
|
|
2
2
|
import type { components } from "./gen/openapi.ts";
|
|
3
|
+
import Decimal from "decimal.js";
|
|
3
4
|
/**
|
|
4
5
|
* The peak TPS rate is queried over the specified period.
|
|
5
6
|
* The period is specified in units of: {hour, day, week, month, year}.
|
|
@@ -208,19 +209,10 @@ export interface ActionNonceResponse {
|
|
|
208
209
|
* WebSocket message types
|
|
209
210
|
*/
|
|
210
211
|
export declare enum WebSocketMessageType {
|
|
211
|
-
Subscribe = "subscribe",
|
|
212
|
-
Unsubscribe = "unsubscribe",
|
|
213
212
|
TradeUpdate = "trades",
|
|
214
213
|
DeltaUpdate = "delta",
|
|
215
214
|
AccountUpdate = "account"
|
|
216
215
|
}
|
|
217
|
-
/**
|
|
218
|
-
* WebSocket subscription request
|
|
219
|
-
*/
|
|
220
|
-
export interface WebSocketSubscription {
|
|
221
|
-
e: WebSocketMessageType;
|
|
222
|
-
streams: string[];
|
|
223
|
-
}
|
|
224
216
|
/**
|
|
225
217
|
* WebSocket trade update message
|
|
226
218
|
*/
|
|
@@ -251,10 +243,20 @@ export interface WebSocketAccountUpdate {
|
|
|
251
243
|
account: Account;
|
|
252
244
|
timestamp: number;
|
|
253
245
|
}
|
|
254
|
-
export type WebSocketMessage =
|
|
246
|
+
export type WebSocketMessage = WebSocketTradeUpdate | WebSocketDeltaUpdate | WebSocketAccountUpdate;
|
|
255
247
|
export interface SPLTokenInfo {
|
|
256
248
|
mint: string;
|
|
257
249
|
precision: number;
|
|
258
250
|
tokenId: number;
|
|
259
251
|
name: string;
|
|
260
252
|
}
|
|
253
|
+
export declare class QuoteSize {
|
|
254
|
+
price: Decimal;
|
|
255
|
+
size: Decimal;
|
|
256
|
+
constructor(quotePrice: Decimal.Value, quoteSize: Decimal.Value);
|
|
257
|
+
value(): Decimal;
|
|
258
|
+
toScaledU64(marketPriceDecimals: number, marketSizeDecimals: number): {
|
|
259
|
+
price: bigint;
|
|
260
|
+
size: bigint;
|
|
261
|
+
};
|
|
262
|
+
}
|
package/dist/types.js
CHANGED
|
@@ -32,10 +32,15 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
35
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.WebSocketMessageType = exports.FillMode = exports.Side = exports.KeyType = exports.PeakTpsPeriodUnit = void 0;
|
|
39
|
+
exports.QuoteSize = exports.WebSocketMessageType = exports.FillMode = exports.Side = exports.KeyType = exports.PeakTpsPeriodUnit = void 0;
|
|
37
40
|
exports.fillModeToProtoFillMode = fillModeToProtoFillMode;
|
|
38
|
-
const proto = __importStar(require("./gen/
|
|
41
|
+
const proto = __importStar(require("./gen/nord_pb"));
|
|
42
|
+
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
43
|
+
const utils_1 = require("./utils");
|
|
39
44
|
/**
|
|
40
45
|
* The peak TPS rate is queried over the specified period.
|
|
41
46
|
* The period is specified in units of: {hour, day, week, month, year}.
|
|
@@ -95,9 +100,29 @@ function fillModeToProtoFillMode(x) {
|
|
|
95
100
|
*/
|
|
96
101
|
var WebSocketMessageType;
|
|
97
102
|
(function (WebSocketMessageType) {
|
|
98
|
-
WebSocketMessageType["Subscribe"] = "subscribe";
|
|
99
|
-
WebSocketMessageType["Unsubscribe"] = "unsubscribe";
|
|
100
103
|
WebSocketMessageType["TradeUpdate"] = "trades";
|
|
101
104
|
WebSocketMessageType["DeltaUpdate"] = "delta";
|
|
102
105
|
WebSocketMessageType["AccountUpdate"] = "account";
|
|
103
106
|
})(WebSocketMessageType || (exports.WebSocketMessageType = WebSocketMessageType = {}));
|
|
107
|
+
// Positive decimal price and size.
|
|
108
|
+
class QuoteSize {
|
|
109
|
+
constructor(quotePrice, quoteSize) {
|
|
110
|
+
const p = new decimal_js_1.default(quotePrice);
|
|
111
|
+
const s = new decimal_js_1.default(quoteSize);
|
|
112
|
+
if (p.isZero() || s.isZero()) {
|
|
113
|
+
throw new Error("quotePrice and quoteSize must be non-zero");
|
|
114
|
+
}
|
|
115
|
+
this.price = p;
|
|
116
|
+
this.size = s;
|
|
117
|
+
}
|
|
118
|
+
value() {
|
|
119
|
+
return this.price.mul(this.size);
|
|
120
|
+
}
|
|
121
|
+
toScaledU64(marketPriceDecimals, marketSizeDecimals) {
|
|
122
|
+
return {
|
|
123
|
+
price: (0, utils_1.toScaledU64)(this.price, marketPriceDecimals),
|
|
124
|
+
size: (0, utils_1.toScaledU64)(this.size, marketSizeDecimals),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.QuoteSize = QuoteSize;
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Decimal } from "decimal.js";
|
|
2
2
|
import { KeyType, type Market, type Token } from "./types";
|
|
3
|
-
import
|
|
3
|
+
import { type Message } from "@bufbuild/protobuf";
|
|
4
|
+
import type { GenMessage } from "@bufbuild/protobuf/codegenv2";
|
|
4
5
|
import { ethers } from "ethers";
|
|
5
6
|
import { RequestInfo, RequestInit, Response } from "node-fetch";
|
|
6
7
|
import { Keypair } from "@solana/web3.js";
|
|
@@ -68,30 +69,15 @@ export declare const toScaledU64: (x: Decimal.Value, decimals: number) => bigint
|
|
|
68
69
|
* @returns Rescaled unsigned integer
|
|
69
70
|
*/
|
|
70
71
|
export declare const toScaledU128: (x: Decimal.Value, decimals: number) => bigint;
|
|
71
|
-
/**
|
|
72
|
-
* Encodes any protobuf message into a length-delimited format,
|
|
73
|
-
* i.e. prefixed with its length encoded as varint
|
|
74
|
-
* @param message message object
|
|
75
|
-
* @param coder associated coder object which implements `MessageFns` interface
|
|
76
|
-
* @returns Encoded message as Uint8Array, prefixed with its length
|
|
77
|
-
*/
|
|
78
|
-
export declare function encodeLengthDelimited<T, M extends proto.MessageFns<T>>(message: T, coder: M): Uint8Array;
|
|
79
72
|
/**
|
|
80
73
|
* Decodes any protobuf message from a length-delimited format,
|
|
81
74
|
* i.e. prefixed with its length encoded as varint
|
|
82
75
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* ```
|
|
87
|
-
* const foo: proto.Bar = decodeLengthDelimited(bytes, proto.Bar);
|
|
88
|
-
* ```
|
|
89
|
-
*
|
|
90
|
-
* @param bytes Byte array with encoded message
|
|
91
|
-
* @param coder associated coder object which implements `MessageFns` interface
|
|
92
|
-
* @returns Decoded Action as Uint8Array.
|
|
76
|
+
* @param bytes Byte array with encoded message
|
|
77
|
+
* @param schema Message schema for decoding
|
|
78
|
+
* @returns Decoded message
|
|
93
79
|
*/
|
|
94
|
-
export declare function decodeLengthDelimited<T
|
|
80
|
+
export declare function decodeLengthDelimited<T extends Message>(bytes: Uint8Array, schema: GenMessage<T>): T;
|
|
95
81
|
export declare function checkPubKeyLength(keyType: KeyType, len: number): void;
|
|
96
82
|
export declare function findMarket(markets: Market[], marketId: number): Market;
|
|
97
83
|
export declare function findToken(tokens: Token[], tokenId: number): Token;
|
package/dist/utils.js
CHANGED
|
@@ -11,7 +11,6 @@ exports.optExpect = optExpect;
|
|
|
11
11
|
exports.checkedFetch = checkedFetch;
|
|
12
12
|
exports.signAction = signAction;
|
|
13
13
|
exports.makeWalletSignFn = makeWalletSignFn;
|
|
14
|
-
exports.encodeLengthDelimited = encodeLengthDelimited;
|
|
15
14
|
exports.decodeLengthDelimited = decodeLengthDelimited;
|
|
16
15
|
exports.checkPubKeyLength = checkPubKeyLength;
|
|
17
16
|
exports.findMarket = findMarket;
|
|
@@ -24,6 +23,7 @@ const secp256k1_1 = require("@noble/curves/secp256k1");
|
|
|
24
23
|
const sha256_1 = require("@noble/hashes/sha256");
|
|
25
24
|
const types_1 = require("./types");
|
|
26
25
|
const wire_1 = require("@bufbuild/protobuf/wire");
|
|
26
|
+
const protobuf_1 = require("@bufbuild/protobuf");
|
|
27
27
|
const ethers_1 = require("ethers");
|
|
28
28
|
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
29
29
|
const web3_js_1 = require("@solana/web3.js");
|
|
@@ -101,6 +101,7 @@ function makeWalletSignFn(walletKey) {
|
|
|
101
101
|
const signingKey = new ethers_1.ethers.SigningKey(walletKey);
|
|
102
102
|
return async (message) => signingKey.sign(ethers_1.ethers.hashMessage(message)).serialized;
|
|
103
103
|
}
|
|
104
|
+
// Returned numbers do fit into specified bits range, or error is thrown.
|
|
104
105
|
function makeToScaledBigUint(params) {
|
|
105
106
|
const Dec = decimal_js_1.Decimal.clone({
|
|
106
107
|
precision: params.precision,
|
|
@@ -159,47 +160,28 @@ exports.toScaledU128 = makeToScaledBigUint({
|
|
|
159
160
|
precision: 40,
|
|
160
161
|
exponent: 56,
|
|
161
162
|
});
|
|
162
|
-
/**
|
|
163
|
-
* Encodes any protobuf message into a length-delimited format,
|
|
164
|
-
* i.e. prefixed with its length encoded as varint
|
|
165
|
-
* @param message message object
|
|
166
|
-
* @param coder associated coder object which implements `MessageFns` interface
|
|
167
|
-
* @returns Encoded message as Uint8Array, prefixed with its length
|
|
168
|
-
*/
|
|
169
|
-
function encodeLengthDelimited(message, coder) {
|
|
170
|
-
const encoded = coder.encode(message).finish();
|
|
171
|
-
if (encoded.byteLength > MAX_PAYLOAD_SIZE) {
|
|
172
|
-
throw new Error(`Encoded message size (${encoded.byteLength} bytes) is greater than max payload size (${MAX_PAYLOAD_SIZE} bytes).`);
|
|
173
|
-
}
|
|
174
|
-
const encodedLength = new wire_1.BinaryWriter().uint32(encoded.byteLength).finish();
|
|
175
|
-
return new Uint8Array([...encodedLength, ...encoded]);
|
|
176
|
-
}
|
|
177
163
|
/**
|
|
178
164
|
* Decodes any protobuf message from a length-delimited format,
|
|
179
165
|
* i.e. prefixed with its length encoded as varint
|
|
180
166
|
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
* ```
|
|
185
|
-
* const foo: proto.Bar = decodeLengthDelimited(bytes, proto.Bar);
|
|
186
|
-
* ```
|
|
187
|
-
*
|
|
188
|
-
* @param bytes Byte array with encoded message
|
|
189
|
-
* @param coder associated coder object which implements `MessageFns` interface
|
|
190
|
-
* @returns Decoded Action as Uint8Array.
|
|
167
|
+
* @param bytes Byte array with encoded message
|
|
168
|
+
* @param schema Message schema for decoding
|
|
169
|
+
* @returns Decoded message
|
|
191
170
|
*/
|
|
192
|
-
function decodeLengthDelimited(bytes,
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
171
|
+
function decodeLengthDelimited(bytes, schema) {
|
|
172
|
+
// use sizeDelimitedPeek to extract the message length and offset
|
|
173
|
+
const peekResult = (0, wire_1.sizeDelimitedPeek)(bytes);
|
|
174
|
+
if (peekResult.size === null || peekResult.offset === null) {
|
|
175
|
+
throw new Error("Failed to parse size-delimited message");
|
|
176
|
+
}
|
|
177
|
+
if (peekResult.size > MAX_PAYLOAD_SIZE) {
|
|
178
|
+
throw new Error(`Encoded message size (${peekResult.size} bytes) is greater than max payload size (${MAX_PAYLOAD_SIZE} bytes).`);
|
|
198
179
|
}
|
|
199
|
-
if (
|
|
200
|
-
throw new Error(`Encoded message size (${
|
|
180
|
+
if (peekResult.offset + peekResult.size > bytes.length) {
|
|
181
|
+
throw new Error(`Encoded message size (${peekResult.size} bytes) is greater than remaining buffer size (${bytes.length - peekResult.offset} bytes).`);
|
|
201
182
|
}
|
|
202
|
-
|
|
183
|
+
// decode the message using the offset and size from peek
|
|
184
|
+
return (0, protobuf_1.fromBinary)(schema, bytes.slice(peekResult.offset, peekResult.offset + peekResult.size));
|
|
203
185
|
}
|
|
204
186
|
function checkPubKeyLength(keyType, len) {
|
|
205
187
|
if (keyType === types_1.KeyType.Bls12_381) {
|
|
@@ -12,7 +12,6 @@ import { NordWebSocketClientEvents } from "./events";
|
|
|
12
12
|
export declare class NordWebSocketClient extends EventEmitter implements NordWebSocketClientEvents {
|
|
13
13
|
private ws;
|
|
14
14
|
private url;
|
|
15
|
-
private subscriptions;
|
|
16
15
|
private reconnectAttempts;
|
|
17
16
|
private maxReconnectAttempts;
|
|
18
17
|
private reconnectDelay;
|
|
@@ -42,16 +41,6 @@ export declare class NordWebSocketClient extends EventEmitter implements NordWeb
|
|
|
42
41
|
* Connect to the Nord WebSocket server
|
|
43
42
|
*/
|
|
44
43
|
connect(): void;
|
|
45
|
-
/**
|
|
46
|
-
* Subscribe to one or more streams
|
|
47
|
-
* @param streams Array of streams to subscribe to (e.g. ["trades@BTCUSDC", "deltas@BTCUSDC"])
|
|
48
|
-
*/
|
|
49
|
-
subscribe(streams: string[]): void;
|
|
50
|
-
/**
|
|
51
|
-
* Unsubscribe from one or more streams
|
|
52
|
-
* @param streams Array of streams to unsubscribe from
|
|
53
|
-
*/
|
|
54
|
-
unsubscribe(streams: string[]): void;
|
|
55
44
|
/**
|
|
56
45
|
* Close the WebSocket connection
|
|
57
46
|
*/
|
|
@@ -6,10 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.NordWebSocketClient = void 0;
|
|
7
7
|
const events_1 = require("events");
|
|
8
8
|
const ws_1 = __importDefault(require("ws"));
|
|
9
|
-
const types_1 = require("../types");
|
|
10
9
|
const VALID_STREAM_TYPES = ["trades", "delta", "account"];
|
|
11
|
-
// Constants for WebSocket readyState
|
|
12
|
-
const WS_OPEN = 1;
|
|
13
10
|
/**
|
|
14
11
|
* WebSocket client for Nord exchange
|
|
15
12
|
*
|
|
@@ -27,7 +24,6 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
27
24
|
constructor(url) {
|
|
28
25
|
super();
|
|
29
26
|
this.ws = null;
|
|
30
|
-
this.subscriptions = new Set();
|
|
31
27
|
this.reconnectAttempts = 0;
|
|
32
28
|
this.maxReconnectAttempts = 5;
|
|
33
29
|
this.reconnectDelay = 1000;
|
|
@@ -124,10 +120,6 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
124
120
|
this.emit("connected");
|
|
125
121
|
this.reconnectAttempts = 0;
|
|
126
122
|
this.reconnectDelay = 1000;
|
|
127
|
-
// Resubscribe to previous subscriptions
|
|
128
|
-
if (this.subscriptions.size > 0) {
|
|
129
|
-
this.subscribe([...this.subscriptions]);
|
|
130
|
-
}
|
|
131
123
|
};
|
|
132
124
|
this.ws.onmessage = (event) => {
|
|
133
125
|
try {
|
|
@@ -138,16 +130,12 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
138
130
|
this.emit("error", new Error(`Failed to parse message: ${error instanceof Error ? error.message : String(error)}`));
|
|
139
131
|
}
|
|
140
132
|
};
|
|
141
|
-
this.ws.onclose = (
|
|
142
|
-
const reason = event && event.reason ? ` Reason: ${event.reason}` : "";
|
|
143
|
-
const code = event && event.code ? ` Code: ${event.code}` : "";
|
|
133
|
+
this.ws.onclose = (_event) => {
|
|
144
134
|
this.emit("disconnected");
|
|
145
|
-
console.log(`WebSocket closed.${code}${reason}`);
|
|
146
135
|
this.reconnect();
|
|
147
136
|
};
|
|
148
137
|
this.ws.onerror = (event) => {
|
|
149
138
|
const errorMsg = `WebSocket error: ${event && event.type ? event.type : "unknown"}`;
|
|
150
|
-
console.error(errorMsg, event);
|
|
151
139
|
this.emit("error", new Error(errorMsg));
|
|
152
140
|
};
|
|
153
141
|
}
|
|
@@ -160,10 +148,6 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
160
148
|
this.reconnectAttempts = 0;
|
|
161
149
|
this.reconnectDelay = 1000;
|
|
162
150
|
this.setupHeartbeat();
|
|
163
|
-
// Resubscribe to previous subscriptions
|
|
164
|
-
if (this.subscriptions.size > 0) {
|
|
165
|
-
this.subscribe([...this.subscriptions]);
|
|
166
|
-
}
|
|
167
151
|
});
|
|
168
152
|
nodeWs.on("message", (data) => {
|
|
169
153
|
try {
|
|
@@ -174,9 +158,8 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
174
158
|
this.emit("error", new Error(`Failed to parse message: ${error instanceof Error ? error.message : String(error)}`));
|
|
175
159
|
}
|
|
176
160
|
});
|
|
177
|
-
nodeWs.on("close", (
|
|
161
|
+
nodeWs.on("close", (_code, _reason) => {
|
|
178
162
|
this.emit("disconnected");
|
|
179
|
-
console.log(`WebSocket closed. Code: ${code} Reason: ${reason}`);
|
|
180
163
|
if (this.pingInterval) {
|
|
181
164
|
clearInterval(this.pingInterval);
|
|
182
165
|
}
|
|
@@ -186,7 +169,6 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
186
169
|
this.reconnect();
|
|
187
170
|
});
|
|
188
171
|
nodeWs.on("error", (error) => {
|
|
189
|
-
console.error("WebSocket error:", error);
|
|
190
172
|
this.emit("error", error);
|
|
191
173
|
});
|
|
192
174
|
nodeWs.on("pong", () => {
|
|
@@ -198,86 +180,9 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
198
180
|
}
|
|
199
181
|
catch (error) {
|
|
200
182
|
const errorMsg = `Failed to initialize WebSocket: ${error instanceof Error ? error.message : String(error)}`;
|
|
201
|
-
console.error(errorMsg);
|
|
202
183
|
this.emit("error", new Error(errorMsg));
|
|
203
184
|
}
|
|
204
185
|
}
|
|
205
|
-
/**
|
|
206
|
-
* Subscribe to one or more streams
|
|
207
|
-
* @param streams Array of streams to subscribe to (e.g. ["trades@BTCUSDC", "deltas@BTCUSDC"])
|
|
208
|
-
*/
|
|
209
|
-
subscribe(streams) {
|
|
210
|
-
// Validate all streams first
|
|
211
|
-
try {
|
|
212
|
-
streams.forEach((stream) => this.validateStream(stream));
|
|
213
|
-
}
|
|
214
|
-
catch (error) {
|
|
215
|
-
this.emit("error", error instanceof Error ? error : new Error(String(error)));
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
if (!this.ws ||
|
|
219
|
-
(this.isBrowser
|
|
220
|
-
? this.ws.readyState !== WS_OPEN
|
|
221
|
-
: this.ws.readyState !== ws_1.default.OPEN)) {
|
|
222
|
-
streams.forEach((stream) => this.subscriptions.add(stream));
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const message = {
|
|
226
|
-
e: types_1.WebSocketMessageType.Subscribe,
|
|
227
|
-
streams,
|
|
228
|
-
};
|
|
229
|
-
try {
|
|
230
|
-
const messageStr = JSON.stringify(message);
|
|
231
|
-
if (this.isBrowser) {
|
|
232
|
-
this.ws.send(messageStr);
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
this.ws.send(messageStr);
|
|
236
|
-
}
|
|
237
|
-
streams.forEach((stream) => this.subscriptions.add(stream));
|
|
238
|
-
}
|
|
239
|
-
catch (error) {
|
|
240
|
-
this.emit("error", error instanceof Error ? error : new Error(String(error)));
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Unsubscribe from one or more streams
|
|
245
|
-
* @param streams Array of streams to unsubscribe from
|
|
246
|
-
*/
|
|
247
|
-
unsubscribe(streams) {
|
|
248
|
-
// Validate all streams first
|
|
249
|
-
try {
|
|
250
|
-
streams.forEach((stream) => this.validateStream(stream));
|
|
251
|
-
}
|
|
252
|
-
catch (error) {
|
|
253
|
-
this.emit("error", error instanceof Error ? error : new Error(String(error)));
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
if (!this.ws ||
|
|
257
|
-
(this.isBrowser
|
|
258
|
-
? this.ws.readyState !== WS_OPEN
|
|
259
|
-
: this.ws.readyState !== ws_1.default.OPEN)) {
|
|
260
|
-
streams.forEach((stream) => this.subscriptions.delete(stream));
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
const message = {
|
|
264
|
-
e: types_1.WebSocketMessageType.Unsubscribe,
|
|
265
|
-
streams,
|
|
266
|
-
};
|
|
267
|
-
try {
|
|
268
|
-
const messageStr = JSON.stringify(message);
|
|
269
|
-
if (this.isBrowser) {
|
|
270
|
-
this.ws.send(messageStr);
|
|
271
|
-
}
|
|
272
|
-
else {
|
|
273
|
-
this.ws.send(messageStr);
|
|
274
|
-
}
|
|
275
|
-
streams.forEach((stream) => this.subscriptions.delete(stream));
|
|
276
|
-
}
|
|
277
|
-
catch (error) {
|
|
278
|
-
this.emit("error", error instanceof Error ? error : new Error(String(error)));
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
186
|
/**
|
|
282
187
|
* Close the WebSocket connection
|
|
283
188
|
*/
|
|
@@ -299,7 +204,6 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
299
204
|
clearTimeout(this.pingTimeout);
|
|
300
205
|
this.pingTimeout = null;
|
|
301
206
|
}
|
|
302
|
-
this.subscriptions.clear();
|
|
303
207
|
}
|
|
304
208
|
/**
|
|
305
209
|
* Handle incoming WebSocket messages
|