@n1xyz/nord-ts 0.2.0 → 0.3.2
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/NordUser.d.ts +3 -0
- package/dist/gen/nord_pb.d.ts +12 -5
- package/dist/gen/openapi.d.ts +236 -65
- package/dist/{bundle.js → index.browser.js} +83649 -66420
- package/dist/index.common.js +116210 -0
- package/dist/types.d.ts +26 -15
- package/dist/websocket/Subscriber.d.ts +2 -2
- package/package.json +8 -5
- package/dist/actions.js +0 -184
- package/dist/client/Nord.js +0 -759
- package/dist/client/NordAdmin.js +0 -362
- package/dist/client/NordUser.js +0 -749
- package/dist/const.js +0 -27
- package/dist/error.js +0 -51
- package/dist/gen/nord_pb.js +0 -1061
- package/dist/gen/openapi.js +0 -5
- package/dist/index.js +0 -10
- package/dist/types.js +0 -92
- package/dist/utils.js +0 -193
- package/dist/websocket/NordWebSocketClient.js +0 -242
- package/dist/websocket/Subscriber.js +0 -24
- package/dist/websocket/events.js +0 -1
- package/dist/websocket/index.js +0 -80
package/dist/types.d.ts
CHANGED
|
@@ -61,10 +61,10 @@ export type PlacementOrigin = components["schemas"]["PlacementOrigin"];
|
|
|
61
61
|
export type FinalizationReason = components["schemas"]["FinalizationReason"];
|
|
62
62
|
export type PagedQuery = components["schemas"]["PagedQuery"];
|
|
63
63
|
export type AccountPnlInfo = components["schemas"]["AccountPnlInfo"];
|
|
64
|
-
export type AccountPnlInfoPage = components["schemas"]["
|
|
65
|
-
export type AccountTriggerInfo = components["schemas"]["
|
|
66
|
-
export type TriggerHistoryPage = components["schemas"]["
|
|
67
|
-
export type WithdrawalHistoryPage = components["schemas"]["
|
|
64
|
+
export type AccountPnlInfoPage = components["schemas"]["PageResult_for_String_and_AccountPnlInfo"];
|
|
65
|
+
export type AccountTriggerInfo = components["schemas"]["TriggerInfo"];
|
|
66
|
+
export type TriggerHistoryPage = components["schemas"]["PageResult_for_String_and_Trigger"];
|
|
67
|
+
export type WithdrawalHistoryPage = components["schemas"]["PageResult_for_String_and_Withdrawal"];
|
|
68
68
|
export type FeeTierConfig = components["schemas"]["FeeTierConfig"];
|
|
69
69
|
export type FeeTierId = components["schemas"]["FeeTierId"];
|
|
70
70
|
export type TokenStats = components["schemas"]["TokenStats"];
|
|
@@ -127,7 +127,7 @@ export interface StreamTrade {
|
|
|
127
127
|
side: Side;
|
|
128
128
|
price: number;
|
|
129
129
|
size: number;
|
|
130
|
-
order_id:
|
|
130
|
+
order_id: string;
|
|
131
131
|
}
|
|
132
132
|
export interface Trades {
|
|
133
133
|
last_update_id: number;
|
|
@@ -199,12 +199,7 @@ export declare enum WebSocketMessageType {
|
|
|
199
199
|
/**
|
|
200
200
|
* WebSocket trade update message
|
|
201
201
|
*/
|
|
202
|
-
export
|
|
203
|
-
e: WebSocketMessageType.TradeUpdate;
|
|
204
|
-
symbol: string;
|
|
205
|
-
trades: StreamTrade[];
|
|
206
|
-
timestamp: number;
|
|
207
|
-
}
|
|
202
|
+
export type WebSocketTradeUpdate = Trades;
|
|
208
203
|
/**
|
|
209
204
|
* WebSocket delta update message
|
|
210
205
|
*/
|
|
@@ -217,19 +212,35 @@ export interface WebSocketDeltaUpdate {
|
|
|
217
212
|
bids: OrderbookEntry[];
|
|
218
213
|
timestamp: number;
|
|
219
214
|
}
|
|
215
|
+
export type OrderId = string;
|
|
220
216
|
export interface WebSocketAccountUpdate {
|
|
221
217
|
last_update_id: number;
|
|
222
218
|
update_id: number;
|
|
223
219
|
account_id: number;
|
|
224
|
-
fills: Record<
|
|
225
|
-
|
|
226
|
-
|
|
220
|
+
fills: Record<OrderId, {
|
|
221
|
+
side: "bid" | "ask";
|
|
222
|
+
quantity: number;
|
|
223
|
+
remaining: number;
|
|
224
|
+
price: number;
|
|
225
|
+
order_id: string;
|
|
226
|
+
market_id: number;
|
|
227
|
+
maker_id: number;
|
|
228
|
+
taker_id: number;
|
|
229
|
+
sender_tracking_id: number | null;
|
|
230
|
+
}>;
|
|
231
|
+
places: Record<OrderId, {
|
|
232
|
+
side: "bid" | "ask";
|
|
233
|
+
current_size: number;
|
|
234
|
+
price: number;
|
|
235
|
+
market_id: number;
|
|
236
|
+
}>;
|
|
237
|
+
cancels: Record<OrderId, {
|
|
227
238
|
side: "bid" | "ask";
|
|
228
239
|
current_size: number;
|
|
229
240
|
price: number;
|
|
230
241
|
market_id: number;
|
|
231
242
|
}>;
|
|
232
|
-
balances: Record<string,
|
|
243
|
+
balances: Record<string, number>;
|
|
233
244
|
}
|
|
234
245
|
export type WebSocketMessage = {
|
|
235
246
|
trades: WebSocketTradeUpdate;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventEmitter } from "events";
|
|
2
|
-
import { Account, DeltaEvent, WebSocketDeltaUpdate, SubscriberConfig,
|
|
2
|
+
import { Account, DeltaEvent, WebSocketDeltaUpdate, SubscriberConfig, Trades, WebSocketTradeUpdate } from "../types";
|
|
3
3
|
/**
|
|
4
4
|
* Subscriber class for handling WebSocket subscriptions
|
|
5
5
|
*/
|
|
@@ -30,7 +30,7 @@ export interface OrderbookSubscription extends EventEmitter {
|
|
|
30
30
|
* Interface for trade subscription
|
|
31
31
|
*/
|
|
32
32
|
export interface TradeSubscription extends EventEmitter {
|
|
33
|
-
on(event: "message", listener: (data:
|
|
33
|
+
on(event: "message", listener: (data: WebSocketTradeUpdate) => void): this;
|
|
34
34
|
on(event: "error", listener: (error: Error) => void): this;
|
|
35
35
|
close(): void;
|
|
36
36
|
removeAllListeners(event?: string): this;
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@n1xyz/nord-ts",
|
|
3
|
-
"version": "0.2
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Typescript for Nord",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "",
|
|
7
7
|
"license": "ISC",
|
|
8
8
|
"type": "module",
|
|
9
|
-
"main": "dist/index.js",
|
|
9
|
+
"main": "dist/index.common.js",
|
|
10
|
+
"browser": "dist/index.browser.js",
|
|
10
11
|
"types": "dist/index.d.ts",
|
|
11
12
|
"files": [
|
|
12
13
|
"dist/",
|
|
@@ -17,12 +18,14 @@
|
|
|
17
18
|
"gen:proto": "bunx @bufbuild/buf generate ../engine",
|
|
18
19
|
"gen:api": "nix run ..#openapi | bunx openapi-typescript > src/gen/openapi.ts",
|
|
19
20
|
"gen": "bun run gen:proto && bun run gen:api",
|
|
20
|
-
"build": "bun
|
|
21
|
+
"build:node": "bun build ./src/index.ts --target=node --format=esm --outfile=dist/index.common.js",
|
|
22
|
+
"build:browser": "bun build ./src/index.ts --target=browser --format=esm --outfile=dist/index.browser.js",
|
|
23
|
+
"build": "bun run gen && bunx tsc && bun run build:node && bun run build:browser && bun run docs",
|
|
21
24
|
"docs": "bunx typedoc --out ./docs ./src",
|
|
22
25
|
"compile": "tsc",
|
|
23
26
|
"clean": "rm -rf ./src/gen ./dist ./docs",
|
|
24
27
|
"fmt": "prettier --write src tests",
|
|
25
|
-
"ci": "bunx eslint && prettier --check src tests",
|
|
28
|
+
"ci": "bunx eslint && bunx tsc && prettier --check src tests",
|
|
26
29
|
"all": "bun install && bun run build && bun run ci && bun fmt"
|
|
27
30
|
},
|
|
28
31
|
"devDependencies": {
|
|
@@ -44,7 +47,7 @@
|
|
|
44
47
|
},
|
|
45
48
|
"dependencies": {
|
|
46
49
|
"@bufbuild/protobuf": "^2.6.3",
|
|
47
|
-
"@n1xyz/proton": "0.1.
|
|
50
|
+
"@n1xyz/proton": "0.1.1",
|
|
48
51
|
"@noble/curves": "^1.9.6",
|
|
49
52
|
"@noble/ed25519": "^2.3.0",
|
|
50
53
|
"@noble/hashes": "^1.8.0",
|
package/dist/actions.js
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
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
|
-
}
|