@n1xyz/nord-ts 0.0.22 → 0.1.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.
@@ -111,11 +111,13 @@ export interface paths {
111
111
  };
112
112
  };
113
113
  put?: never;
114
- /** @description Send an action to nord to execute. */
114
+ /** @description Send an action to nord to execute. This doesn't use `Protobuf<T>` since we want to length-delimit this message. `body` - (length prefix of action, action data protobuf, and signature). signature has exact length, but depend on action kind. body is exact payload used via other transports and journalled for rexecution */
115
115
  post: {
116
116
  parameters: {
117
117
  query?: never;
118
- header?: never;
118
+ header: {
119
+ "content-type": string;
120
+ };
119
121
  path?: never;
120
122
  cookie?: never;
121
123
  };
@@ -134,6 +136,27 @@ export interface paths {
134
136
  "application/octet-stream": unknown;
135
137
  };
136
138
  };
139
+ 413: {
140
+ headers: {
141
+ [name: string]: unknown;
142
+ };
143
+ content: {
144
+ "application/json": components["schemas"]["PayloadTooLarge"];
145
+ };
146
+ };
147
+ 415: {
148
+ headers: {
149
+ /**
150
+ * @description Expected request media type
151
+ * @example application/octet-stream
152
+ */
153
+ accept: string;
154
+ [name: string]: unknown;
155
+ };
156
+ content: {
157
+ "application/json": components["schemas"]["AcceptedMediaType"];
158
+ };
159
+ };
137
160
  };
138
161
  };
139
162
  delete?: never;
@@ -1892,6 +1915,13 @@ export interface components {
1892
1915
  /** Format: uint16 */
1893
1916
  weightBps: number;
1894
1917
  };
