@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.
- package/README.md +20 -16
- package/dist/gen/nord_pb.d.ts +100 -32
- package/dist/gen/nord_pb.js +62 -9
- package/dist/gen/openapi.d.ts +45 -8
- package/dist/nord/api/actions.d.ts +1 -0
- package/dist/nord/api/actions.js +51 -23
- package/dist/types.js +2 -2
- package/dist/utils.js +1 -0
- package/package.json +1 -1
- package/src/gen/nord_pb.ts +121 -36
- package/src/gen/openapi.ts +45 -8
- package/src/nord/api/actions.ts +59 -25
- package/src/types.ts +2 -2
- package/src/utils.ts +1 -0
- package/src/gen/nord.ts +0 -7593
package/dist/gen/openapi.d.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
2268
|
+
finalizedAt: string;
|
|
2237
2269
|
};
|
|
2238
2270
|
/** @enum {string} */
|
|
2239
2271
|
TriggerKind: "stopLoss" | "takeProfit";
|
|
2240
2272
|
/** @enum {string} */
|
|
2241
|
-
TriggerStatus: "
|
|
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;
|
package/dist/nord/api/actions.js
CHANGED
|
@@ -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
|
|
65
|
-
const
|
|
66
|
-
//
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
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 ${
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
113
|
-
throw new Error("quotePrice and quoteSize must be
|
|
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);
|