@n1xyz/nord-ts 0.0.22 → 0.1.0

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.
@@ -112,11 +112,13 @@ export interface paths {
112
112
  };
113
113
  };
114
114
  put?: never;
115
- /** @description Send an action to nord to execute. */
115
+ /** @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 */
116
116
  post: {
117
117
  parameters: {
118
118
  query?: never;
119
- header?: never;
119
+ header: {
120
+ "content-type": string;
121
+ };
120
122
  path?: never;
121
123
  cookie?: never;
122
124
  };
@@ -135,6 +137,19 @@ export interface paths {
135
137
  "application/octet-stream": unknown;
136
138
  };
137
139
  };
140
+ 415: {
141
+ headers: {
142
+ /**
143
+ * @description Expected request media type
144
+ * @example application/octet-stream
145
+ */
146
+ accept: string;
147
+ [name: string]: unknown;
148
+ };
149
+ content: {
150
+ "application/json": components["schemas"]["AcceptedMediaType"];
151
+ };
152
+ };
138
153
  };
139
154
  };
140
155
  delete?: never;
@@ -1893,6 +1908,9 @@ export interface components {
1893
1908
  /** Format: uint16 */
1894
1909
  weightBps: number;
1895
1910
  };
1911
+ AcceptedMediaType: {
1912
+ expected: string;
1913
+ };
1896
1914
  ActionsQuery: {
1897
1915
  /** Format: uint64 */
1898
1916
  from: number;
@@ -2224,8 +2242,6 @@ export interface components {
2224
2242
  HistoryTriggerInfo: {
2225
2243
  /** Format: uint32 */
2226
2244
  accountId: number;
2227
- /** Format: uint64 */
2228
- actionId: number;
2229
2245
  /** Format: uint32 */
2230
2246
  marketId: number;
2231
2247
  /** Format: uint64 */
@@ -2233,21 +2249,30 @@ export interface components {
2233
2249
  side: components["schemas"]["Side"];
2234
2250
  kind: components["schemas"]["TriggerKind"];
2235
2251
  status: components["schemas"]["TriggerStatus"];
2252
+ /** Format: uint64 */
2253
+ createdAtActionId: number;
2254
+ /** Format: uint64 */
2255
+ finalizedAtActionId?: number | null;
2236
2256
  createdAt: string;
2237
- updatedAt: string;
2257
+ finalizedAt: string;
2238
2258
  };
2239
2259
  /** @enum {string} */
2240
2260
  TriggerKind: "stopLoss" | "takeProfit";
2241
2261
  /** @enum {string} */
2242
- TriggerStatus: "added" | "succeeded" | "failed" | "removed";
2262
+ TriggerStatus: "active" | "success" | "cancel" | "fail" | "remove";
2243
2263
  TriggerInfo: {
2244
2264
  /** Format: uint32 */
2245
2265
  marketId: number;
2246
- /** Format: uint64 */
2247
- price: number;
2248
2266
  side: components["schemas"]["Side"];
2249
2267
  kind: components["schemas"]["TriggerKind"];
2268
+ triggerPrice: components["schemas"]["PositivePriceMantissa"];
2269
+ limitPrice?: components["schemas"]["PositivePriceMantissa"] | null;
2250
2270
  };
2271
+ /**
2272
+ * Format: uint64
2273
+ * @description 63 bit integer, which is always positive
2274
+ */
2275
+ PositivePriceMantissa: number;
2251
2276
  OrderNotFound: null;
2252
2277
  PageResult_for_String_and_Trade: {
2253
2278
  /** @description Set of items for requested by query. */
@@ -1,5 +1,8 @@
1
1
  import Decimal from "decimal.js";
2
2
  import * as proto from "../../gen/nord_pb";
3
+ import { paths, components } from "../../gen/openapi";
4
+ import createClient from "openapi-fetch";
5
+
3
6
  import { create } from "@bufbuild/protobuf";
4
7
  import {
5
8
  FillMode,
@@ -54,25 +57,23 @@ async function sendAction(
54
57
  action: proto.Action,
55
58
  actionErrorDesc: string,
56
59
  ): Promise<proto.Receipt> {
57
- const encoded = sizeDelimitedEncode(proto.ActionSchema, action);
58
- // validate the payload size
59
- const MAX_PAYLOAD_SIZE = 100 * 1024; // 100 kB
60
- if (encoded.byteLength > MAX_PAYLOAD_SIZE) {
61
- throw new Error(
62
- `Encoded message size (${encoded.byteLength} bytes) is greater than max payload size (${MAX_PAYLOAD_SIZE} bytes).`,
63
- );
64
- }
65
- const body = await makeSignedMessage(encoded);
66
-
67
- // TODO: this should be changed to use openapi
68
- const response = await checkedFetch(`${serverUrl}/action`, {
69
- method: "POST",
70
- headers: {
71
- "Content-Type": "application/json",
60
+ const body = await prepareAction(action, makeSignedMessage);
61
+ // NOTE: restructure and reuse client as it is in Nord.ts
62
+ const client = createClient<paths>({ baseUrl: serverUrl });
63
+ const response = await client.POST("/action", {
64
+ params: {
65
+ header: {
66
+ "content-type": "application/octet-stream",
67
+ },
72
68
  },
73
- body,
69
+ body: body,
74
70
  });
75
- const rawResp = new Uint8Array(await response.arrayBuffer());
71
+
72
+ if (response.error) {
73
+ throw new Error(`Failed to ${actionErrorDesc}, HTTP status ${response}`);
74
+ }
75
+
76
+ const rawResp = new Uint8Array(await response.response.arrayBuffer());
76
77
 
77
78
  const resp: proto.Receipt = decodeLengthDelimited(
78
79
  rawResp,
@@ -88,6 +89,24 @@ async function sendAction(
88
89
  return resp;
89
90
  }
90
91
 
92
+ // Given action and signature function, prepare the signed message to send to server as `body`.
93
+ // `makeSignedMessage` must include the original message and signature.
94
+ export async function prepareAction(
95
+ action: proto.Action,
96
+ makeSignedMessage: (message: Uint8Array) => Promise<Uint8Array>,
97
+ ) {
98
+ const encoded = sizeDelimitedEncode(proto.ActionSchema, action);
99
+ // NOTE(agent): keep in sync with MAX_HTTP_REQUEST_BODY_SIZE in rust code
100
+ const MAX_HTTP_REQUEST_BODY_SIZE = 1024;
101
+ if (encoded.byteLength > MAX_HTTP_REQUEST_BODY_SIZE) {
102
+ throw new Error(
103
+ `Encoded message size (${encoded.byteLength} bytes) is greater than max payload size (${MAX_HTTP_REQUEST_BODY_SIZE} bytes).`,
104
+ );
105
+ }
106
+ const body = await makeSignedMessage(encoded);
107
+ return body;
108
+ }
109
+
91
110
  export async function createSession(
92
111
  serverUrl: string,
93
112
  walletSignFn: (message: string | Uint8Array) => Promise<Uint8Array>,
@@ -241,6 +260,11 @@ export async function placeOrder(
241
260
  ? params.quoteSize.toScaledU64(params.priceDecimals, params.sizeDecimals)
242
261
  : undefined;
243
262
 
263
+ assert(
264
+ price > 0n || size > 0n || scaledQuote !== undefined,
265
+ "OrderLimit must include at least one of: size, price, or quoteSize",
266
+ );
267
+
244
268
  const action = createAction(currentTimestamp, nonce, {
245
269
  case: "placeOrder",
246
270
  value: create(proto.Action_PlaceOrderSchema, {
@@ -431,6 +455,12 @@ export async function atomic(
431
455
  ? a.quoteSize.toScaledU64(a.priceDecimals, a.sizeDecimals)
432
456
  : undefined;
433
457
 
458
+ // Require at least one limit to be set (non-zero size, non-zero price, or quoteSize)
459
+ assert(
460
+ price > 0n || size > 0n || scaledQuote !== undefined,
461
+ "OrderLimit must include at least one of: size, price, or quoteSize",
462
+ );
463
+
434
464
  const tradeOrPlace: proto.TradeOrPlace = create(
435
465
  proto.TradeOrPlaceSchema,
436
466
  {
package/src/types.ts CHANGED
@@ -310,8 +310,8 @@ export class QuoteSize {
310
310
  constructor(quotePrice: Decimal.Value, quoteSize: Decimal.Value) {
311
311
  const p = new Decimal(quotePrice);
312
312
  const s = new Decimal(quoteSize);
313
- if (p.isZero() || s.isZero()) {
314
- throw new Error("quotePrice and quoteSize must be non-zero");
313
+ if (!p.isPositive() || !s.isPositive()) {
314
+ throw new Error("quotePrice and quoteSize must be positive");
315
315
  }
316
316
  this.price = p;
317
317
  this.size = s;