1918
+ AcceptedMediaType: {
1919
+ expected: string;
1920
+ };
1921
+ PayloadTooLarge: {
1922
+ /** Format: uint */
1923
+ limit: number;
1924
+ };
1895
1925
  ActionsQuery: {
1896
1926
  /** Format: uint64 */
1897
1927
  from: number;
@@ -2223,8 +2253,6 @@ export interface components {
2223
2253
  HistoryTriggerInfo: {
2224
2254
  /** Format: uint32 */
2225
2255
  accountId: number;
2226
- /** Format: uint64 */
2227
- actionId: number;
2228
2256
  /** Format: uint32 */
2229
2257
  marketId: number;
2230
2258
  /** Format: uint64 */
@@ -2232,21 +2260,30 @@ export interface components {
2232
2260
  side: components["schemas"]["Side"];
2233
2261
  kind: components["schemas"]["TriggerKind"];
2234
2262
  status: components["schemas"]["TriggerStatus"];
2263
+ /** Format: uint64 */
2264
+ createdAtActionId: number;
2265
+ /** Format: uint64 */
2266
+ finalizedAtActionId?: number | null;
2235
2267
  createdAt: string;
2236
- updatedAt: string;
2268
+ finalizedAt: string;
2237
2269
  };
2238
2270
  /** @enum {string} */
2239
2271
  TriggerKind: "stopLoss" | "takeProfit";
2240
2272
  /** @enum {string} */
2241
- TriggerStatus: "added" | "succeeded" | "failed" | "removed";
2273
+ TriggerStatus: "active" | "success" | "cancel" | "fail" | "remove";
2242
2274
  TriggerInfo: {
2243
2275
  /** Format: uint32 */
2244
2276
  marketId: number;
2245
- /** Format: uint64 */
2246
- price: number;
2247
2277
  side: components["schemas"]["Side"];
2248
2278
  kind: components["schemas"]["TriggerKind"];
2279
+ triggerPrice: components["schemas"]["PositivePriceMantissa"];
2280
+ limitPrice?: components["schemas"]["PositivePriceMantissa"] | null;
2249
2281
  };
2282
+ /**
2283
+ * Format: uint64
2284
+ * @description 63 bit integer, which is always positive
2285
+ */
2286
+ PositivePriceMantissa: number;
2250
2287
  OrderNotFound: null;
2251
2288
  PageResult_for_String_and_Trade: {
2252
2289
  /** @description Set of items for requested by query. */
@@ -2,6 +2,7 @@ import Decimal from "decimal.js";
2
2
  import * as proto from "../../gen/nord_pb";
3
3
  import { FillMode, Side, QuoteSize } from "../../types";
4
4
  import { BigIntValue } from "../../utils";
5
+ export declare function prepareAction(action: proto.Action, makeSignedMessage: (message: Uint8Array) => Promise<Uint8Array>): Promise<Uint8Array<ArrayBufferLike>>;
5
6
  export declare function createSession(serverUrl: string, walletSignFn: (message: string | Uint8Array) => Promise<Uint8Array>, currentTimestamp: bigint, nonce: number, params: {
6
7
  userPubkey: Uint8Array;
7
8
  sessionPubkey: Uint8Array;
@@ -32,7 +32,11 @@ 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 });
39
+ exports.prepareAction = prepareAction;
36
40
  exports.createSession = createSession;
37
41
  exports.revokeSession = revokeSession;
38
42
  exports.withdraw = withdraw;
@@ -41,6 +45,7 @@ exports.cancelOrder = cancelOrder;
41
45
  exports.transfer = transfer;
42
46
  exports.atomic = atomic;
43
47
  const proto = __importStar(require("../../gen/nord_pb"));
48
+ const openapi_fetch_1 = __importDefault(require("openapi-fetch"));
44
49
  const protobuf_1 = require("@bufbuild/protobuf");
45
50
  const types_1 = require("../../types");
46
51
  const utils_1 = require("../../utils");
@@ -61,29 +66,49 @@ function createAction(currentTimestamp, nonce, kind) {
61
66
  kind,
62
67
  });
63
68
  }
64
- async function sendAction(serverUrl, makeSignedMessage, action, actionErrorDesc) {
65
- const encoded = (0, wire_1.sizeDelimitedEncode)(proto.ActionSchema, action);
66
- // validate the payload size
67
- const MAX_PAYLOAD_SIZE = 100 * 1024; // 100 kB
68
- if (encoded.byteLength > MAX_PAYLOAD_SIZE) {
69
- throw new Error(`Encoded message size (${encoded.byteLength} bytes) is greater than max payload size (${MAX_PAYLOAD_SIZE} bytes).`);
70
- }
71
- const body = await makeSignedMessage(encoded);
72
- // TODO: this should be changed to use openapi
73
- const response = await (0, utils_1.checkedFetch)(`${serverUrl}/action`, {
74
- method: "POST",
75
- headers: {
76
- "Content-Type": "application/json",
69
+ async function sendAction(serverUrl, makeSignedMessage, action) {
70
+ const body = await prepareAction(action, makeSignedMessage);
71
+ // NOTE: restructure and reuse client as it is in Nord.ts
72
+ const client = (0, openapi_fetch_1.default)({ baseUrl: serverUrl });
73
+ const response = await client.POST("/action", {
74
+ params: {
75
+ header: {
76
+ "content-type": "application/octet-stream",
77
+ },
77
78
  },
78
- body,
79
+ body: body,
80
+ // NOTE: openapi-fetch ignores headers and types/const headers in schema, and always assume all things are JSON
81
+ // to handle multi type bodies, need these overrides and later adhoc parsing
82
+ bodySerializer: (body) => body,
83
+ parseAs: "stream",
79
84
  });
80
- const rawResp = new Uint8Array(await response.arrayBuffer());
85
+ if (response.error) {
86
+ throw new Error(`Failed to ${action.kind.case}, HTTP status ${JSON.stringify(response.error)}`);
87
+ }
88
+ const rawResp = new Uint8Array(await response.response.bytes());
81
89
  const resp = (0, utils_1.decodeLengthDelimited)(rawResp, proto.ReceiptSchema);
82
90
  if (resp.kind?.case === "err") {
83
- throw new Error(`Could not ${actionErrorDesc}, reason: ${proto.Error[resp.kind.value]}`);
91
+ throw new Error(`Could not execute ${action.kind.case}, reason: ${proto.Error[resp.kind.value]}`);
84
92
  }
85
93
  return resp;
86
94
  }
95
+ // Given action and signature function, prepare the signed message to send to server as `body`.
96
+ // `makeSignedMessage` must include the original message and signature.
97
+ async function prepareAction(action, makeSignedMessage) {
98
+ const encoded = (0, wire_1.sizeDelimitedEncode)(proto.ActionSchema, action);
99
+ // NOTE(agent): keep in sync with MAX_ENCODED_ACTION_SIZE in Rust code
100
+ const MAX_ENCODED_ACTION_SIZE = 1024;
101
+ if (encoded.byteLength > MAX_ENCODED_ACTION_SIZE) {
102
+ console.warn("Encoded message:", encoded);
103
+ throw new Error(`Encoded message size (${encoded.byteLength} bytes) is greater than max payload size (${MAX_ENCODED_ACTION_SIZE} bytes).`);
104
+ }
105
+ const body = await makeSignedMessage(encoded);
106
+ if (body.byteLength > MAX_ENCODED_ACTION_SIZE) {
107
+ console.warn("Encoded length:", encoded.byteLength);
108
+ throw new Error(`Signed message size (${body.byteLength} bytes) is greater than max payload size (${MAX_ENCODED_ACTION_SIZE} bytes).`);
109
+ }
110
+ return body;
111
+ }
87
112
  async function createSession(serverUrl, walletSignFn, currentTimestamp, nonce, params) {
88
113
  (0, utils_1.checkPubKeyLength)(types_1.KeyType.Ed25519, params.userPubkey.length);
89
114
  (0, utils_1.checkPubKeyLength)(types_1.KeyType.Ed25519, params.sessionPubkey.length);
@@ -103,7 +128,7 @@ async function createSession(serverUrl, walletSignFn, currentTimestamp, nonce, p
103
128
  expiryTimestamp: expiry,
104
129
  }),
105
130
  });
106
- const resp = await sendAction(serverUrl, (m) => walletSign(walletSignFn, m), action, "create a new session");
131
+ const resp = await sendAction(serverUrl, (m) => walletSign(walletSignFn, m), action);
107
132
  if (resp.kind?.case === "createSessionResult") {
108
133
  return {
109
134
  actionId: resp.actionId,
@@ -121,7 +146,7 @@ async function revokeSession(serverUrl, walletSignFn, currentTimestamp, nonce, p
121
146
  sessionId: BigInt(params.sessionId),
122
147
  }),
123
148
  });
124
- const resp = await sendAction(serverUrl, (m) => walletSign(walletSignFn, m), action, "revoke session");
149
+ const resp = await sendAction(serverUrl, (m) => walletSign(walletSignFn, m), action);
125
150
  return { actionId: resp.actionId };
126
151
  }
127
152
  async function withdraw(serverUrl, signFn, currentTimestamp, nonce, params) {
@@ -137,7 +162,7 @@ async function withdraw(serverUrl, signFn, currentTimestamp, nonce, params) {
137
162
  amount,
138
163
  }),
139
164
  });
