@n1xyz/nord-ts 0.0.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.
Files changed (141) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc.js +20 -0
  3. package/.prettierignore +1 -0
  4. package/README.md +110 -0
  5. package/dist/abis/ERC20_ABI.d.ts +39 -0
  6. package/dist/abis/ERC20_ABI.js +313 -0
  7. package/dist/abis/NORD_GETTERS_FACET_ABI.d.ts +34 -0
  8. package/dist/abis/NORD_GETTERS_FACET_ABI.js +195 -0
  9. package/dist/abis/NORD_RAMP_FACET_ABI.d.ts +35 -0
  10. package/dist/abis/NORD_RAMP_FACET_ABI.js +144 -0
  11. package/dist/abis/index.d.ts +3 -0
  12. package/dist/abis/index.js +9 -0
  13. package/dist/const.d.ts +11 -0
  14. package/dist/const.js +34 -0
  15. package/dist/gen/common.d.ts +63 -0
  16. package/dist/gen/common.js +205 -0
  17. package/dist/gen/nord.d.ts +705 -0
  18. package/dist/gen/nord.js +4784 -0
  19. package/dist/index.d.ts +5 -0
  20. package/dist/index.js +21 -0
  21. package/dist/nord/Nord.d.ts +76 -0
  22. package/dist/nord/Nord.js +376 -0
  23. package/dist/nord/NordImpl.d.ts +7 -0
  24. package/dist/nord/NordImpl.js +6 -0
  25. package/dist/nord/NordUser.d.ts +77 -0
  26. package/dist/nord/NordUser.js +249 -0
  27. package/dist/nord/actions.d.ts +101 -0
  28. package/dist/nord/actions.js +254 -0
  29. package/dist/nord/index.d.ts +2 -0
  30. package/dist/nord/index.js +9 -0
  31. package/dist/types.d.ts +343 -0
  32. package/dist/types.js +92 -0
  33. package/dist/utils.d.ts +114 -0
  34. package/dist/utils.js +257 -0
  35. package/docs/.nojekyll +1 -0
  36. package/docs/assets/highlight.css +92 -0
  37. package/docs/assets/icons.js +15 -0
  38. package/docs/assets/icons.svg +1 -0
  39. package/docs/assets/main.js +59 -0
  40. package/docs/assets/navigation.js +1 -0
  41. package/docs/assets/search.js +1 -0
  42. package/docs/assets/style.css +1415 -0
  43. package/docs/classes/Nord.html +44 -0
  44. package/docs/classes/NordUser.html +35 -0
  45. package/docs/classes/Subscriber.html +6 -0
  46. package/docs/enums/FillMode.html +5 -0
  47. package/docs/enums/KeyType.html +4 -0
  48. package/docs/enums/PeakTpsPeriodUnit.html +15 -0
  49. package/docs/enums/Side.html +3 -0
  50. package/docs/functions/assert.html +1 -0
  51. package/docs/functions/bigIntToProtoU128.html +4 -0
  52. package/docs/functions/checkPubKeyLength.html +1 -0
  53. package/docs/functions/checkedFetch.html +6 -0
  54. package/docs/functions/createWebSocketSubscription.html +12 -0
  55. package/docs/functions/decodeLengthDelimited.html +10 -0
  56. package/docs/functions/encodeLengthDelimited.html +6 -0
  57. package/docs/functions/fillModeToProtoFillMode.html +5 -0
  58. package/docs/functions/findMarket.html +1 -0
  59. package/docs/functions/findToken.html +1 -0
  60. package/docs/functions/makeWalletSignFn.html +6 -0
  61. package/docs/functions/optExpect.html +5 -0
  62. package/docs/functions/optMap.html +5 -0
  63. package/docs/functions/optUnwrap.html +2 -0
  64. package/docs/functions/panic.html +1 -0
  65. package/docs/functions/signAction.html +6 -0
  66. package/docs/functions/toScaledU128.html +8 -0
  67. package/docs/functions/toScaledU64.html +8 -0
  68. package/docs/index.html +21 -0
  69. package/docs/interfaces/Account.html +8 -0
  70. package/docs/interfaces/ActionInfo.html +8 -0
  71. package/docs/interfaces/ActionQuery.html +4 -0
  72. package/docs/interfaces/ActionResponse.html +8 -0
  73. package/docs/interfaces/ActionsExtendedInfo.html +10 -0
  74. package/docs/interfaces/ActionsQuery.html +5 -0
  75. package/docs/interfaces/ActionsResponse.html +6 -0
  76. package/docs/interfaces/AggregateMetrics.html +12 -0
  77. package/docs/interfaces/BlockQuery.html +6 -0
  78. package/docs/interfaces/BlockResponse.html +6 -0
  79. package/docs/interfaces/BlockSummary.html +8 -0
  80. package/docs/interfaces/BlockSummaryResponse.html +6 -0
  81. package/docs/interfaces/DeltaEvent.html +6 -0
  82. package/docs/interfaces/ERC20TokenInfo.html +5 -0
  83. package/docs/interfaces/Info.html +3 -0
  84. package/docs/interfaces/Market.html +6 -0
  85. package/docs/interfaces/MarketStats.html +7 -0
  86. package/docs/interfaces/MarketsStatsResponse.html +2 -0
  87. package/docs/interfaces/NordConfig.html +5 -0
  88. package/docs/interfaces/Order.html +6 -0
  89. package/docs/interfaces/OrderInfo.html +6 -0
  90. package/docs/interfaces/OrderbookOrder.html +6 -0
  91. package/docs/interfaces/OrderbookResponse.html +10 -0
  92. package/docs/interfaces/PerpMarketStats.html +5 -0
  93. package/docs/interfaces/RollmanActionExtendedInfo.html +4 -0
  94. package/docs/interfaces/RollmanActionInfo.html +4 -0
  95. package/docs/interfaces/RollmanActionResponse.html +4 -0
  96. package/docs/interfaces/RollmanActionsResponse.html +2 -0
  97. package/docs/interfaces/RollmanBlockResponse.html +3 -0
  98. package/docs/interfaces/SubscriberConfig.html +3 -0
  99. package/docs/interfaces/Token.html +5 -0
  100. package/docs/interfaces/Trade.html +5 -0
  101. package/docs/interfaces/TradeInfo.html +20 -0
  102. package/docs/interfaces/Trades.html +5 -0
  103. package/docs/interfaces/TradesQueryParams.html +10 -0
  104. package/docs/interfaces/TradesResponse.html +12 -0
  105. package/docs/modules.html +77 -0
  106. package/docs/types/BigIntValue.html +2 -0
  107. package/docs/variables/DEBUG_KEYS.html +1 -0
  108. package/docs/variables/DEFAULT_FUNDING_AMOUNTS.html +1 -0
  109. package/docs/variables/DEV_CONTRACT_ADDRESS.html +1 -0
  110. package/docs/variables/DEV_TOKEN_INFOS.html +1 -0
  111. package/docs/variables/DEV_URL.html +1 -0
  112. package/docs/variables/ERC20_ABI.html +1 -0
  113. package/docs/variables/EVM_DEV_URL.html +1 -0
  114. package/docs/variables/FAUCET_PRIVATE_ADDRESS.html +1 -0
  115. package/docs/variables/MAX_BUFFER_LEN.html +1 -0
  116. package/docs/variables/NORD_GETTERS_FACET_ABI.html +1 -0
  117. package/docs/variables/NORD_RAMP_FACET_ABI.html +1 -0
  118. package/docs/variables/SESSION_TTL.html +1 -0
  119. package/docs/variables/WEBSERVER_DEV_URL.html +1 -0
  120. package/docs/variables/ZERO_DECIMAL.html +1 -0
  121. package/jest.config.ts +9 -0
  122. package/nodemon.json +4 -0
  123. package/package.json +61 -0
  124. package/protoc-generate.sh +23 -0
  125. package/src/abis/ERC20_ABI.ts +310 -0
  126. package/src/abis/NORD_GETTERS_FACET_ABI.ts +192 -0
  127. package/src/abis/NORD_RAMP_FACET_ABI.ts +141 -0
  128. package/src/abis/index.ts +3 -0
  129. package/src/const.ts +39 -0
  130. package/src/gen/common.ts +280 -0
  131. package/src/gen/nord.ts +5666 -0
  132. package/src/index.ts +5 -0
  133. package/src/nord/Nord.ts +504 -0
  134. package/src/nord/NordImpl.ts +8 -0
  135. package/src/nord/NordUser.ts +469 -0
  136. package/src/nord/actions.ts +484 -0
  137. package/src/nord/index.ts +2 -0
  138. package/src/types.ts +393 -0
  139. package/src/utils.ts +300 -0
  140. package/tests/utils.spec.ts +154 -0
  141. package/tsconfig.json +24 -0
