@n1xyz/nord-ts 0.1.3 → 0.1.5

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.
@@ -56,11 +56,10 @@ class Nord {
56
56
  *
57
57
  * @param config - Configuration options for the Nord client
58
58
  * @param config.webServerUrl - Base URL for the Nord web server
59
- * @param config.bridgeVk - Bridge verification key
60
59
  * @param config.solanaUrl - Solana cluster URL
61
60
  * @throws {Error} If required configuration is missing
62
61
  */
63
- constructor({ bridgeVk, solanaUrl, webServerUrl, protonClient, }) {
62
+ constructor({ solanaUrl, webServerUrl, protonClient, }) {
64
63
  /** Available markets */
65
64
  this.markets = [];
66
65
  /** Available tokens */
@@ -68,7 +67,6 @@ class Nord {
68
67
  /** Map of symbol to market_id */
69
68
  this.symbolToMarketId = new Map();
70
69
  this.webServerUrl = webServerUrl;
71
- this.bridgeVk = bridgeVk;
72
70
  this.solanaUrl = solanaUrl;
73
71
  this.protonClient = protonClient;
74
72
  this.httpClient = (0, openapi_fetch_1.default)({ baseUrl: webServerUrl });
@@ -179,24 +177,22 @@ class Nord {
179
177
  *
180
178
  * @param nordConfig - Configuration options for the Nord client
181
179
  * @param nordConfig.webServerUrl - Base URL for the Nord web server
182
- * @param nordConfig.bridgeVk - Bridge verification key
180
+ * @param nordConfig.app - App address
183
181
  * @param nordConfig.solanaUrl - Solana cluster URL
184
182
  * @returns Initialized Nord client
185
183
  * @throws {NordError} If initialization fails
186
184
  */
187
- static async initNord({ bridgeVk: bridgeVk_, solanaUrl, webServerUrl, }) {
185
+ static async initNord({ app, solanaUrl, webServerUrl, }) {
188
186
  // TODO: we should parametrize the connectionn not have it done here.
189
187
  // this is a dogshit api, only here to be compatible with the shitty
190
188
  // vibecoded code and not break zero one team's workflow.
191
189
  const connection = new web3_js_1.Connection(solanaUrl, { commitment: "confirmed" });
192
- const bridgeVk = new web3_js_1.PublicKey(bridgeVk_);
193
190
  const protonClient = await proton_1.ProtonClient.init({
194
191
  protonUrl: webServerUrl,
195
- bridgeVk,
192
+ app: new web3_js_1.PublicKey(app),
196
193
  solConn: connection,
197
194
  });
198
195
  const nord = new Nord({
199
- bridgeVk,
200
196
  protonClient,
201
197
  solanaUrl,
202
198
  webServerUrl,
@@ -488,6 +484,29 @@ class Nord {
488
484
  async getInfo() {
489
485
  return await this.GET("/info", {});
490
486
  }
487
+ /**
488
+ * Fetch the current fee tier brackets configured on Nord.
489
+ *
490
+ * @returns Array of fee tier identifiers paired with their configuration
491
+ * @throws {NordError} If the request fails
492
+ */
493
+ async getFeeBrackets() {
494
+ return await this.GET("/fee/brackets/info", {});
495
+ }
496
+ /**
497
+ * Retrieve the fee tier assigned to a specific account.
498
+ *
499
+ * @param accountId - Account identifier to query
500
+ * @returns Fee tier details for the requested account
501
+ * @throws {NordError} If the request fails
502
+ */
503
+ async getAccountFeeTier(accountId) {
504
+ return await this.GET("/account/{account_id}/fee/tier", {
505
+ params: {
506
+ path: { account_id: accountId },
507
+ },
508
+ });
509
+ }
491
510
  /**
492
511
  * Get account information
493
512
  *
@@ -502,6 +521,66 @@ class Nord {
502
521
  },
503
522
  });
504
523
  }
524
+ /**
525
+ * Get the public key associated with an account id.
526
+ *
527
+ * @param accountId - Account id to query
528
+ * @returns Base58-encoded account public key
529
+ * @throws {NordError} If the request fails
530
+ */
531
+ async getAccountPubkey(accountId) {
532
+ return await this.GET("/account/{account_id}/pubkey", {
533
+ params: {
534
+ path: { account_id: accountId },
535
+ },
536
+ });
537
+ }
538
+ /**
539
+ * Get the withdrawal fee charged for an account.
540
+ *
541
+ * @param accountId - Account id to query
542
+ * @returns Withdrawal fee quoted in quote token units
543
+ * @throws {NordError} If the request fails
544
+ */
545
+ async getAccountWithdrawalFee(accountId) {
546
+ return await this.GET("/account/{account_id}/fees/withdrawal", {
547
+ params: {
548
+ path: { account_id: accountId },
549
+ },
550
+ });
551
+ }
552
+ /**
553
+ * Get open orders for an account.
554
+ *
555
+ * @param accountId - Account id to query
556
+ * @param query - Optional pagination parameters
557
+ * @returns Page of orders keyed by client order id
558
+ * @throws {NordError} If the request fails
559
+ */
560
+ async getAccountOrders(accountId, query) {
561
+ return await this.GET("/account/{account_id}/orders", {
562
+ params: {
563
+ path: { account_id: accountId },
564
+ query: {
565
+ startInclusive: query?.startInclusive,
566
+ pageSize: query?.pageSize,
567
+ },
568
+ },
569
+ });
570
+ }
571
+ /**
572
+ * List account fee tiers with pagination support.
573
+ */
574
+ async getAccountsFeeTiers(query) {
575
+ return await this.GET("/accounts/fee-tiers", {
576
+ params: {
577
+ query: {
578
+ startInclusive: query?.startInclusive ?? undefined,
579
+ pageSize: query?.pageSize ?? undefined,
580
+ },
581
+ },
582
+ });
583
+ }
505
584
  /**
506
585
  * Get profit and loss history for an account
507
586
  *
@@ -535,6 +614,71 @@ class Nord {
535
614
  },
536
615
  });
537
616
  }
617
+ /**
618
+ * Fetch the per-market fee quote for an account.
619
+ *
620
+ * @param params - Market id, fee kind, and account id to quote
621
+ * @returns Fee in quote token units (negative means fee is charged)
622
+ * @throws {NordError} If the request fails
623
+ */
624
+ async getMarketFee({ marketId, feeKind, accountId, }) {
625
+ return await this.GET("/market/{market_id}/fees/{fee_kind}/{account_id}", {
626
+ params: {
627
+ path: {
628
+ market_id: marketId,
629
+ fee_kind: feeKind,
630
+ account_id: accountId,
631
+ },
632
+ },
633
+ });
634
+ }
635
+ /**
636
+ * Fetch token statistics such as index price and oracle metadata.
637
+ *
638
+ * @param tokenId - Token identifier
639
+ * @returns Token stats
640
+ * @throws {NordError} If the request fails
641
+ */
642
+ async getTokenStats(tokenId) {
643
+ return await this.GET("/tokens/{token_id}/stats", {
644
+ params: {
645
+ path: { token_id: tokenId },
646
+ },
647
+ });
648
+ }
649
+ /**
650
+ * Get order summary by order id.
651
+ *
652
+ * @param orderId - Order identifier
653
+ * @returns Order information
654
+ * @throws {NordError} If the request fails
655
+ */
656
+ async getOrder(orderId) {
657
+ return await this.GET("/order/{order_id}", {
658
+ params: {
659
+ path: { order_id: orderId },
660
+ },
661
+ });
662
+ }
663
+ /**
664
+ * Get trade history for a specific order.
665
+ *
666
+ * @param orderId - Order identifier
667
+ * @param query - Optional pagination parameters
668
+ * @returns Page of trades associated with the order
669
+ * @throws {NordError} If the request fails
670
+ */
671
+ async getOrderTrades(orderId, query) {
672
+ return await this.GET("/order/{order_id}/trades", {
673
+ params: {
674
+ path: { order_id: orderId },
675
+ query: {
676
+ startInclusive: query?.startInclusive,
677
+ pageSize: query?.pageSize,
678
+ },
679
+ },
680
+ });
681
+ }
538
682
  /**
539
683
  * Check if an account exists for the given address
540
684
  *
@@ -545,5 +689,59 @@ class Nord {
545
689
  async accountExists(pubkey) {
546
690
  return !!(await this.getUser({ pubkey }));
547
691
  }
692
+ /**
693
+ * Fetch active triggers for an account.
694
+ *
695
+ * @param params Optional parameters containing an explicit account id.
696
+ * @throws {NordError} If no account can be resolved or the request fails.
697
+ */
698
+ async getAccountTriggers(params) {
699
+ const accountId = params?.accountId;
700
+ if (accountId == null) {
701
+ throw new NordError_1.NordError("Account ID is undefined. Make sure to call updateAccountId() before requesting triggers.");
702
+ }
703
+ try {
704
+ const triggers = await this.GET("/account/{account_id}/triggers", {
705
+ params: {
706
+ path: { account_id: accountId },
707
+ },
708
+ });
709
+ return triggers ?? [];
710
+ }
711
+ catch (error) {
712
+ throw new NordError_1.NordError("Failed to fetch account triggers", { cause: error });
713
+ }
714
+ }
715
+ /**
716
+ * Fetch trigger history for an account.
717
+ *
718
+ * @param params Optional parameters with account id and history query filters.
719
+ * @throws {NordError} If no account can be resolved or the request fails.
720
+ */
721
+ async getAccountTriggerHistory(params) {
722
+ const accountId = params?.accountId;
723
+ if (accountId == null) {
724
+ throw new NordError_1.NordError("Account ID is undefined. Make sure to call updateAccountId() before requesting trigger history.");
725
+ }
726
+ const { accountId: _, ...query } = params;
727
+ try {
728
+ return await this.GET("/account/{account_id}/triggers/history", {
729
+ params: {
730
+ path: { account_id: accountId },
731
+ query: {
732
+ since: query.since,
733
+ until: query.until,
734
+ pageSize: query.pageSize,
735
+ startInclusive: query.startInclusive,
736
+ },
737
+ },
738
+ });
739
+ }
740
+ catch (error) {
741
+ throw new NordError_1.NordError("Failed to fetch account trigger history", {
742
+ cause: error,
743
+ });
744
+ }
745
+ }
548
746
  }
549
747
  exports.Nord = Nord;
@@ -0,0 +1,236 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import * as proto from "../../gen/nord_pb";
3
+ import { Nord } from "./Nord";
4
+ import { FeeTierConfig } from "../../gen/nord_pb";
5
+ /**
6
+ * Parameters required to register a new token via the admin API.
7
+ */
8
+ export interface CreateTokenParams {
9
+ tokenDecimals: number;
10
+ weightBps: number;
11
+ viewSymbol: string;
12
+ oracleSymbol: string;
13
+ mintAddr: PublicKey;
14
+ }
15
+ /**
16
+ * Parameters used when creating a new market.
17
+ */
18
+ export interface CreateMarketParams {
19
+ sizeDecimals: number;
20
+ priceDecimals: number;
21
+ imfBps: number;
22
+ cmfBps: number;
23
+ mmfBps: number;
24
+ marketType: proto.MarketType;
25
+ viewSymbol: string;
26
+ oracleSymbol: string;
27
+ baseTokenId: number;
28
+ }
29
+ /**
30
+ * Configuration for updating the Wormhole guardian set on the oracle.
31
+ */
32
+ export interface PythSetWormholeGuardiansParams {
33
+ guardianSetIndex: number;
34
+ addresses: string[];
35
+ }
36
+ /**
37
+ * Parameters required to link an oracle symbol to a Pyth price feed.
38
+ */
39
+ export interface PythSetSymbolFeedParams {
40
+ oracleSymbol: string;
41
+ priceFeedId: string;
42
+ }
43
+ /**
44
+ * Identifies a market that should be frozen.
45
+ */
46
+ export interface FreezeMarketParams {
47
+ marketId: number;
48
+ }
49
+ /**
50
+ * Identifies a market that should be unfrozen.
51
+ */
52
+ export interface UnfreezeMarketParams {
53
+ marketId: number;
54
+ }
55
+ /**
56
+ * Parameters for adding a new fee tier.
57
+ */
58
+ export interface AddFeeTierParams {
59
+ config: FeeTierConfig;
60
+ }
61
+ /**
62
+ * Parameters for updating an existing fee tier.
63
+ */
64
+ export interface UpdateFeeTierParams {
65
+ tierId: number;
66
+ config: FeeTierConfig;
67
+ }
68
+ /**
69
+ * Administrative client capable of submitting privileged configuration actions.
70
+ */
71
+ export declare class NordAdmin {
72
+ private readonly nord;
73
+ private readonly signFn;
74
+ private constructor();
75
+ /** Create a new admin client.
76
+ *
77
+ * @param nord - Nord instance
78
+ * @param signFn - Function to sign messages with the admin's wallet.
79
+ *
80
+ * `signFn` must sign the _hex-encoded_ message, not the raw message itself, for
81
+ * the purpose of being compatible with Solana wallets.
82
+ *
83
+ * In practice, you will do something along the lines of:
84
+ *
85
+ * ```typescript
86
+ * (x) => wallet.signMessage(new TextEncoder().encode(x.toHex()));
87
+ * ```
88
+ *
89
+ * For a software signing key, this might look more like:
90
+ *
91
+ * ```typescript
92
+ * (x) => nacl.sign.detached(new TextEncoder().encode(x.toHex()), sk);
93
+ * ``
94
+ *
95
+ * where `nacl` is the tweetnacl library.
96
+ */
97
+ static new({ nord, signFn, }: Readonly<{
98
+ nord: Nord;
99
+ signFn: (m: Uint8Array) => Promise<Uint8Array>;
100
+ }>): NordAdmin;
101
+ /**
102
+ * Submit an action and append the admin signature before sending it to Nord.
103
+ *
104
+ * @param kind - Action payload describing the admin request
105
+ * @throws {NordError} If signing or submission fails
106
+ */
107
+ private submitAction;
108
+ /**
109
+ * Register a new token that can be listed on Nord.
110
+ *
111
+ * @param params - Token configuration values
112
+ * @returns Action identifier and resulting token metadata
113
+ * @throws {NordError} If the action submission fails
114
+ */
115
+ createToken({ tokenDecimals, weightBps, viewSymbol, oracleSymbol, mintAddr, }: CreateTokenParams): Promise<{
116
+ actionId: bigint;
117
+ } & proto.Receipt_InsertTokenResult>;
118
+ /**
119
+ * Open a new market with the provided trading parameters.
120
+ *
121
+ * @param params - Market configuration to apply
122
+ * @returns Action identifier and resulting market metadata
123
+ * @throws {NordError} If the action submission fails
124
+ */
125
+ createMarket(params: CreateMarketParams): Promise<{
126
+ actionId: bigint;
127
+ } & proto.Receipt_InsertMarketResult>;
128
+ /**
129
+ * Update the Pyth guardian set used for verifying Wormhole messages.
130
+ *
131
+ * Each address must decode from a 20-byte hex string (with or without a
132
+ * leading `0x` prefix). The engine validates the supplied guardian set index
133
+ * before applying the update.
134
+ *
135
+ * @param params - Guardian set index and guardian addresses
136
+ * @returns Action identifier and guardian update receipt
137
+ * @throws {NordError} If the action submission fails
138
+ */
139
+ pythSetWormholeGuardians(params: PythSetWormholeGuardiansParams): Promise<{
140
+ actionId: bigint;
141
+ } & proto.Receipt_UpdateGuardianSetResult>;
142
+ /**
143
+ * Link an oracle symbol to a specific Pyth price feed.
144
+ *
145
+ * The price feed identifier must decode to 32 bytes (with or without a
146
+ * leading `0x` prefix). Use this call to create or update the mapping used
147
+ * by the oracle integration.
148
+ *
149
+ * @param params - Oracle symbol and price feed identifier
150
+ * @returns Action identifier and symbol feed receipt
151
+ * @throws {NordError} If the action submission fails
152
+ */
153
+ pythSetSymbolFeed(params: PythSetSymbolFeedParams): Promise<{
154
+ actionId: bigint;
155
+ } & proto.Receipt_OracleSymbolFeedResult>;
156
+ /**
157
+ * Pause all trading activity on the exchange.
158
+ *
159
+ * @returns Action identifier confirming the pause
160
+ * @throws {NordError} If the action submission fails
161
+ */
162
+ pause(): Promise<{
163
+ actionId: bigint;
164
+ }>;
165
+ /**
166
+ * Resume trading activity after a pause.
167
+ *
168
+ * @returns Action identifier confirming the unpause
169
+ * @throws {NordError} If the action submission fails
170
+ */
171
+ unpause(): Promise<{
172
+ actionId: bigint;
173
+ }>;
174
+ /**
175
+ * Freeze an individual market, preventing new trades and orders.
176
+ *
177
+ * @param params - Target market identifier
178
+ * @returns Action identifier and freeze receipt
179
+ * @throws {NordError} If the action submission fails
180
+ */
181
+ freezeMarket(params: FreezeMarketParams): Promise<{
182
+ actionId: bigint;
183
+ } & proto.Receipt_MarketFreezeUpdated>;
184
+ /**
185
+ * Unfreeze a market that was previously halted.
186
+ *
187
+ * @param params - Target market identifier
188
+ * @returns Action identifier and freeze receipt
189
+ * @throws {NordError} If the action submission fails
190
+ */
191
+ unfreezeMarket(params: UnfreezeMarketParams): Promise<{
192
+ actionId: bigint;
193
+ } & proto.Receipt_MarketFreezeUpdated>;
194
+ /**
195
+ * Append a new fee tier to the account bracket configuration.
196
+ *
197
+ * - The engine supports at most 16 tiers (ids 0–15). Tier 0 is reserved for
198
+ * the default Nord fees; use `updateFeeTier` if you need to change it.
199
+ * - The first appended tier receives id 1, and subsequent tiers increment the id.
200
+ *
201
+ * @param params - Fee tier configuration to insert
202
+ * @returns Action identifier and fee tier addition receipt
203
+ * @throws {NordError} If the action submission fails or the new tier exceeds the maximum range (0-15).
204
+ */
205
+ addFeeTier(params: AddFeeTierParams): Promise<{
206
+ actionId: bigint;
207
+ } & proto.Receipt_FeeTierAdded>;
208
+ /**
209
+ * Update an existing fee tier with new maker/taker rates.
210
+ *
211
+ * Tier identifiers must already exist; attempting to update a missing tier
212
+ * causes the action to fail.
213
+ *
214
+ * @param params - Fee tier identifier and updated configuration
215
+ * @returns Action identifier and fee tier update receipt
216
+ * @throws {NordError} If the action submission fails or the tier ID exceeds the configured range.
217
+ */
218
+ updateFeeTier(params: UpdateFeeTierParams): Promise<{
219
+ actionId: bigint;
220
+ } & proto.Receipt_FeeTierUpdated>;
221
+ /**
222
+ * Assign a fee tier to one or more accounts.
223
+ *
224
+ * The tier id must be within the configured range (0–15). Every account starts
225
+ * on tier 0; assigning it to another tier requires that tier to exist already.
226
+ * Invalid account ids or tier ids cause the action to fail.
227
+ *
228
+ * @param accounts - Account IDs to update
229
+ * @param tierId - Target fee tier identifier
230
+ * @returns Action identifier and accounts-tier receipt
231
+ * @throws {NordError} If the tier id exceeds the configured range or an account id is invalid.
232
+ */
233
+ updateAccountsTier(accounts: number[], tierId: number): Promise<{
234
+ actionId: bigint;
235
+ } & proto.Receipt_AccountsTierUpdated>;
236
+ }