140
- const resp = await sendAction(serverUrl, (m) => sessionSign(signFn, m), action, "withdraw");
165
+ const resp = await sendAction(serverUrl, (m) => sessionSign(signFn, m), action);
141
166
  if (resp.kind?.case === "withdrawResult") {
142
167
  return { actionId: resp.actionId, ...resp.kind.value };
143
168
  }
@@ -151,6 +176,7 @@ async function placeOrder(serverUrl, signFn, currentTimestamp, nonce, params) {
151
176
  const scaledQuote = params.quoteSize
152
177
  ? params.quoteSize.toScaledU64(params.priceDecimals, params.sizeDecimals)
153
178
  : undefined;
179
+ (0, utils_1.assert)(price > 0n || size > 0n || scaledQuote !== undefined, "OrderLimit must include at least one of: size, price, or quoteSize");
154
180
  const action = createAction(currentTimestamp, nonce, {
155
181
  case: "placeOrder",
156
182
  value: (0, protobuf_1.create)(proto.Action_PlaceOrderSchema, {
@@ -174,7 +200,7 @@ async function placeOrder(serverUrl, signFn, currentTimestamp, nonce, params) {
174
200
  delegatorAccountId: params.liquidateeId,
175
201
  }),
176
202
  });
177
- const resp = await sendAction(serverUrl, (m) => sessionSign(signFn, m), action, "place order");
203
+ const resp = await sendAction(serverUrl, (m) => sessionSign(signFn, m), action);
178
204
  if (resp.kind?.case === "placeOrderResult") {
179
205
  return {
180
206
  actionId: resp.actionId,
@@ -196,7 +222,7 @@ async function cancelOrder(serverUrl, signFn, currentTimestamp, nonce, params) {
196
222
  delegatorAccountId: params.liquidateeId,
197
223
  }),
198
224
  });
199
- const resp = await sendAction(serverUrl, (m) => sessionSign(signFn, m), action, "cancel order");
225
+ const resp = await sendAction(serverUrl, (m) => sessionSign(signFn, m), action);
200
226
  if (resp.kind?.case === "cancelOrderResult") {
201
227
  return {
202
228
  actionId: resp.actionId,
@@ -219,7 +245,7 @@ async function transfer(serverUrl, signFn, currentTimestamp, nonce, params) {
219
245
  amount: (0, utils_1.toScaledU64)(params.amount ?? 0, params.tokenDecimals),
220
246
  }),
221
247
  });
