@n1xyz/nord-ts 0.3.2 → 0.3.4
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.js +184 -0
- package/dist/client/Nord.d.ts +9 -15
- package/dist/client/Nord.js +759 -0
- package/dist/client/NordAdmin.js +362 -0
- package/dist/client/NordUser.d.ts +3 -1
- package/dist/client/NordUser.js +752 -0
- package/dist/const.js +27 -0
- package/dist/error.js +51 -0
- package/dist/gen/nord_pb.d.ts +132 -114
- package/dist/gen/nord_pb.js +1068 -0
- package/dist/gen/openapi.d.ts +345 -72
- package/dist/gen/openapi.js +5 -0
- package/dist/index.browser.js +61342 -80207
- package/dist/index.common.js +59722 -87597
- package/dist/index.js +10 -0
- 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 +15 -6
- package/dist/types.js +92 -0
- package/dist/utils.js +193 -0
- package/dist/websocket/NordWebSocketClient.d.ts +1 -0
- package/dist/websocket/NordWebSocketClient.js +242 -0
- package/dist/websocket/Subscriber.d.ts +7 -1
- package/dist/websocket/Subscriber.js +24 -0
- package/dist/websocket/events.d.ts +2 -1
- package/dist/websocket/events.js +1 -0
- package/dist/websocket/index.d.ts +1 -1
- package/dist/websocket/index.js +80 -0
- package/package.json +2 -2
package/dist/actions.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import * as proto from "./gen/nord_pb";
|
|
2
|
+
import { create } from "@bufbuild/protobuf";
|
|
3
|
+
import { fillModeToProtoFillMode, Side } from "./types";
|
|
4
|
+
import { assert, decodeLengthDelimited, SESSION_TTL, toScaledU64, signUserPayload, } from "./utils";
|
|
5
|
+
import { sizeDelimitedEncode } from "@bufbuild/protobuf/wire";
|
|
6
|
+
import { NordError } from "./error";
|
|
7
|
+
export function formatReceiptError(receipt) {
|
|
8
|
+
if (receipt.kind?.case === "err") {
|
|
9
|
+
const err = receipt.kind.value;
|
|
10
|
+
return proto.Error[err] ?? err.toString();
|
|
11
|
+
}
|
|
12
|
+
return receipt.kind?.case ?? "unknown";
|
|
13
|
+
}
|
|
14
|
+
export function expectReceiptKind(receipt, expected, action) {
|
|
15
|
+
if (receipt.kind?.case !== expected) {
|
|
16
|
+
const label = formatReceiptError(receipt);
|
|
17
|
+
throw new NordError(`Failed to ${action}: ${label}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async function sessionSign(signFn, message) {
|
|
21
|
+
const signature = await signFn(message);
|
|
22
|
+
return new Uint8Array([...message, ...signature]);
|
|
23
|
+
}
|
|
24
|
+
// Helper to create an action with common fields
|
|
25
|
+
export function createAction(currentTimestamp, nonce, kind) {
|
|
26
|
+
return create(proto.ActionSchema, {
|
|
27
|
+
currentTimestamp,
|
|
28
|
+
nonce,
|
|
29
|
+
kind,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export async function sendAction(client, makeSignedMessage, action) {
|
|
33
|
+
const body = await prepareAction(action, makeSignedMessage);
|
|
34
|
+
const response = await client.POST("/action", {
|
|
35
|
+
params: {
|
|
36
|
+
header: {
|
|
37
|
+
"content-type": "application/octet-stream",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
body: body,
|
|
41
|
+
// NOTE: openapi-fetch ignores headers and types/const headers in schema, and always assume all things are JSON
|
|
42
|
+
// to handle multi type bodies, need these overrides and later adhoc parsing
|
|
43
|
+
bodySerializer: (body) => body,
|
|
44
|
+
parseAs: "stream",
|
|
45
|
+
});
|
|
46
|
+
if (response.error) {
|
|
47
|
+
throw new Error(`Failed to ${action.kind.case}, HTTP status ${JSON.stringify(response.error)}`);
|
|
48
|
+
}
|
|
49
|
+
const rawResp = new Uint8Array(await response.response.arrayBuffer());
|
|
50
|
+
const resp = decodeLengthDelimited(rawResp, proto.ReceiptSchema);
|
|
51
|
+
if (resp.kind?.case === "err") {
|
|
52
|
+
throw new Error(`Could not execute ${action.kind.case}, reason: ${proto.Error[resp.kind.value]}`);
|
|
53
|
+
}
|
|
54
|
+
return resp;
|
|
55
|
+
}
|
|
56
|
+
// Given action and signature function, prepare the signed message to send to server as `body`.
|
|
57
|
+
// `makeSignedMessage` must include the original message and signature.
|
|
58
|
+
export async function prepareAction(action, makeSignedMessage) {
|
|
59
|
+
const encoded = sizeDelimitedEncode(proto.ActionSchema, action);
|
|
60
|
+
// NOTE(agent): keep in sync with MAX_ENCODED_ACTION_SIZE in Rust code
|
|
61
|
+
const MAX_ENCODED_ACTION_SIZE = 1024;
|
|
62
|
+
if (encoded.byteLength > MAX_ENCODED_ACTION_SIZE) {
|
|
63
|
+
console.warn("Encoded message:", encoded);
|
|
64
|
+
throw new Error(`Encoded message size (${encoded.byteLength} bytes) is greater than max payload size (${MAX_ENCODED_ACTION_SIZE} bytes).`);
|
|
65
|
+
}
|
|
66
|
+
const body = await makeSignedMessage(encoded);
|
|
67
|
+
if (body.byteLength > MAX_ENCODED_ACTION_SIZE) {
|
|
68
|
+
console.warn("Encoded length:", encoded.byteLength);
|
|
69
|
+
throw new Error(`Signed message size (${body.byteLength} bytes) is greater than max payload size (${MAX_ENCODED_ACTION_SIZE} bytes).`);
|
|
70
|
+
}
|
|
71
|
+
return body;
|
|
72
|
+
}
|
|
73
|
+
export async function createSession(client, signMessage, currentTimestamp, nonce, params) {
|
|
74
|
+
let expiry = 0n;
|
|
75
|
+
if (params.expiryTimestamp !== undefined) {
|
|
76
|
+
expiry = params.expiryTimestamp;
|
|
77
|
+
assert(expiry > currentTimestamp, "Cannot set expiry timestamp in the past");
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
expiry = currentTimestamp + SESSION_TTL;
|
|
81
|
+
}
|
|
82
|
+
const action = createAction(currentTimestamp, nonce, {
|
|
83
|
+
case: "createSession",
|
|
84
|
+
value: create(proto.Action_CreateSessionSchema, {
|
|
85
|
+
userPubkey: params.userPubkey.toBytes(),
|
|
86
|
+
blstPubkey: params.sessionPubkey.toBytes(),
|
|
87
|
+
expiryTimestamp: expiry,
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
const resp = await sendAction(client, async (payload) => {
|
|
91
|
+
return new Uint8Array([
|
|
92
|
+
...payload,
|
|
93
|
+
...(await signUserPayload({
|
|
94
|
+
payload,
|
|
95
|
+
signMessage,
|
|
96
|
+
})),
|
|
97
|
+
]);
|
|
98
|
+
}, action);
|
|
99
|
+
if (resp.kind?.case === "createSessionResult") {
|
|
100
|
+
return {
|
|
101
|
+
actionId: resp.actionId,
|
|
102
|
+
sessionId: resp.kind.value.sessionId,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
throw new Error(`Unexpected receipt kind ${resp.kind?.case}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export async function revokeSession(client, signMessage, currentTimestamp, nonce, params) {
|
|
110
|
+
const action = createAction(currentTimestamp, nonce, {
|
|
111
|
+
case: "revokeSession",
|
|
112
|
+
value: create(proto.Action_RevokeSessionSchema, {
|
|
113
|
+
sessionId: BigInt(params.sessionId),
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
const resp = await sendAction(client, async (payload) => {
|
|
117
|
+
return new Uint8Array([
|
|
118
|
+
...payload,
|
|
119
|
+
...(await signUserPayload({
|
|
120
|
+
payload,
|
|
121
|
+
signMessage,
|
|
122
|
+
})),
|
|
123
|
+
]);
|
|
124
|
+
}, action);
|
|
125
|
+
return { actionId: resp.actionId };
|
|
126
|
+
}
|
|
127
|
+
export async function atomic(client, signFn, currentTimestamp, nonce, params) {
|
|
128
|
+
assert(params.actions.length > 0 && params.actions.length <= 4, "Atomic action must contain between 1 and 4 sub-actions");
|
|
129
|
+
const subactions = params.actions.map((a) => {
|
|
130
|
+
if (a.kind === "place") {
|
|
131
|
+
const price = toScaledU64(a.price ?? 0, a.priceDecimals);
|
|
132
|
+
const size = toScaledU64(a.size ?? 0, a.sizeDecimals);
|
|
133
|
+
const scaledQuote = a.quoteSize
|
|
134
|
+
? a.quoteSize.toWire(a.priceDecimals, a.sizeDecimals)
|
|
135
|
+
: undefined;
|
|
136
|
+
// Require at least one limit to be set (non-zero size, non-zero price, or quoteSize)
|
|
137
|
+
assert(price > 0n || size > 0n || scaledQuote !== undefined, "OrderLimit must include at least one of: size, price, or quoteSize");
|
|
138
|
+
const tradeOrPlace = create(proto.TradeOrPlaceSchema, {
|
|
139
|
+
marketId: a.marketId,
|
|
140
|
+
orderType: create(proto.OrderTypeSchema, {
|
|
141
|
+
side: a.side === Side.Bid ? proto.Side.BID : proto.Side.ASK,
|
|
142
|
+
fillMode: fillModeToProtoFillMode(a.fillMode),
|
|
143
|
+
isReduceOnly: a.isReduceOnly,
|
|
144
|
+
}),
|
|
145
|
+
limit: create(proto.OrderLimitSchema, {
|
|
146
|
+
price,
|
|
147
|
+
size,
|
|
148
|
+
quoteSize: scaledQuote === undefined
|
|
149
|
+
? undefined
|
|
150
|
+
: create(proto.QuoteSizeSchema, {
|
|
151
|
+
size: scaledQuote.size,
|
|
152
|
+
price: scaledQuote.price,
|
|
153
|
+
}),
|
|
154
|
+
}),
|
|
155
|
+
clientOrderId: a.clientOrderId === undefined ? undefined : BigInt(a.clientOrderId),
|
|
156
|
+
});
|
|
157
|
+
return create(proto.AtomicSubactionKindSchema, {
|
|
158
|
+
inner: { case: "tradeOrPlace", value: tradeOrPlace },
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return create(proto.AtomicSubactionKindSchema, {
|
|
162
|
+
inner: {
|
|
163
|
+
case: "cancelOrder",
|
|
164
|
+
value: create(proto.CancelOrderSchema, { orderId: BigInt(a.orderId) }),
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
const action = createAction(currentTimestamp, nonce, {
|
|
169
|
+
case: "atomic",
|
|
170
|
+
value: create(proto.AtomicSchema, {
|
|
171
|
+
sessionId: BigInt(params.sessionId),
|
|
172
|
+
accountId: params.accountId, // optional
|
|
173
|
+
actions: subactions,
|
|
174
|
+
}),
|
|
175
|
+
});
|
|
176
|
+
const resp = await sendAction(client, (m) => sessionSign(signFn, m), action);
|
|
177
|
+
if (resp.kind?.case === "atomic") {
|
|
178
|
+
return {
|
|
179
|
+
actionId: resp.actionId,
|
|
180
|
+
results: resp.kind.value.results,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
throw new Error(`Unexpected receipt kind ${resp.kind?.case}`);
|
|
184
|
+
}
|
package/dist/client/Nord.d.ts
CHANGED
|
@@ -3,9 +3,9 @@ import { Connection, PublicKey } from "@solana/web3.js";
|
|
|
3
3
|
import { EventEmitter } from "events";
|
|
4
4
|
import { Client } from "openapi-fetch";
|
|
5
5
|
import type { paths } from "../gen/openapi.ts";
|
|
6
|
-
import { Account, AccountPnlInfoPage, PagedQuery, ActionResponse, MarketsInfo, Market, MarketStats, NordConfig, OrderbookQuery, OrderbookResponse, FeeTierConfig, Token, TradesResponse, User, AccountTriggerInfo, TriggerHistoryPage, WithdrawalHistoryPage, FeeTierId, AccountFeeTierPage, PageResultStringOrderInfo, PageResultStringTrade, OrderInfoFromApi, TokenStats, FillRole, AdminInfo, AccountVolumeInfo, GetAccountVolumeQuery,
|
|
6
|
+
import { Account, AccountPnlInfoPage, PagedQuery, ActionResponse, MarketsInfo, Market, MarketStats, NordConfig, OrderbookQuery, OrderbookResponse, FeeTierConfig, Token, TradesResponse, User, AccountTriggerInfo, TriggerHistoryPage, WithdrawalHistoryPage, FeeTierId, AccountFeeTierPage, PageResultStringOrderInfo, PageResultStringTrade, OrderInfoFromApi, TokenStats, FillRole, AdminInfo, AccountVolumeInfo, GetAccountVolumeQuery, CandleResolution } from "../types";
|
|
7
7
|
import { NordWebSocketClient } from "../websocket/index";
|
|
8
|
-
import { OrderbookSubscription, TradeSubscription } from "../websocket/Subscriber";
|
|
8
|
+
import { OrderbookSubscription, TradeSubscription, CandleSubscription } from "../websocket/Subscriber";
|
|
9
9
|
/**
|
|
10
10
|
* User subscription interface
|
|
11
11
|
*/
|
|
@@ -45,6 +45,7 @@ export declare class Nord {
|
|
|
45
45
|
* @param trades - Market symbols to subscribe to for trade updates
|
|
46
46
|
* @param deltas - Market symbols to subscribe to for orderbook delta updates
|
|
47
47
|
* @param accounts - Account IDs to subscribe to for account updates
|
|
48
|
+
* @param candles - Candle subscriptions with symbol and resolution
|
|
48
49
|
* @returns A new WebSocket client with the requested subscriptions
|
|
49
50
|
* @throws {NordError} If invalid subscription options are provided
|
|
50
51
|
*
|
|
@@ -62,10 +63,14 @@ export declare class Nord {
|
|
|
62
63
|
* trades: ["BTCUSDC", "ETHUSDC"]
|
|
63
64
|
* });
|
|
64
65
|
*/
|
|
65
|
-
createWebSocketClient({ trades, deltas, accounts, }: Readonly<{
|
|
66
|
+
createWebSocketClient({ trades, deltas, accounts, candles, }: Readonly<{
|
|
66
67
|
trades?: string[];
|
|
67
68
|
deltas?: string[];
|
|
68
69
|
accounts?: number[];
|
|
70
|
+
candles?: Array<{
|
|
71
|
+
symbol: string;
|
|
72
|
+
resolution: CandleResolution;
|
|
73
|
+
}>;
|
|
69
74
|
}>): NordWebSocketClient;
|
|
70
75
|
private GET;
|
|
71
76
|
/**
|
|
@@ -161,6 +166,7 @@ export declare class Nord {
|
|
|
161
166
|
* @throws {NordError} If symbol is invalid
|
|
162
167
|
*/
|
|
163
168
|
subscribeOrderbook(symbol: string): OrderbookSubscription;
|
|
169
|
+
subscribeBars(symbol: string, resolution: CandleResolution): CandleSubscription;
|
|
164
170
|
/**
|
|
165
171
|
* Subscribe to trade updates for a market
|
|
166
172
|
*
|
|
@@ -328,18 +334,6 @@ export declare class Nord {
|
|
|
328
334
|
feeKind: FillRole;
|
|
329
335
|
accountId: number;
|
|
330
336
|
}>): Promise<number>;
|
|
331
|
-
/**
|
|
332
|
-
* Fetch the latest available market price at or before the given timestamp.
|
|
333
|
-
*
|
|
334
|
-
* @param marketId - Market identifier
|
|
335
|
-
* @param atOrBefore - RFC3339 timestamp to look back from (returns the latest price at or before this time)
|
|
336
|
-
* @returns Previous market price record; price is `null` if no trades exist at or before `at`
|
|
337
|
-
* @throws {NordError} If the request fails
|
|
338
|
-
*/
|
|
339
|
-
getPrevMarketPrice({ marketId, atOrBefore, }: Readonly<{
|
|
340
|
-
marketId: number;
|
|
341
|
-
atOrBefore: string;
|
|
342
|
-
}>): Promise<PreviousMarketPrice>;
|
|
343
337
|
/**
|
|
344
338
|
* Fetch token statistics such as index price and oracle metadata.
|
|
345
339
|
*
|