@n1xyz/nord-ts 0.1.7 → 0.1.8

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 (84) hide show
  1. package/dist/actions.js +39 -82
  2. package/dist/bundle.js +79181 -0
  3. package/dist/client/Nord.d.ts +2 -2
  4. package/dist/client/Nord.js +46 -78
  5. package/dist/client/NordAdmin.d.ts +2 -2
  6. package/dist/client/NordAdmin.js +57 -89
  7. package/dist/client/NordUser.js +118 -147
  8. package/dist/const.js +5 -8
  9. package/dist/error.js +7 -5
  10. package/dist/gen/nord_pb.js +88 -92
  11. package/dist/gen/openapi.d.ts +5 -6
  12. package/dist/gen/openapi.js +1 -2
  13. package/dist/index.js +10 -49
  14. package/dist/types.d.ts +1 -0
  15. package/dist/types.js +21 -60
  16. package/dist/utils.js +38 -86
  17. package/dist/websocket/NordWebSocketClient.js +12 -17
  18. package/dist/websocket/Subscriber.js +6 -7
  19. package/dist/websocket/events.js +1 -2
  20. package/dist/websocket/index.js +10 -15
  21. package/package.json +2 -3
  22. package/dist/api/client.d.ts +0 -14
  23. package/dist/api/client.js +0 -45
  24. package/dist/bridge/client.d.ts +0 -151
  25. package/dist/bridge/client.js +0 -434
  26. package/dist/bridge/const.d.ts +0 -23
  27. package/dist/bridge/const.js +0 -47
  28. package/dist/bridge/index.d.ts +0 -4
  29. package/dist/bridge/index.js +0 -23
  30. package/dist/bridge/types.d.ts +0 -120
  31. package/dist/bridge/types.js +0 -18
  32. package/dist/bridge/utils.d.ts +0 -64
  33. package/dist/bridge/utils.js +0 -131
  34. package/dist/gen/common.d.ts +0 -68
  35. package/dist/gen/common.js +0 -215
  36. package/dist/gen/nord.d.ts +0 -882
  37. package/dist/gen/nord.js +0 -6520
  38. package/dist/idl/bridge.d.ts +0 -569
  39. package/dist/idl/bridge.js +0 -8
  40. package/dist/idl/bridge.json +0 -1506
  41. package/dist/idl/index.d.ts +0 -607
  42. package/dist/idl/index.js +0 -8
  43. package/dist/nord/api/actions.d.ts +0 -126
  44. package/dist/nord/api/actions.js +0 -397
  45. package/dist/nord/api/core.d.ts +0 -16
  46. package/dist/nord/api/core.js +0 -81
  47. package/dist/nord/api/market.d.ts +0 -36
  48. package/dist/nord/api/market.js +0 -96
  49. package/dist/nord/api/metrics.d.ts +0 -67
  50. package/dist/nord/api/metrics.js +0 -229
  51. package/dist/nord/api/queries.d.ts +0 -46
  52. package/dist/nord/api/queries.js +0 -109
  53. package/dist/nord/api/triggers.d.ts +0 -7
  54. package/dist/nord/api/triggers.js +0 -38
  55. package/dist/nord/client/Nord.d.ts +0 -396
  56. package/dist/nord/client/Nord.js +0 -747
  57. package/dist/nord/client/NordAdmin.d.ts +0 -259
  58. package/dist/nord/client/NordAdmin.js +0 -395
  59. package/dist/nord/client/NordClient.d.ts +0 -33
  60. package/dist/nord/client/NordClient.js +0 -45
  61. package/dist/nord/client/NordUser.d.ts +0 -362
  62. package/dist/nord/client/NordUser.js +0 -781
  63. package/dist/nord/index.d.ts +0 -11
  64. package/dist/nord/index.js +0 -36
  65. package/dist/nord/models/Subscriber.d.ts +0 -37
  66. package/dist/nord/models/Subscriber.js +0 -25
  67. package/dist/nord/utils/NordError.d.ts +0 -35
  68. package/dist/nord/utils/NordError.js +0 -49
  69. package/src/actions.ts +0 -333
  70. package/src/client/Nord.ts +0 -934
  71. package/src/client/NordAdmin.ts +0 -484
  72. package/src/client/NordUser.ts +0 -1122
  73. package/src/const.ts +0 -34
  74. package/src/error.ts +0 -76
  75. package/src/gen/.gitkeep +0 -0
  76. package/src/gen/nord_pb.ts +0 -5053
  77. package/src/gen/openapi.ts +0 -2904
  78. package/src/index.ts +0 -11
  79. package/src/types.ts +0 -327
  80. package/src/utils.ts +0 -266
  81. package/src/websocket/NordWebSocketClient.ts +0 -316
  82. package/src/websocket/Subscriber.ts +0 -56
  83. package/src/websocket/events.ts +0 -31
  84. package/src/websocket/index.ts +0 -105