package/src/types.ts ADDED
@@ -0,0 +1,393 @@
1
+ import * as proto from "./gen/nord";
2
+
3
+ /**
4
+ * The peak TPS rate is queried over the specified period.
5
+ * The period is specified in units of: {hour, day, week, month, year}.
6
+ * Example inputs:
7
+ * 1. AggregateMetrics.txPeakTpsPeriod = 3,
8
+ * AggregateMetrics.txPeakTpsPeriodUnit = "d" => Peak TPS over last 3 days.
9
+ * 1. AggregateMetrics.txPeakTpsPeriod = 1,
10
+ * AggregateMetrics.txPeakTpsPeriodUnit = "w" => Peak TPS over last week.
11
+ */
12
+ export enum PeakTpsPeriodUnit {
13
+ Hour = "h",
14
+ Day = "d",
15
+ Week = "w",
16
+ Month = "m",
17
+ Year = "y",
18
+ }
19
+
20
+ export interface NordConfig {
21
+ evmUrl: string;
22
+ webServerUrl: string;
23
+ contractAddress: string;
24
+ tokenInfos: ERC20TokenInfo[];
25
+ }
26
+
27
+ export interface ERC20TokenInfo {
28
+ address: string;
29
+ precision: number;
30
+ tokenId: number;
31
+ name: string;
32
+ }
33
+
34
+ export interface Order {
35
+ orderId: number;
36
+ isLong: boolean;
37
+ size: number;
38
+ price: number;
39
+ marketId: number;
40
+ }
41
+
42
+ export enum KeyType {
43
+ Ed25519,
44
+ Secp256k1,
45
+ Bls12_381,
46
+ }
47
+
48
+ export enum Side {
49
+ Ask,
50
+ Bid,
51
+ }
52
+
53
+ export enum FillMode {
54
+ Limit,
55
+ PostOnly,
56
+ ImmediateOrCancel,
57
+ FillOrKill,
58
+ }
59
+
60
+ export interface SubscriberConfig {
61
+ streamURL: string;
62
+ maxBufferLen?: number;
63
+ }
64
+
65
+ export interface Market {
66
+ symbol: string;
67
+ baseTokenId: number;
68
+ quoteTokenId: number;
69
+ priceDecimals: number;
70
+ sizeDecimals: number;
71
+ }
72
+
73
+ export interface Token {
74
+ symbol: string;
75
+ ethAddr: string;
76
+ decimals: number;
77
+ tokenId: number;
78
+ }
79
+
80
+ export interface Info {
81
+ markets: Market[];
82
+ tokens: Token[];
83
+ }
84
+
85
+ export interface DeltaEvent {
86
+ last_update_id: number;
87
+ update_id: number;
88
+ market_symbol: string;
89
+ asks: [number, number];
90
+ bids: [number, number];
91
+ }
92
+
93
+ export interface Trade {
94
+ side: Side;
95
+ price: number;
96
+ size: number;
97
+ order_id: number;
98
+ }
99
+
100
+ export interface Trades {
101
+ last_update_id: number;
102
+ update_id: number;
103
+ market_symbol: string;
104
+ trades: Trade[];
105
+ }
106
+
107
+ export interface OrderInfo {
108
+ id: number;
109
+ reduce_only: boolean;
110
+ imit_price: number;
111
+ size: number;
112
+ account_id: number;
113
+ }
114
+
115
+ interface HashMap<T> {
116
+ [key: number]: T;
117
+ }
118
+
119
+ export interface Account {
120
+ last_update_id: number;
121
+ update_id: number;
122
+ account_id: number;
123
+ fills: HashMap<FillMode>;
124
+ places: HashMap<OrderInfo>;
125
+ cancels: HashMap<OrderInfo>;
126
+ balances: HashMap<number>;
127
+ }
128
+
129
+ /**
130
+ * Query the transactions in the specified L2 block.
131
+ * @field {number} block_number specifies the block number to query.
132
+ * If not specified, transactions from latest block
133
+ * are returned.
134
+ */
135
+ export interface BlockQuery {
136
+ block_number?: number;
137
+ }
138
+
139
+ /**
140
+ * Response for BlockQuery.
141
+ * @field {number} block_number specifies the block number being returned.
142
+ * @field {BlockActions} actions are the list of transactions from the block.
143
+ */
144
+ export interface BlockResponse {
145
+ block_number: number;
146
+ actions: ActionInfo[];
147
+ }
148
+
149
+ /**
150
+ * Response for BlockSummaryQuery.
151
+ * @field {BlockSummary} block_summary is the summary of upto the last N blocks.
152
+ * The server can return fewer than last_n block summary if
153
+ * fewer blocks are available or if it exceeds a max cap.
154
+ */
155
+ export interface BlockSummaryResponse {
156
+ block_summary: BlockSummary[];
157
+ }
158
+
159
+ /**
160
+ * Query the action for the specified action id.
161
+ * @field {number} action_id specifies the action to query.
162
+ */
163
+ export interface ActionQuery {
164
+ action_id: number;
165
+ }
166
+
167
+ /**
168
+ * Response for ActionQuery.
169
+ * @field {number} block_number the block the action is part of.
170
+ * If the action is not yet included in any block,
171
+ * null is returned.
172
+ * @field {Action} the transaction.
173
+ */
174
+ export interface ActionResponse {
175
+ block_number?: number;
176
+ action: proto.Action;
177
+ }
178
+
179
+ /**
180
+ * Query the recent actions
181
+ * @field {number} last_n requests last N actions.
182
+ * @field {number} action_id specifies the action to query.
183
+ */
184
+ export interface ActionsQuery {
185
+ last_n: number;
186
+ }
187
+
188
+ /**
189
+ * Response for ActionsQuery.
190
+ * @field {ActionsExtendedInfo} actions returns upto the last N actions.
191
+ * The server can return fewer than last_n actions if
192
+ * fewer actions are available or if it exceeds a max cap.
193
+ */
194
+ export interface ActionsResponse {
195
+ actions: ActionsExtendedInfo[];
196
+ }
197
+
198
+ /**
199
+ * Block summary.
200
+ * @field {number} block_number Block number.
201
+ * @field {Action} from First action_id in the block.
202
+ * @field {Action} to Last action_id in the block.
203
+ */
204
+ export interface BlockSummary {
205
+ block_number: number;
206
+ from_action_id: number;
207
+ to_action_id: number;
208
+ }
209
+
210
+ /**
211
+ * Info about the block transaction.
212
+ * @field {number} action_id is the action identifier.
213
+ * @field {Action} action in protobuf format.
214
+ * @field {number} exec_timestamp is the execution timestamp.
215
+ */
216
+ export interface ActionInfo {
217
+ action_id: number;
218
+ action: proto.Action;
219
+ exec_timestamp: number;
220
+ }
221
+
222
+ /**
223
+ * Extended info about the block transaction.
224
+ * @field {number} block_number the block the action is part of.
225
+ * If the action is not yet included in any block,
226
+ * null is returned.
227
+ * @field {number} action_id of the action.
228
+ * @field {Action} action the transaction.
229
+ */
230
+ export interface ActionsExtendedInfo {
231
+ block_number?: number;
232
+ action_id: number;
233
+ action: proto.Action;
234
+ }
235
+
236
+ /**
237
+ * Aggregate metrics
238
+ * @field {number} blocks_total: Total number of L2 blocks.
239
+ * @field {number} tx_total: Total number of transactions.
240
+ * @field {number} tx_tps: Transaction throughput.
241
+ * @field {number} tx_tps_peak: Peak transaction throughput.
242
+ * @field {number} request_latency_average: Average request latency.
243
+ */
244
+ export interface AggregateMetrics {
245
+ blocks_total: number;
246
+ tx_total: number;
247
+ tx_tps: number;
248
+ tx_tps_peak: number;
249
+ request_latency_average: number;
250
+ }
251
+
252
+ /**
253
+ * Parameters for querying trades
254
+ * @field {number} accountId - ID of target account
255
+ * @field {string} [since] - Start with this timestamp (RFC3339); defaults to UNIX epoch start
256
+ * @field {string} [until] - End with this timestamp (RFC3339); defaults to current date-time
257
+ * @field {string} [pageId] - Fetch results starting with this page
258
+ */
259
+ export interface TradesQueryParams {
260
+ accountId: number;
261
+ since?: string;
262
+ until?: string;
263
+ pageId?: string;
264
+ }
265
+
266
+ /**
267
+ * Trade information
268
+ * @field {string} id - Trade ID
269
+ * @field {string} timestamp - Trade timestamp (RFC3339)
270
+ * @field {string} symbol - Market symbol
271
+ * @field {string} side - Trade side (buy/sell)
272
+ * @field {number} price - Trade price
273
+ * @field {number} size - Trade size
274
+ * @field {number} fee - Trade fee
275
+ * @field {string} feeCurrency - Fee currency
276
+ * @field {number} orderId - Order ID
277
+ */
278
+ export interface TradeInfo {
279
+ id: string;
280
+ timestamp: string;
281
+ symbol: string;
282
+ side: string;
283
+ price: number;
284
+ size: number;
285
+ fee: number;
286
+ feeCurrency: string;
287
+ orderId: number;
288
+ }
289
+
290
+ /**
291
+ * Response for trades query
292
+ * @field {number} accountId - Account ID
293
+ * @field {string} since - Start timestamp (RFC3339)
294
+ * @field {string} until - End timestamp (RFC3339)
295
+ * @field {string} [nextPageId] - ID for the next page of results
296
+ * @field {TradeInfo[]} trades - Array of trades
297
+ */
298
+ export interface TradesResponse {
299
+ accountId: number;
300
+ since: string;
301
+ until: string;
302
+ nextPageId?: string;
303
+ trades: TradeInfo[];
304
+ }
305
+
306
+ /**
307
+ * Order in the orderbook
308
+ * @field {number} price - Order price
309
+ * @field {number} size - Order size
310
+ */
311
+ export interface OrderbookOrder {
312
+ price: number;
313
+ size: number;
314
+ }
315
+
316
+ /**
317
+ * Response for orderbook query
318
+ * @field {string} symbol - Market symbol
319
+ * @field {number} timestamp - Orderbook timestamp
320
+ * @field {OrderbookOrder[]} bids - Array of bid orders
321
+ * @field {OrderbookOrder[]} asks - Array of ask orders
322
+ */
323
+ export interface OrderbookResponse {
324
+ symbol: string;
325
+ timestamp: number;
326
+ bids: OrderbookOrder[];
327
+ asks: OrderbookOrder[];
328
+ }
329
+
330
+ // The JSON types returned by rollman, that need to be translated to TS format.
331
+ export interface RollmanBlockResponse {
332
+ block_number: number;
333
+ actions: RollmanActionInfo[];
334
+ }
335
+
336
+ export interface RollmanActionResponse {
337
+ block_number?: number;
338
+ action_pb: Uint8Array;
339
+ exec_timestamp: number;
340
+ }
341
+
342
+ export interface RollmanActionsResponse {
343
+ actions: RollmanActionExtendedInfo[];
344
+ }
345
+
346
+ export interface RollmanActionInfo {
347
+ action_id: number;
348
+ action_pb: Uint8Array;
349
+ exec_timestamp: number;
350
+ }
351
+
352
+ export interface RollmanActionExtendedInfo {
353
+ block_number?: number;
354
+ action_id: number;
355
+ action_pb: Uint8Array;
356
+ }
357
+
358
+ export interface MarketsStatsResponse {
359
+ markets: MarketStats[];
360
+ }
361
+
362
+ export interface MarketStats {
363
+ market_id: number;
364
+ index_price: [number, number];
365
+ volume_24h: number;
366
+ high_24h: number;
367
+ low_24h: number;
368
+ perp_stats?: PerpMarketStats;
369
+ }
370
+
371
+ export interface PerpMarketStats {
372
+ mark_price?: number;
373
+ funding_rate?: number;
374
+ next_funding_time?: Date;
375
+ open_interest?: number;
376
+ }
377
+
378
+ /**
379
+ * Converts a `FillMode` enum to its corresponding protobuf representation.
380
+ *
381
+ * @param x - The fill mode to convert.
382
+ * @returns The corresponding protobuf fill mode.
383
+ * @throws Will throw an error if provided with an invalid fill mode.
384
+ */
385
+ export function fillModeToProtoFillMode(x: FillMode): proto.FillMode {
386
+ if (x === FillMode.Limit) return proto.FillMode.LIMIT;
387
+ if (x === FillMode.PostOnly) return proto.FillMode.POST_ONLY;
388
+ if (x === FillMode.ImmediateOrCancel) {
389
+ return proto.FillMode.IMMEDIATE_OR_CANCEL;
390
+ }
391
+ if (x === FillMode.FillOrKill) return proto.FillMode.FILL_OR_KILL;
392
+ throw new Error("Invalid fill mode");
393
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,300 @@
1
+ import { Decimal } from "decimal.js";
2
+ import { ed25519 } from "@noble/curves/ed25519";
3
+ import { bls12_381 as bls } from "@noble/curves/bls12-381";
4
+ import { secp256k1 as secp } from "@noble/curves/secp256k1";
5
+ import { sha256 } from "@noble/hashes/sha256";
6
+ import { KeyType, type Market, type Token } from "./types";
7
+ import * as proto from "./gen/nord";
8
+ import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
9
+ import { ethers } from "ethers";
10
+ import fetch from "node-fetch";
11
+ import { RequestInfo, RequestInit, Response } from "node-fetch";
12
+
13
+ export const SESSION_TTL: bigint = 10n * 60n * 1000n * 10000n;
14
+ export const ZERO_DECIMAL = new Decimal(0);
15
+ export const MAX_BUFFER_LEN = 10_000;
16
+
17
+ const MAX_PAYLOAD_SIZE = 100 * 1024; // 100 kB
18
+
19
+ /** Any type convertible to bigint */
20
+ export type BigIntValue = bigint | number | string;
21
+
22
+ export function panic(message: string): never {
23
+ throw new Error(message);
24
+ }
25
+
26
+ export function assert(predicate: boolean, message?: string): void {
27
+ if (!predicate) panic(message ?? "Assertion violated");
28
+ }
29
+ /**
30
+ * Extracts value out of optional if it's defined, or throws error if it's not
31
+ * @param value Optional value to unwrap
32
+ * @param message Error message
33
+ * @returns Unwrapped value
34
+ */
35
+ export function optExpect<T>(value: T | undefined, message: string): T {
36
+ if (value === undefined) throw new Error(message);
37
+ return value as T;
38
+ }
39
+ /**
40
+ * Unwraps optional value with default error message
41
+ * @param value
42
+ * @returns
43
+ */
44
+ export function optUnwrap<T>(value: T | undefined): T {
45
+ return optExpect(value, "Optional contains no value");
46
+ }
47
+ /**
48
+ * Applies function to value if it's defined, or passes `undefined` through
49
+ * @param value Optional value to map
50
+ * @param mapFn Mapper function
51
+ * @returns Either mapped value or undefined
52
+ */
53
+ export function optMap<T, U>(
54
+ value: T | undefined,
55
+ mapFn: (arg: T) => U,
56
+ ): U | undefined {
57
+ return value !== undefined ? mapFn(value) : undefined;
58
+ }
59
+ /** Behaves same as `node-fetch/fetch` but throws if response is a failure
60
+ *
61
+ * @param url Request HTTP URL
62
+ * @param init Request parameters
63
+ * @returns Raw response if fetch succeeded
64
+ * @throws If response wasn't Ok
65
+ */
66
+ export async function checkedFetch(
67
+ url: RequestInfo,
68
+ init?: RequestInit,
69
+ ): Promise<Response> {
70
+ const resp = await fetch(url, init);
71
+ assert(resp.ok, `Request failed with ${resp.status}: ${resp.statusText}`);
72
+ return resp;
73
+ }
74
+
75
+ /**
76
+ * Signs an action using the specified secret key and key type.
77
+ * @param action - The action data to be signed.
78
+ * @param sk - Secret key used for signing the action.
79
+ * @param keyType - Type of the key used for signing.
80
+ * @returns A new Uint8Array containing the action followed by its signature.
81
+ */
82
+ export function signAction(
83
+ action: Uint8Array,
84
+ sk: Uint8Array,
85
+ keyType: KeyType,
86
+ ): Uint8Array {
87
+ let sig: Uint8Array;
88
+ if (keyType === KeyType.Ed25519) {
89
+ sig = ed25519.sign(action, sk);
90
+ } else if (keyType === KeyType.Bls12_381) {
91
+ sig = bls.sign(action, sk);
92
+ } else if (keyType === KeyType.Secp256k1) {
93
+ sig = secp.sign(sha256(action), sk).toCompactRawBytes();
94
+ } else {
95
+ throw new Error("Invalid key type");
96
+ }
97
+ return new Uint8Array([...action, ...sig]);
98
+ }
99
+
100
+ /**
101
+ * Constructs wallet signing function, usable with `NordUser` type
102
+ *
103
+ * @param walletKey Either raw signing key as bytes array or hex string prefixed with `"0x"`
104
+ * @returns Async function which accepts arbitrary message, generates its digets,
105
+ * then signs it with provided user wallet key and returns signature
106
+ * as hex string prefixed with `"0x"`
107
+ */
108
+ export function makeWalletSignFn(
109
+ walletKey: ethers.BytesLike,
110
+ ): (message: Uint8Array | string) => Promise<string> {
111
+ const signingKey = new ethers.SigningKey(walletKey);
112
+ return async (message) =>
113
+ signingKey.sign(ethers.hashMessage(message)).serialized;
114
+ }
115
+
116
+ function makeToScaledBigUint(params: {
117
+ precision: number;
118
+ exponent: number;
119
+ bits: number;
120
+ }): (x: Decimal.Value, decimals: number) => bigint {
121
+ const Dec = Decimal.clone({
122
+ precision: params.precision,
123
+ toExpPos: params.exponent,
124
+ toExpNeg: -params.exponent,
125
+ });
126
+
127
+ const Ten = new Dec(10);
128
+
129
+ const Max = new Dec(((1n << BigInt(params.bits)) - 1n).toString());
130
+
131
+ return (x, decimals) => {
132
+ const dec = new Dec(x);
133
+
134
+ if (dec.isZero()) {
135
+ return 0n;
136
+ }
137
+
138
+ if (dec.isNeg()) {
139
+ throw new Error(`Number is negative`);
140
+ }
141
+
142
+ const scaled = Ten.pow(decimals).mul(dec).truncated();
143
+ if (scaled.isZero()) {
144
+ throw new Error(
145
+ `Precision loss when converting ${dec} to scaled integer`,
146
+ );
147
+ }
148
+
149
+ if (scaled.greaterThan(Max)) {
150
+ throw new Error(
151
+ `Integer is out of range: ${scaled} exceeds limit ${Max}`,
152
+ );
153
+ }
154
+
155
+ return BigInt(scaled.toString());
156
+ };
157
+ }
158
+ /**
159
+ * Converts decimal value into rescaled 64-bit unsigned integer
160
+ * by scaling it up by specified number of decimal digits.
161
+ *
162
+ * Ensures that number won't accidentally become zero
163
+ * or exceed U64's value range
164
+ *
165
+ * @param x Decimal value to rescale
166
+ * @param decimals Number of decimal digits
167
+ * @returns Rescaled unsigned integer
168
+ */
169
+ export const toScaledU64 = makeToScaledBigUint({
170
+ bits: 64,
171
+ precision: 20,
172
+ exponent: 28,
173
+ });
174
+ /**
175
+ * Converts decimal value into rescaled 128-bit unsigned integer
176
+ * by scaling it up by specified number of decimal digits.
177
+ *
178
+ * Ensures that number won't accidentally become zero
179
+ * or exceed U128's value range
180
+ *
181
+ * @param x Decimal value to rescale
182
+ * @param decimals Number of decimal digits
183
+ * @returns Rescaled unsigned integer
184
+ */
185
+ export const toScaledU128 = makeToScaledBigUint({
186
+ bits: 128,
187
+ precision: 40,
188
+ exponent: 56,
189
+ });
190
+
191
+ const U64_MAX = (1n << 64n) - 1n;
192
+ const U128_MAX = (1n << 128n) - 1n;
193
+ /**
194
+ * Converts U128 into pair of U64 numbers, to pass it through protobuf
195
+ * @param value integer, must fit U128 limits
196
+ * @returns Pair of U64 integers which represent original number split in two
197
+ */
198
+ export function bigIntToProtoU128(value: bigint): proto.U128 {
199
+ if (value < 0n) {
200
+ throw new Error(`Negative number (${value})`);
201
+ }
202
+
203
+ if (value > U128_MAX) {
204
+ throw new Error(`U128 overflow (${value})`);
205
+ }
206
+
207
+ return {
208
+ lo: value & U64_MAX,
209
+ hi: (value >> 64n) & U64_MAX,
210
+ };
211
+ }
212
+
213
+ /**
214
+ * Encodes any protobuf message into a length-delimited format,
215
+ * i.e. prefixed with its length encoded as varint
216
+ * @param message message object
217
+ * @param coder associated coder object which implements `MessageFns` interface
218
+ * @returns Encoded message as Uint8Array, prefixed with its length
219
+ */
220
+ export function encodeLengthDelimited<T, M extends proto.MessageFns<T>>(
221
+ message: T,
222
+ coder: M,
223
+ ): Uint8Array {
224
+ const encoded = coder.encode(message).finish();
225
+ if (encoded.byteLength > MAX_PAYLOAD_SIZE) {
226
+ throw new Error(
227
+ `Encoded message size (${encoded.byteLength} bytes) is greater than max payload size (${MAX_PAYLOAD_SIZE} bytes).`,
228
+ );
229
+ }
230
+ const encodedLength = new BinaryWriter().uint32(encoded.byteLength).finish();
231
+ return new Uint8Array([...encodedLength, ...encoded]);
232
+ }
233
+
234
+ /**
235
+ * Decodes any protobuf message from a length-delimited format,
236
+ * i.e. prefixed with its length encoded as varint
237
+ *
238
+ * NB: Please note that due to limitations of Typescript type inference
239
+ * it requires to specify variable type explicitly:
240
+ *
241
+ * ```
242
+ * const foo: proto.Bar = decodeLengthDelimited(bytes, proto.Bar);
243
+ * ```
244
+ *
245
+ * @param bytes Byte array with encoded message
246
+ * @param coder associated coder object which implements `MessageFns` interface
247
+ * @returns Decoded Action as Uint8Array.
248
+ */
249
+ export function decodeLengthDelimited<T, M extends proto.MessageFns<T>>(
250
+ bytes: Uint8Array,
251
+ coder: M,
252
+ ): T {
253
+ const lengthReader = new BinaryReader(bytes);
254
+ const msgLength = lengthReader.uint32();
255
+ const startsAt = lengthReader.pos;
256
+
257
+ if (msgLength > MAX_PAYLOAD_SIZE) {
258
+ throw new Error(
259
+ `Encoded message size (${msgLength} bytes) is greater than max payload size (${MAX_PAYLOAD_SIZE} bytes).`,
260
+ );
261
+ }
262
+
263
+ if (startsAt + msgLength > bytes.byteLength) {
264
+ throw new Error(
265
+ `Encoded message size (${msgLength} bytes) is greater than remaining buffer size (${bytes.byteLength - startsAt} bytes).`,
266
+ );
267
+ }
268
+
269
+ return coder.decode(bytes.slice(startsAt, startsAt + msgLength));
270
+ }
271
+
272
+ export function checkPubKeyLength(keyType: KeyType, len: number): void {
273
+ if (keyType === KeyType.Bls12_381) {
274
+ throw new Error(
275
+ "Cannot create a user using Bls12_381, use Ed25119 or Secp256k1 instead.",
276
+ );
277
+ }
278
+
279
+ if (len !== 32 && keyType === KeyType.Ed25519) {
280
+ throw new Error("Ed25519 pubkeys must be 32 length.");
281
+ }
282
+
283
+ if (len !== 33 && keyType === KeyType.Secp256k1) {
284
+ throw new Error("Secp256k1 pubkeys must be 33 length.");
285
+ }
286
+ }
287
+
288
+ export function findMarket(markets: Market[], marketId: number): Market {
289
+ if (marketId < 0 || markets.length - 1 < marketId) {
290
+ throw new Error(`The market with marketId=${marketId} not found`);
291
+ }
292
+ return markets[marketId];
293
+ }
294
+
295
+ export function findToken(tokens: Token[], tokenId: number): Token {
296
+ if (tokenId < 0 || tokens.length - 1 < tokenId) {
297
+ throw new Error(`The token with tokenId=${tokenId} not found`);
298
+ }
299
+ return tokens[tokenId];
300
+ }