@n1xyz/nord-ts 0.1.4 → 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.
@@ -1,14 +1,20 @@
1
+ import { PublicKey } from "@solana/web3.js";
1
2
  import * as proto from "../../gen/nord_pb";
2
- import { NordClient } from "./NordClient";
3
- import type { NordClientParams } from "./NordClient";
4
- import type { NordUser } from "./NordUser";
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
+ */
5
8
  export interface CreateTokenParams {
6
9
  tokenDecimals: number;
7
10
  weightBps: number;
8
11
  viewSymbol: string;
9
12
  oracleSymbol: string;
10
- solAddr: Uint8Array;
13
+ mintAddr: PublicKey;
11
14
  }
15
+ /**
16
+ * Parameters used when creating a new market.
17
+ */
12
18
  export interface CreateMarketParams {
13
19
  sizeDecimals: number;
14
20
  priceDecimals: number;
@@ -20,51 +26,211 @@ export interface CreateMarketParams {
20
26
  oracleSymbol: string;
21
27
  baseTokenId: number;
22
28
  }
29
+ /**
30
+ * Configuration for updating the Wormhole guardian set on the oracle.
31
+ */
23
32
  export interface PythSetWormholeGuardiansParams {
24
33
  guardianSetIndex: number;
25
- addresses: Uint8Array[];
34
+ addresses: string[];
26
35
  }
36
+ /**
37
+ * Parameters required to link an oracle symbol to a Pyth price feed.
38
+ */
27
39
  export interface PythSetSymbolFeedParams {
28
40
  oracleSymbol: string;
29
- priceFeedId: Uint8Array;
41
+ priceFeedId: string;
30
42
  }
43
+ /**
44
+ * Identifies a market that should be frozen.
45
+ */
31
46
  export interface FreezeMarketParams {
32
47
  marketId: number;
33
48
  }
49
+ /**
50
+ * Identifies a market that should be unfrozen.
51
+ */
34
52
  export interface UnfreezeMarketParams {
35
53
  marketId: number;
36
54
  }
37
- export interface NordAdminParams extends NordClientParams {
38
- signFn: (message: Uint8Array) => Promise<Uint8Array>;
55
+ /**
56
+ * Parameters for adding a new fee tier.
57
+ */
58
+ export interface AddFeeTierParams {
59
+ config: FeeTierConfig;
39
60
  }
40
- export declare class NordAdmin extends NordClient {
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;
41
73
  private readonly signFn;
42
- constructor(params: NordAdminParams);
43
- clone(): NordAdmin;
44
- static fromUser(user: NordUser, adminSignFn: (message: Uint8Array) => Promise<Uint8Array>): NordAdmin;
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
+ */
45
107
  private submitAction;
46
- createToken(params: CreateTokenParams): Promise<{
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<{
47
116
  actionId: bigint;
48
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
+ */
49
125
  createMarket(params: CreateMarketParams): Promise<{
50
126
  actionId: bigint;
51
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
+ */
52
139
  pythSetWormholeGuardians(params: PythSetWormholeGuardiansParams): Promise<{
53
140
  actionId: bigint;
54
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
+ */
55
153
  pythSetSymbolFeed(params: PythSetSymbolFeedParams): Promise<{
56
154
  actionId: bigint;
57
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
+ */
58
162
  pause(): Promise<{
59
163
  actionId: bigint;
60
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
+ */
61
171
  unpause(): Promise<{
62
172
  actionId: bigint;
63
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
+ */
64
181
  freezeMarket(params: FreezeMarketParams): Promise<{
65
182
  actionId: bigint;
66
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
+ */
67
191
  unfreezeMarket(params: UnfreezeMarketParams): Promise<{
68
192
  actionId: bigint;
69
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>;
70
236
  }
@@ -34,79 +34,92 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.NordAdmin = void 0;
37
- const proto = __importStar(require("../../gen/nord_pb"));
38
37
  const protobuf_1 = require("@bufbuild/protobuf");
38
+ const proto = __importStar(require("../../gen/nord_pb"));
39
39
  const utils_1 = require("../../utils");
40
- const types_1 = require("../../types");
40
+ const actions_1 = require("../api/actions");
41
41
  const NordError_1 = require("../utils/NordError");
42
- const NordClient_1 = require("./NordClient");
43
- class NordAdmin extends NordClient_1.NordClient {
44
- constructor(params) {
45
- const { signFn: adminSignFn, ...clientParams } = params;
46
- super(clientParams);
47
- this.signFn = adminSignFn;
48
- }
49
- clone() {
50
- const copy = new NordAdmin({
51
- nord: this.nord,
52
- address: this.address,
53
- walletSignFn: this.walletSignFn,
54
- sessionSignFn: this.sessionSignFn,
55
- transactionSignFn: this.transactionSignFn,
56
- connection: this.connection,
57
- sessionId: this.sessionId,
58
- sessionPubKey: new Uint8Array(this.sessionPubKey),
59
- publicKey: this.publicKey,
60
- signFn: this.signFn,
61
- });
62
- this.cloneClientState(copy);
63
- return copy;
42
+ /**
43
+ * Administrative client capable of submitting privileged configuration actions.
44
+ */
45
+ class NordAdmin {
46
+ constructor({ nord, signFn, }) {
47
+ this.nord = nord;
48
+ this.signFn = signFn;
64
49
  }
65
- static fromUser(user, adminSignFn) {
50
+ /** Create a new admin client.
51
+ *
52
+ * @param nord - Nord instance
53
+ * @param signFn - Function to sign messages with the admin's wallet.
54
+ *
55
+ * `signFn` must sign the _hex-encoded_ message, not the raw message itself, for
56
+ * the purpose of being compatible with Solana wallets.
57
+ *
58
+ * In practice, you will do something along the lines of:
59
+ *
60
+ * ```typescript
61
+ * (x) => wallet.signMessage(new TextEncoder().encode(x.toHex()));
62
+ * ```
63
+ *
64
+ * For a software signing key, this might look more like:
65
+ *
66
+ * ```typescript
67
+ * (x) => nacl.sign.detached(new TextEncoder().encode(x.toHex()), sk);
68
+ * ``
69
+ *
70
+ * where `nacl` is the tweetnacl library.
71
+ */
72
+ static new({ nord, signFn, }) {
66
73
  return new NordAdmin({
67
- nord: user.nord,
68
- address: user.address,
69
- walletSignFn: user.walletSignFn,
70
- sessionSignFn: user.sessionSignFn,
71
- transactionSignFn: user.transactionSignFn,
72
- connection: user.connection,
73
- sessionId: user.sessionId,
74
- sessionPubKey: new Uint8Array(user.sessionPubKey),
75
- publicKey: user.publicKey,
76
- signFn: adminSignFn,
74
+ nord,
75
+ signFn,
77
76
  });
78
77
  }
78
+ /**
79
+ * Submit an action and append the admin signature before sending it to Nord.
80
+ *
81
+ * @param kind - Action payload describing the admin request
82
+ * @throws {NordError} If signing or submission fails
83
+ */
79
84
  async submitAction(kind) {
80
- try {
81
- return await this.submitSignedAction(kind, async (message) => {
82
- const signature = await this.signFn(message);
83
- const signed = new Uint8Array(message.length + signature.length);
84
- signed.set(message);
85
- signed.set(signature, message.length);
86
- return signed;
87
- });
88
- }
89
- catch (error) {
90
- throw new NordError_1.NordError(`Admin action ${kind.case} failed`, {
91
- cause: error,
92
- });
93
- }
85
+ const timestamp = await this.nord.getTimestamp();
86
+ const action = (0, actions_1.createAction)(timestamp, 0, kind);
87
+ return (0, actions_1.sendAction)(this.nord.webServerUrl, async (xs) => {
88
+ const signature = await this.signFn(xs);
89
+ if (signature.length !== 64) {
90
+ throw new NordError_1.NordError("invalid signature length; must be 64 bytes");
91
+ }
92
+ return Uint8Array.from([...xs, ...signature]);
93
+ }, action);
94
94
  }
95
- async createToken(params) {
96
- (0, utils_1.checkPubKeyLength)(types_1.KeyType.Ed25519, params.solAddr.length);
95
+ /**
96
+ * Register a new token that can be listed on Nord.
97
+ *
98
+ * @param params - Token configuration values
99
+ * @returns Action identifier and resulting token metadata
100
+ * @throws {NordError} If the action submission fails
101
+ */
102
+ async createToken({ tokenDecimals, weightBps, viewSymbol, oracleSymbol, mintAddr, }) {
97
103
  const receipt = await this.submitAction({
98
104
  case: "createToken",
99
105
  value: (0, protobuf_1.create)(proto.Action_CreateTokenSchema, {
100
- tokenDecimals: params.tokenDecimals,
101
- weightBps: params.weightBps,
102
- viewSymbol: params.viewSymbol,
103
- oracleSymbol: params.oracleSymbol,
104
- solAddr: params.solAddr,
106
+ tokenDecimals,
107
+ weightBps,
108
+ viewSymbol,
109
+ oracleSymbol,
110
+ solAddr: mintAddr.toBytes(),
105
111
  }),
106
112
  });
107
- this.expectReceiptKind(receipt, "insertTokenResult", "create token");
113
+ (0, actions_1.expectReceiptKind)(receipt, "insertTokenResult", "create token");
108
114
  return { actionId: receipt.actionId, ...receipt.kind.value };
109
115
  }
116
+ /**
117
+ * Open a new market with the provided trading parameters.
118
+ *
119
+ * @param params - Market configuration to apply
120
+ * @returns Action identifier and resulting market metadata
121
+ * @throws {NordError} If the action submission fails
122
+ */
110
123
  async createMarket(params) {
111
124
  const receipt = await this.submitAction({
112
125
  case: "createMarket",
@@ -122,47 +135,112 @@ class NordAdmin extends NordClient_1.NordClient {
122
135
  baseTokenId: params.baseTokenId,
123
136
  }),
124
137
  });
125
- this.expectReceiptKind(receipt, "insertMarketResult", "create market");
138
+ (0, actions_1.expectReceiptKind)(receipt, "insertMarketResult", "create market");
126
139
  return { actionId: receipt.actionId, ...receipt.kind.value };
127
140
  }
141
+ /**
142
+ * Update the Pyth guardian set used for verifying Wormhole messages.
143
+ *
144
+ * Each address must decode from a 20-byte hex string (with or without a
145
+ * leading `0x` prefix). The engine validates the supplied guardian set index
146
+ * before applying the update.
147
+ *
148
+ * @param params - Guardian set index and guardian addresses
149
+ * @returns Action identifier and guardian update receipt
150
+ * @throws {NordError} If the action submission fails
151
+ */
128
152
  async pythSetWormholeGuardians(params) {
153
+ const addresses = params.addresses.map((address) => {
154
+ try {
155
+ const decoded = (0, utils_1.decodeHex)(address);
156
+ if (decoded.length !== 20) {
157
+ throw new Error("guardian address must be 20 bytes");
158
+ }
159
+ return decoded;
160
+ }
161
+ catch (e) {
162
+ throw new NordError_1.NordError("invalid guardian address; must be a 20 byte hex address", { cause: e });
163
+ }
164
+ });
129
165
  const receipt = await this.submitAction({
130
166
  case: "pythSetWormholeGuardians",
131
167
  value: (0, protobuf_1.create)(proto.Action_PythSetWormholeGuardiansSchema, {
132
168
  guardianSetIndex: params.guardianSetIndex,
133
- addresses: params.addresses,
169
+ addresses,
134
170
  }),
135
171
  });
136
- this.expectReceiptKind(receipt, "updateGuardianSetResult", "update wormhole guardians");
172
+ (0, actions_1.expectReceiptKind)(receipt, "updateGuardianSetResult", "update wormhole guardians");
137
173
  return { actionId: receipt.actionId, ...receipt.kind.value };
138
174
  }
175
+ /**
176
+ * Link an oracle symbol to a specific Pyth price feed.
177
+ *
178
+ * The price feed identifier must decode to 32 bytes (with or without a
179
+ * leading `0x` prefix). Use this call to create or update the mapping used
180
+ * by the oracle integration.
181
+ *
182
+ * @param params - Oracle symbol and price feed identifier
183
+ * @returns Action identifier and symbol feed receipt
184
+ * @throws {NordError} If the action submission fails
185
+ */
139
186
  async pythSetSymbolFeed(params) {
187
+ let priceFeedId;
188
+ try {
189
+ priceFeedId = (0, utils_1.decodeHex)(params.priceFeedId);
190
+ if (priceFeedId.length !== 32) {
191
+ throw new Error("price feed id must be 32 bytes");
192
+ }
193
+ }
194
+ catch (e) {
195
+ throw new NordError_1.NordError("invalid price feed id; must be a 32 byte hex id", {
196
+ cause: e,
197
+ });
198
+ }
140
199
  const receipt = await this.submitAction({
141
200
  case: "pythSetSymbolFeed",
142
201
  value: (0, protobuf_1.create)(proto.Action_PythSetSymbolFeedSchema, {
143
202
  oracleSymbol: params.oracleSymbol,
144
- priceFeedId: params.priceFeedId,
203
+ priceFeedId,
145
204
  }),
146
205
  });
147
- this.expectReceiptKind(receipt, "oracleSymbolFeedResult", "set symbol feed");
206
+ (0, actions_1.expectReceiptKind)(receipt, "oracleSymbolFeedResult", "set symbol feed");
148
207
  return { actionId: receipt.actionId, ...receipt.kind.value };
149
208
  }
209
+ /**
210
+ * Pause all trading activity on the exchange.
211
+ *
212
+ * @returns Action identifier confirming the pause
213
+ * @throws {NordError} If the action submission fails
214
+ */
150
215
  async pause() {
151
216
  const receipt = await this.submitAction({
152
217
  case: "pause",
153
218
  value: (0, protobuf_1.create)(proto.Action_PauseSchema, {}),
154
219
  });
155
- this.expectReceiptKind(receipt, "paused", "pause");
220
+ (0, actions_1.expectReceiptKind)(receipt, "paused", "pause");
156
221
  return { actionId: receipt.actionId };
157
222
  }
223
+ /**
224
+ * Resume trading activity after a pause.
225
+ *
226
+ * @returns Action identifier confirming the unpause
227
+ * @throws {NordError} If the action submission fails
228
+ */
158
229
  async unpause() {
159
230
  const receipt = await this.submitAction({
160
231
  case: "unpause",
161
232
  value: (0, protobuf_1.create)(proto.Action_UnpauseSchema, {}),
162
233
  });
163
- this.expectReceiptKind(receipt, "unpaused", "unpause");
234
+ (0, actions_1.expectReceiptKind)(receipt, "unpaused", "unpause");
164
235
  return { actionId: receipt.actionId };
165
236
  }
237
+ /**
238
+ * Freeze an individual market, preventing new trades and orders.
239
+ *
240
+ * @param params - Target market identifier
241
+ * @returns Action identifier and freeze receipt
242
+ * @throws {NordError} If the action submission fails
243
+ */
166
244
  async freezeMarket(params) {
167
245
  const receipt = await this.submitAction({
168
246
  case: "freezeMarket",
@@ -170,9 +248,16 @@ class NordAdmin extends NordClient_1.NordClient {
170
248
  marketId: params.marketId,
171
249
  }),
172
250
  });
173
- this.expectReceiptKind(receipt, "marketFreezeUpdated", "freeze market");
251
+ (0, actions_1.expectReceiptKind)(receipt, "marketFreezeUpdated", "freeze market");
174
252
  return { actionId: receipt.actionId, ...receipt.kind.value };
175
253
  }
254
+ /**
255
+ * Unfreeze a market that was previously halted.
256
+ *
257
+ * @param params - Target market identifier
258
+ * @returns Action identifier and freeze receipt
259
+ * @throws {NordError} If the action submission fails
260
+ */
176
261
  async unfreezeMarket(params) {
177
262
  const receipt = await this.submitAction({
178
263
  case: "unfreezeMarket",
@@ -180,7 +265,72 @@ class NordAdmin extends NordClient_1.NordClient {
180
265
  marketId: params.marketId,
181
266
  }),
182
267
  });
183
- this.expectReceiptKind(receipt, "marketFreezeUpdated", "unfreeze market");
268
+ (0, actions_1.expectReceiptKind)(receipt, "marketFreezeUpdated", "unfreeze market");
269
+ return { actionId: receipt.actionId, ...receipt.kind.value };
270
+ }
271
+ /**
272
+ * Append a new fee tier to the account bracket configuration.
273
+ *
274
+ * - The engine supports at most 16 tiers (ids 0–15). Tier 0 is reserved for
275
+ * the default Nord fees; use `updateFeeTier` if you need to change it.
276
+ * - The first appended tier receives id 1, and subsequent tiers increment the id.
277
+ *
278
+ * @param params - Fee tier configuration to insert
279
+ * @returns Action identifier and fee tier addition receipt
280
+ * @throws {NordError} If the action submission fails or the new tier exceeds the maximum range (0-15).
281
+ */
282
+ async addFeeTier(params) {
283
+ const receipt = await this.submitAction({
284
+ case: "addFeeTier",
285
+ value: (0, protobuf_1.create)(proto.Action_AddFeeTierSchema, {
286
+ config: (0, protobuf_1.create)(proto.FeeTierConfigSchema, params.config),
287
+ }),
288
+ });
289
+ (0, actions_1.expectReceiptKind)(receipt, "feeTierAdded", "add fee tier");
290
+ return { actionId: receipt.actionId, ...receipt.kind.value };
291
+ }
292
+ /**
293
+ * Update an existing fee tier with new maker/taker rates.
294
+ *
295
+ * Tier identifiers must already exist; attempting to update a missing tier
296
+ * causes the action to fail.
297
+ *
298
+ * @param params - Fee tier identifier and updated configuration
299
+ * @returns Action identifier and fee tier update receipt
300
+ * @throws {NordError} If the action submission fails or the tier ID exceeds the configured range.
301
+ */
302
+ async updateFeeTier(params) {
303
+ const receipt = await this.submitAction({
304
+ case: "updateFeeTier",
305
+ value: (0, protobuf_1.create)(proto.Action_UpdateFeeTierSchema, {
306
+ id: params.tierId,
307
+ config: (0, protobuf_1.create)(proto.FeeTierConfigSchema, params.config),
308
+ }),
309
+ });
310
+ (0, actions_1.expectReceiptKind)(receipt, "feeTierUpdated", "update fee tier");
311
+ return { actionId: receipt.actionId, ...receipt.kind.value };
312
+ }
313
+ /**
314
+ * Assign a fee tier to one or more accounts.
315
+ *
316
+ * The tier id must be within the configured range (0–15). Every account starts
317
+ * on tier 0; assigning it to another tier requires that tier to exist already.
318
+ * Invalid account ids or tier ids cause the action to fail.
319
+ *
320
+ * @param accounts - Account IDs to update
321
+ * @param tierId - Target fee tier identifier
322
+ * @returns Action identifier and accounts-tier receipt
323
+ * @throws {NordError} If the tier id exceeds the configured range or an account id is invalid.
324
+ */
325
+ async updateAccountsTier(accounts, tierId) {
326
+ const receipt = await this.submitAction({
327
+ case: "updateAccountsTier",
328
+ value: (0, protobuf_1.create)(proto.Action_UpdateAccountsTierSchema, {
329
+ accounts,
330
+ tierId,
331
+ }),
332
+ });
333
+ (0, actions_1.expectReceiptKind)(receipt, "accountsTierUpdated", "update accounts tier");
184
334
  return { actionId: receipt.actionId, ...receipt.kind.value };
185
335
  }
186
336
  }
@@ -2,10 +2,6 @@ import { Connection, PublicKey } from "@solana/web3.js";
2
2
  import type { Transaction } from "@solana/web3.js";
3
3
  import * as proto from "../../gen/nord_pb";
4
4
  import { Nord } from "./Nord";
5
- type ReceiptKind = NonNullable<proto.Receipt["kind"]>;
6
- type ExtractReceiptKind<K extends ReceiptKind["case"]> = Extract<ReceiptKind, {
7
- case: K;
8
- }>;
9
5
  export interface NordClientParams {
10
6
  nord: Nord;
11
7
  address: PublicKey;
@@ -34,9 +30,4 @@ export declare abstract class NordClient {
34
30
  protected nextActionNonce(): number;
35
31
  protected cloneClientState(target: NordClient): void;
36
32
  getSolanaPublicKey(): PublicKey;
37
- protected expectReceiptKind<K extends ReceiptKind["case"]>(receipt: proto.Receipt, expected: K, action: string): asserts receipt is proto.Receipt & {
38
- kind: ExtractReceiptKind<K>;
39
- };
40
- protected formatReceiptError(receipt: proto.Receipt): string;
41
33
  }
42
- export {};