222
- const resp = await sendAction(serverUrl, (m) => sessionSign(signFn, m), action, "transfer");
248
+ const resp = await sendAction(serverUrl, (m) => sessionSign(signFn, m), action);
223
249
  if (resp.kind?.case === "transferred") {
224
250
  return {
225
251
  actionId: resp.actionId,
@@ -243,6 +269,8 @@ async function atomic(serverUrl, signFn, currentTimestamp, nonce, params) {
243
269
  const scaledQuote = a.quoteSize
244
270
  ? a.quoteSize.toScaledU64(a.priceDecimals, a.sizeDecimals)
245
271
  : undefined;
272
+ // Require at least one limit to be set (non-zero size, non-zero price, or quoteSize)
273
+ (0, utils_1.assert)(price > 0n || size > 0n || scaledQuote !== undefined, "OrderLimit must include at least one of: size, price, or quoteSize");
246
274
  const tradeOrPlace = (0, protobuf_1.create)(proto.TradeOrPlaceSchema, {
247
275
  marketId: a.marketId,
248
276
  orderType: (0, protobuf_1.create)(proto.OrderTypeSchema, {
@@ -281,7 +309,7 @@ async function atomic(serverUrl, signFn, currentTimestamp, nonce, params) {
281
309
  actions: subactions,
282
310
  }),
283
311
  });
284
- const resp = await sendAction(serverUrl, (m) => sessionSign(signFn, m), action, "execute atomic action");
312
+ const resp = await sendAction(serverUrl, (m) => sessionSign(signFn, m), action);
285
313
  if (resp.kind?.case === "atomic") {
286
314
  return {
287
315
  actionId: resp.actionId,
package/dist/types.js CHANGED
@@ -109,8 +109,8 @@ class QuoteSize {
109
109
  constructor(quotePrice, quoteSize) {
110
110
  const p = new decimal_js_1.default(quotePrice);
111
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");
112
+ if (!p.isPositive() || !s.isPositive()) {
113
+ throw new Error("quotePrice and quoteSize must be positive");
114
114
  }
115
115
  this.price = p;
116
116
  this.size = s;
package/dist/utils.js CHANGED
@@ -31,6 +31,7 @@ const bs58_1 = __importDefault(require("bs58"));
31
31
  exports.SESSION_TTL = 60n * 60n * 24n * 30n;
32
32
  exports.ZERO_DECIMAL = new decimal_js_1.Decimal(0);
33
33
  exports.MAX_BUFFER_LEN = 10000;
34
+ // Max size of data returned from Nord endpoints
34
35
  const MAX_PAYLOAD_SIZE = 100 * 1024; // 100 kB
35
36
  function panic(message) {
36
37
  throw new Error(message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@n1xyz/nord-ts",
3
- "version": "0.0.22",
3
+ "version": "0.1.1",
4
4
  "description": "Typescript for Nord",
5
5
  "keywords": [],
6
6
  "author": "",