package/src/index.ts DELETED
@@ -1,11 +0,0 @@
1
- export * from "./types";
2
- export * from "./utils";
3
- export * from "./const";
4
- export * from "./error";
5
- export * from "./websocket/index";
6
- export * from "./client/Nord";
7
- export * from "./client/NordUser";
8
- export * from "./client/NordAdmin";
9
-
10
- export * as proto from "./gen/nord_pb";
11
- export * as openapi from "./gen/openapi";
package/src/types.ts DELETED
@@ -1,327 +0,0 @@
1
- import * as proto from "./gen/nord_pb";
2
- import type { components } from "./gen/openapi.ts";
3
- import Decimal from "decimal.js";
4
- import { toScaledU64 } from "./utils";
5
- import { Connection } from "@solana/web3.js";
6
-
7
- /**
8
- * Nord subscription type for trades or deltas
9
- */
10
- export type SubscriptionType = "trades" | "deltas" | "account";
11
-
12
- /**
13
- * Pattern for a valid Nord subscription
14
- * Format should be: "<type>@<parameter>"
15
- * Examples: "trades@BTCUSDC", "deltas@ETHUSDC", "account@42"
16
- */
17
- export type SubscriptionPattern = `${SubscriptionType}@${string}` | string;
18
-
19
- /**
20
- * Configuration options for the Nord client
21
- */
22
- export interface NordConfig {
23
- /** Base URL for the Nord web server */
24
- webServerUrl: string;
25
- /** App address */
26
- app: string;
27
- /** Solana connection */
28
- solanaConnection: Connection;
29
- /** Proton URL, defaults to webServerUrl */
30
- // TODO: this is ass. move to NordUser.
31
- protonUrl?: string;
32
- /**
33
- * Whether to initialize WebSockets on creation, defaults to true
34
- * @deprecated this is a funky api we're gonna be removing it
35
- */
36
- initWebSockets?: boolean;
37
- }
38
-
39
- export type MarketsInfo = components["schemas"]["MarketsInfo"];
40
- export type Market = MarketsInfo["markets"][number];
41
- export type Token = MarketsInfo["tokens"][number];
42
- export type Account = components["schemas"]["Account"];
43
- export type TradesResponse =
44
- components["schemas"]["PageResult_for_String_and_Trade"];
45
- export type User = components["schemas"]["User"];
46
- export type OrderbookResponse = components["schemas"]["OrderbookInfo"];
47
- export type MarketStats = components["schemas"]["MarketStats"];
48
- export type OrderbookInfo = components["schemas"]["OrderbookInfo"];
49
- export type MarketStatsFromApi = components["schemas"]["MarketStats"];
50
- export type TradeFromApi = components["schemas"]["Trade"];
51
- // Generic PageResult type - note that K and V must match existing schema keys
52
- export type PageResult<K extends string, V extends string> = K extends "String"
53
- ? V extends "OrderInfo"
54
- ? components["schemas"]["PageResult_for_String_and_OrderInfo"]
55
- : V extends "Trade"
56
- ? components["schemas"]["PageResult_for_String_and_Trade"]
57
- : never
58
- : never;
59
- export type PageResultStringOrderInfo =
60
- components["schemas"]["PageResult_for_String_and_OrderInfo"];
61
- export type PageResultStringTrade =
62
- components["schemas"]["PageResult_for_String_and_Trade"];
63
- export type OrderInfoFromApi = components["schemas"]["OrderInfo"];
64
- export type OpenOrder = components["schemas"]["OpenOrder"];
65
- export type Balance = components["schemas"]["Balance"];
66
- export type PositionSummary = components["schemas"]["PositionSummary"];
67
- export type PerpPosition = components["schemas"]["PerpPosition"];
68
- export type AccountMarginsView = components["schemas"]["AccountMarginsView"];
69
- export type SideSummary = components["schemas"]["SideSummary"];
70
- export type UserSession = components["schemas"]["UserSession"];
71
- export type ActionsItem = components["schemas"]["ActionsItem"];
72
- export type FillRole = components["schemas"]["FillRole"];
73
- export type PerpMarketStatsFromApi = components["schemas"]["PerpMarketStats"];
74
- export type SideFromApi = components["schemas"]["Side"];
75
- export type FillModeFromApi = components["schemas"]["FillMode"];
76
- export type PlacementOrigin = components["schemas"]["PlacementOrigin"];
77
- export type FinalizationReason = components["schemas"]["FinalizationReason"];
78
- export type AccountPnlQuery = components["schemas"]["AccountPnlQuery"];
79
- export type AccountPnl = components["schemas"]["AccountPnl"];
80
- export type AccountPnlPage =
81
- components["schemas"]["PageResult_for_uint64_and_AccountPnl"];
82
- export type AccountTriggerInfo = components["schemas"]["AccountTriggerInfo"];
83
- export type TriggerHistoryPage =
84
- components["schemas"]["PageResult_for_uint64_and_HistoryTriggerInfo"];
85
- export type HistoryTriggerQuery = components["schemas"]["AccountTriggersQuery"];
86
- export type FeeTierConfig = components["schemas"]["FeeTierConfig"];
87
- export type FeeTierId = components["schemas"]["FeeTierId"];
88
- export type TokenStats = components["schemas"]["TokenStats"];
89
- export type AccountFeeTier = components["schemas"]["AccountFeeTier"];
90
- export type AccountFeeTierPage =
91
- components["schemas"]["PageResult_for_uint32_and_AccountFeeTier"];
92
-
93
- /**
94
- * Configuration options for the Nord client
95
- */
96
- export interface TokenInfo {
97
- address: string;
98
- precision: number;
99
- tokenId: number;
100
- name: string;
101
- }
102
-
103
- export interface Order {
104
- orderId: number;
105
- isLong: boolean;
106
- size: number;
107
- price: number;
108
- marketId: number;
109
- }
110
-
111
- export enum Side {
112
- Ask = "ask",
113
- Bid = "bid",
114
- }
115
-
116
- export enum FillMode {
117
- Limit,
118
- PostOnly,
119
- ImmediateOrCancel,
120
- FillOrKill,
121
- }
122
-
123
- export enum TriggerKind {
124
- StopLoss = 0,
125
- TakeProfit = 1,
126
- }
127
-
128
- export enum TriggerStatus {
129
- Active = 0,
130
- Success = 1,
131
- Cancel = 2,
132
- Remove = 4,
133
- }
134
-
135
- export interface SubscriberConfig {
136
- streamURL: string;
137
- maxBufferLen?: number;
138
- }
139
-
140
- export interface DeltaEvent {
141
- last_update_id: number;
142
- update_id: number;
143
- market_symbol: string;
144
- asks: OrderbookEntry[];
145
- bids: OrderbookEntry[];
146
- }
147
-
148
- export interface StreamTrade {
149
- side: Side;
150
- price: number;
151
- size: number;
152
- order_id: number;
153
- }
154
-
155
- export interface Trades {
156
- last_update_id: number;
157
- update_id: number;
158
- market_symbol: string;
159
- trades: StreamTrade[];
160
- }
161
-
162
- export interface LocalOrderInfo {
163
- id: number;
164
- reduce_only: boolean;
165
- limit_price: number;
166
- size: number;
167
- account_id: number;
168
- sender_tracking_id?: number;
169
- }
170
-
171
- export interface HashMap<T> {
172
- [key: number]: T;
173
- }
174
-
175
- export interface ActionResponse {
176
- actionId: number;
177
- action: proto.Action;
178
- physicalExecTime: Date;
179
- }
180
-
181
- /**
182
- * Converts a `FillMode` enum to its corresponding protobuf representation.
183
- *
184
- * @param x - The fill mode to convert.
185
- * @returns The corresponding protobuf fill mode.
186
- * @throws Will throw an error if provided with an invalid fill mode.
187
- */
188
- export function fillModeToProtoFillMode(x: FillMode): proto.FillMode {
189
- if (x === FillMode.Limit) return proto.FillMode.LIMIT;
190
- if (x === FillMode.PostOnly) return proto.FillMode.POST_ONLY;
191
- if (x === FillMode.ImmediateOrCancel) {
192
- return proto.FillMode.IMMEDIATE_OR_CANCEL;
193
- }
194
- if (x === FillMode.FillOrKill) return proto.FillMode.FILL_OR_KILL;
195
- throw new Error("Invalid fill mode");
196
- }
197
-
198
- /**
199
- * Orderbook entry representing price and size
200
- */
201
- export interface OrderbookEntry {
202
- price: number;
203
- size: number;
204
- }
205
-
206
- /**
207
- * Query parameters for orderbook
208
- *
209
- * Note: While you can provide either symbol or market_id, the API endpoint only accepts market_id.
210
- * If you provide a symbol, it will be converted to a market_id internally.
211
- */
212
- export interface OrderbookQuery {
213
- symbol?: string;
214
- marketId?: number;
215
- }
216
-
217
- /**
218
- * Response for timestamp query
219
- */
220
- export interface TimestampResponse {
221
- timestamp: number; // engine's current logical timestamp
222
- }
223
-
224
- /**
225
- * Response for action nonce query
226
- */
227
- export interface ActionNonceResponse {
228
- nonce: number; // next expected action nonce
229
- }
230
-
231
- /**
232
- * WebSocket message types
233
- */
234
- export enum WebSocketMessageType {
235
- TradeUpdate = "trades",
236
- DeltaUpdate = "delta",
237
- AccountUpdate = "account",
238
- }
239
-
240
- /**
241
- * WebSocket trade update message
242
- */
243
- export interface WebSocketTradeUpdate {
244
- e: WebSocketMessageType.TradeUpdate;
245
- symbol: string;
246
- trades: StreamTrade[];
247
- timestamp: number;
248
- }
249
-
250
- /**
251
- * WebSocket delta update message
252
- */
253
- export interface WebSocketDeltaUpdate {
254
- e: WebSocketMessageType.DeltaUpdate;
255
- last_update_id: number;
256
- update_id: number;
257
- market_symbol: string;
258
- asks: OrderbookEntry[];
259
- bids: OrderbookEntry[];
260
- timestamp: number;
261
- }
262
-
263
- /**
264
- * WebSocket user update message
265
- */
266
- export interface WebSocketAccountUpdate {
267
- e: WebSocketMessageType.AccountUpdate;
268
- accountId: number;
269
- account: Account;
270
- timestamp: number;
271
- }
272
-
273
- export type WebSocketMessage =
274
- | WebSocketTradeUpdate
275
- | WebSocketDeltaUpdate
276
- | WebSocketAccountUpdate;
277
-
278
- export interface SPLTokenInfo {
279
- mint: string;
280
- precision: number;
281
- tokenId: number;
282
- name: string;
283
- }
284
-
285
- // Positive decimal price and size.
286
- // Example:
287
- // ```
288
- // const limit = new QuoteSize(new Decimal(114000), new Decimal(0.00035)),
289
- //```
290
- // Gives 40$ USD limit.
291
- //
292
- // Given price is same(or very close) to the market price,
293
- // limit gives size tick as close as possible to settlemnt size tick.
294
-
295
- // If you want to get smaller tick on client (on server it will not change),
296
- // do `new QuoteSize(new Decimal(114000/2), new Decimal(0.00070))`.
297
- // It will be 40$ limit, but may help if BTC suddently moves fast.
298
- export class QuoteSize {
299
- price: Decimal;
300
- size: Decimal;
301
- /// Input can be only positive values.
302
- constructor(quotePrice: Decimal.Value, quoteSize: Decimal.Value) {
303
- const p = new Decimal(quotePrice);
304
- const s = new Decimal(quoteSize);
305
- if (!p.isPositive() || !s.isPositive()) {
306
- throw new Error("quotePrice and quoteSize must be positive");
307
- }
308
- this.price = p;
309
- this.size = s;
310
- }
311
-
312
- // USD value of limit, use for debug
313
- value(): Decimal {
314
- return this.price.mul(this.size);
315
- }
316
-
317
- // Converts to wire format to be send to server, scaling price and size according to market decimals.
318
- toWire(
319
- marketPriceDecimals: number,
320
- marketSizeDecimals: number,
321
- ): { price: bigint; size: bigint } {
322
- return {
323
- price: toScaledU64(this.price, marketPriceDecimals),
324
- size: toScaledU64(this.size, marketSizeDecimals),
325
- };
326
- }
327
- }
package/src/utils.ts DELETED
@@ -1,266 +0,0 @@
1
- import { Decimal } from "decimal.js";
2
- import { type Market, type Token } from "./types";
3
- import { sizeDelimitedPeek } from "@bufbuild/protobuf/wire";
4
- import { fromBinary, type Message } from "@bufbuild/protobuf";
5
- import type { GenMessage } from "@bufbuild/protobuf/codegenv2";
6
- import { ethers } from "ethers";
7
- import fetch from "node-fetch";
8
- import { RequestInfo, RequestInit, Response } from "node-fetch";
9
- import { Keypair } from "@solana/web3.js";
10
- import bs58 from "bs58";
11
- import * as solana from "@solana/web3.js";
12
-
13
- export const SESSION_TTL: bigint = 60n * 60n * 24n * 30n;
14
- export const ZERO_DECIMAL = new Decimal(0);
15
- export const MAX_BUFFER_LEN = 10_000;
16
-
17
- // Max size of data returned from Nord endpoints
18
- const MAX_PAYLOAD_SIZE = 100 * 1024; // 100 kB
19
-
20
- /** Any type convertible to bigint */
21
- export type BigIntValue = bigint | number | string;
22
-
23
- export function panic(message: string): never {
24
- throw new Error(message);
25
- }
26
-
27
- export function isRfc3339(s: string): boolean {
28
- const REGEX =
29
- /^((?:(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}(?:\.\d+)?))(Z|[\+-]\d{2}:\d{2})?)$/;
30
- return REGEX.test(s);
31
- }
32
-
33
- export function assert(
34
- predicate: boolean,
35
- message?: string,
36
- ): asserts predicate {
37
- if (!predicate) panic(message ?? "Assertion violated");
38
- }
39
- /**
40
- * Extracts value out of optional if it's defined, or throws error if it's not
41
- * @param value Optional value to unwrap
42
- * @param message Error message
43
- * @returns Unwrapped value
44
- */
45
- export function optExpect<T>(value: T | undefined, message: string): T {
46
- if (value === undefined) throw new Error(message);
47
- return value as T;
48
- }
49
- /** Behaves same as `node-fetch/fetch` but throws if response is a failure
50
- *
51
- * @param url Request HTTP URL
52
- * @param init Request parameters
53
- * @returns Raw response if fetch succeeded
54
- * @throws If response wasn't Ok
55
- */
56
- export async function checkedFetch(
57
- url: RequestInfo,
58
- init?: RequestInit,
59
- ): Promise<Response> {
60
- const resp = await fetch(url, init);
61
- assert(resp.ok, `Request failed with ${resp.status}: ${resp.statusText}`);
62
- return resp;
63
- }
64
-
65
- /**
66
- * Constructs wallet signing function, usable with `NordUser` type
67
- *
68
- * @param walletKey Either raw signing key as bytes array or hex string prefixed with `"0x"`
69
- * @returns Async function which accepts arbitrary message, generates its digets,
70
- * then signs it with provided user wallet key and returns signature
71
- * as hex string prefixed with `"0x"`
72
- */
73
- export function makeWalletSignFn(
74
- walletKey: ethers.BytesLike,
75
- ): (message: Uint8Array | string) => Promise<string> {
76
- const signingKey = new ethers.SigningKey(walletKey);
77
- return async (message) =>
78
- signingKey.sign(ethers.hashMessage(message)).serialized;
79
- }
80
-
81
- // Returned numbers do fit into specified bits range, or error is thrown.
82
- function makeToScaledBigUint(params: {
83
- precision: number;
84
- exponent: number;
85
- bits: number;
86
- }): (x: Decimal.Value, decimals: number) => bigint {
87
- const Dec = Decimal.clone({
88
- precision: params.precision,
89
- toExpPos: params.exponent,
90
- toExpNeg: -params.exponent,
91
- });
92
-
93
- const Ten = new Dec(10);
94
-
95
- const Max = new Dec(((1n << BigInt(params.bits)) - 1n).toString());
96
-
97
- return (x, decimals) => {
98
- const dec = new Dec(x);
99
-
100
- if (dec.isZero()) {
101
- return 0n;
102
- }
103
-
104
- if (dec.isNeg()) {
105
- throw new Error(`Number is negative`);
106
- }
107
-
108
- const scaled = Ten.pow(decimals).mul(dec).truncated();
109
- if (scaled.isZero()) {
110
- throw new Error(
111
- `Precision loss when converting ${dec} to scaled integer`,
112
- );
113
- }
114
-
115
- if (scaled.greaterThan(Max)) {
116
- throw new Error(
117
- `Integer is out of range: ${scaled} exceeds limit ${Max}`,
118
- );
119
- }
120
-
121
- return BigInt(scaled.toString());
122
- };
123
- }
124
- /**
125
- * Converts decimal value into rescaled 64-bit unsigned integer
126
- * by scaling it up by specified number of decimal digits.
127
- *
128
- * Ensures that number won't accidentally become zero
129
- * or exceed U64's value range
130
- *
131
- * @param x Decimal value to rescale
132
- * @param decimals Number of decimal digits
133
- * @returns Rescaled unsigned integer
134
- */
135
- export const toScaledU64 = makeToScaledBigUint({
136
- bits: 64,
137
- precision: 20,
138
- exponent: 28,
139
- });
140
- /**
141
- * Converts decimal value into rescaled 128-bit unsigned integer
142
- * by scaling it up by specified number of decimal digits.
143
- *
144
- * Ensures that number won't accidentally become zero
145
- * or exceed U128's value range
146
- *
147
- * @param x Decimal value to rescale
148
- * @param decimals Number of decimal digits
149
- * @returns Rescaled unsigned integer
150
- */
151
- export const toScaledU128 = makeToScaledBigUint({
152
- bits: 128,
153
- precision: 40,
154
- exponent: 56,
155
- });
156
-
157
- /**
158
- * Decodes any protobuf message from a length-delimited format,
159
- * i.e. prefixed with its length encoded as varint
160
- *
161
- * @param bytes Byte array with encoded message
162
- * @param schema Message schema for decoding
163
- * @returns Decoded message
164
- */
165
- export function decodeLengthDelimited<T extends Message>(
166
- bytes: Uint8Array,
167
- schema: GenMessage<T>,
168
- ): T {
169
- // use sizeDelimitedPeek to extract the message length and offset
170
- const peekResult = sizeDelimitedPeek(bytes);
171
-
172
- if (peekResult.size === null || peekResult.offset === null) {
173
- throw new Error("Failed to parse size-delimited message");
174
- }
175
-
176
- if (peekResult.size > MAX_PAYLOAD_SIZE) {
177
- throw new Error(
178
- `Encoded message size (${peekResult.size} bytes) is greater than max payload size (${MAX_PAYLOAD_SIZE} bytes).`,
179
- );
180
- }
181
-
182
- if (peekResult.offset + peekResult.size > bytes.length) {
183
- throw new Error(
184
- `Encoded message size (${peekResult.size} bytes) is greater than remaining buffer size (${bytes.length - peekResult.offset} bytes).`,
185
- );
186
- }
187
-
188
- // decode the message using the offset and size from peek
189
- return fromBinary(
190
- schema,
191
- bytes.slice(peekResult.offset, peekResult.offset + peekResult.size),
192
- );
193
- }
194
-
195
- export function decodeHex(value: string): Uint8Array {
196
- const hex = value.startsWith("0x") ? value.slice(2) : value;
197
- return Uint8Array.from(Buffer.from(hex, "hex"));
198
- }
199
-
200
- export function findMarket(markets: Market[], marketId: number): Market {
201
- if (marketId < 0 || markets.length - 1 < marketId) {
202
- throw new Error(`The market with marketId=${marketId} not found`);
203
- }
204
- return markets[marketId];
205
- }
206
-
207
- export function findToken(tokens: Token[], tokenId: number): Token {
208
- if (tokenId < 0 || tokens.length - 1 < tokenId) {
209
- throw new Error(`The token with tokenId=${tokenId} not found`);
210
- }
211
- return tokens[tokenId];
212
- }
213
-
214
- export function keypairFromPrivateKey(
215
- privateKey: string | Uint8Array,
216
- ): Keypair {
217
- if (typeof privateKey === "string") {
218
- if (!privateKey.startsWith("0x")) {
219
- return Keypair.fromSecretKey(bs58.decode(privateKey));
220
- }
221
- const hex = privateKey.startsWith("0x") ? privateKey.slice(2) : privateKey;
222
- const bytes = new Uint8Array(
223
- hex.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16)),
224
- );
225
- return Keypair.fromSecretKey(bytes);
226
- }
227
- return Keypair.fromSecretKey(privateKey);
228
- }
229
-
230
- export async function signUserPayload({
231
- payload,
232
- user,
233
- signTransaction,
234
- }: Readonly<{
235
- payload: Uint8Array;
236
- user: solana.PublicKey;
237
- signTransaction: (tx: solana.Transaction) => Promise<solana.Transaction>;
238
- }>): Promise<Uint8Array> {
239
- const tx = new solana.Transaction({
240
- blockhash: bs58.encode(new Uint8Array(32)),
241
- lastValidBlockHeight: 0,
242
- feePayer: user,
243
- });
244
- tx.add(
245
- new solana.TransactionInstruction({
246
- keys: [],
247
- programId: user,
248
- data: Buffer.from(payload),
249
- }),
250
- );
251
- const signedTx = await signTransaction(tx);
252
- const sig = signedTx.signatures[0];
253
- assert(
254
- sig.signature !== null,
255
- "signature must be non-null; check your signTransaction function",
256
- );
257
- assert(
258
- sig.signature.length === 64, //.
259
- "signature must be 64 bytes",
260
- );
261
- assert(
262
- sig.publicKey.equals(user),
263
- `signature is for ${sig.publicKey}, expected ${user}`,
264
- );
265
- return sig.signature;
266
- }