@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.
- package/dist/gen/nord_pb.d.ts +286 -3
- package/dist/gen/nord_pb.js +107 -64
- package/dist/gen/openapi.d.ts +165 -1
- package/dist/nord/api/actions.d.ts +9 -0
- package/dist/nord/api/actions.js +16 -0
- package/dist/nord/client/Nord.d.ts +91 -1
- package/dist/nord/client/Nord.js +148 -0
- package/dist/nord/client/NordAdmin.d.ts +179 -13
- package/dist/nord/client/NordAdmin.js +216 -66
- package/dist/nord/client/NordClient.d.ts +0 -9
- package/dist/nord/client/NordClient.js +0 -48
- package/dist/nord/client/NordUser.js +6 -6
- package/dist/nord/index.d.ts +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +5 -0
- package/package.json +2 -2
- package/src/gen/nord_pb.ts +378 -63
- package/src/gen/openapi.ts +165 -1
- package/src/nord/api/actions.ts +26 -1
- package/src/nord/client/Nord.ts +183 -0
- package/src/nord/client/NordAdmin.ts +292 -83
- package/src/nord/client/NordClient.ts +0 -26
- package/src/nord/client/NordUser.ts +7 -6
- package/src/nord/index.ts +0 -1
- package/src/types.ts +6 -0
- package/src/utils.ts +5 -0
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
import * as proto from "../../gen/nord_pb";
|
|
2
1
|
import { create } from "@bufbuild/protobuf";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
2
|
+
import { PublicKey } from "@solana/web3.js";
|
|
3
|
+
import * as proto from "../../gen/nord_pb";
|
|
4
|
+
import { decodeHex } from "../../utils";
|
|
5
|
+
import { createAction, sendAction, expectReceiptKind } from "../api/actions";
|
|
5
6
|
import { NordError } from "../utils/NordError";
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import type { NordUser } from "./NordUser";
|
|
7
|
+
import { Nord } from "./Nord";
|
|
8
|
+
import { FeeTierConfig } from "../../gen/nord_pb";
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Parameters required to register a new token via the admin API.
|
|
12
|
+
*/
|
|
10
13
|
export interface CreateTokenParams {
|
|
11
14
|
tokenDecimals: number;
|
|
12
15
|
weightBps: number;
|
|
13
16
|
viewSymbol: string;
|
|
14
17
|
oracleSymbol: string;
|
|
15
|
-
|
|
18
|
+
mintAddr: PublicKey;
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Parameters used when creating a new market.
|
|
23
|
+
*/
|
|
18
24
|
export interface CreateMarketParams {
|
|
19
25
|
sizeDecimals: number;
|
|
20
26
|
priceDecimals: number;
|
|
@@ -27,108 +33,165 @@ export interface CreateMarketParams {
|
|
|
27
33
|
baseTokenId: number;
|
|
28
34
|
}
|
|
29
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Configuration for updating the Wormhole guardian set on the oracle.
|
|
38
|
+
*/
|
|
30
39
|
export interface PythSetWormholeGuardiansParams {
|
|
31
40
|
guardianSetIndex: number;
|
|
32
|
-
addresses:
|
|
41
|
+
addresses: string[];
|
|
33
42
|
}
|
|
34
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Parameters required to link an oracle symbol to a Pyth price feed.
|
|
46
|
+
*/
|
|
35
47
|
export interface PythSetSymbolFeedParams {
|
|
36
48
|
oracleSymbol: string;
|
|
37
|
-
priceFeedId:
|
|
49
|
+
priceFeedId: string;
|
|
38
50
|
}
|
|
39
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Identifies a market that should be frozen.
|
|
54
|
+
*/
|
|
40
55
|
export interface FreezeMarketParams {
|
|
41
56
|
marketId: number;
|
|
42
57
|
}
|
|
43
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Identifies a market that should be unfrozen.
|
|
61
|
+
*/
|
|
44
62
|
export interface UnfreezeMarketParams {
|
|
45
63
|
marketId: number;
|
|
46
64
|
}
|
|
47
65
|
|
|
48
|
-
|
|
49
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Parameters for adding a new fee tier.
|
|
68
|
+
*/
|
|
69
|
+
export interface AddFeeTierParams {
|
|
70
|
+
config: FeeTierConfig;
|
|
50
71
|
}
|
|
51
72
|
|
|
52
|
-
|
|
53
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Parameters for updating an existing fee tier.
|
|
75
|
+
*/
|
|
76
|
+
export interface UpdateFeeTierParams {
|
|
77
|
+
tierId: number;
|
|
78
|
+
config: FeeTierConfig;
|
|
79
|
+
}
|
|
54
80
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Administrative client capable of submitting privileged configuration actions.
|
|
83
|
+
*/
|
|
84
|
+
export class NordAdmin {
|
|
85
|
+
private readonly nord: Nord;
|
|
86
|
+
private readonly signFn: (x: Uint8Array) => Promise<Uint8Array>;
|
|
60
87
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
sessionPubKey: new Uint8Array(this.sessionPubKey),
|
|
71
|
-
publicKey: this.publicKey,
|
|
72
|
-
signFn: this.signFn,
|
|
73
|
-
});
|
|
74
|
-
this.cloneClientState(copy);
|
|
75
|
-
return copy;
|
|
88
|
+
private constructor({
|
|
89
|
+
nord,
|
|
90
|
+
signFn,
|
|
91
|
+
}: {
|
|
92
|
+
nord: Nord;
|
|
93
|
+
signFn: (x: Uint8Array) => Promise<Uint8Array>;
|
|
94
|
+
}) {
|
|
95
|
+
this.nord = nord;
|
|
96
|
+
this.signFn = signFn;
|
|
76
97
|
}
|
|
77
98
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
99
|
+
/** Create a new admin client.
|
|
100
|
+
*
|
|
101
|
+
* @param nord - Nord instance
|
|
102
|
+
* @param signFn - Function to sign messages with the admin's wallet.
|
|
103
|
+
*
|
|
104
|
+
* `signFn` must sign the _hex-encoded_ message, not the raw message itself, for
|
|
105
|
+
* the purpose of being compatible with Solana wallets.
|
|
106
|
+
*
|
|
107
|
+
* In practice, you will do something along the lines of:
|
|
108
|
+
*
|
|
109
|
+
* ```typescript
|
|
110
|
+
* (x) => wallet.signMessage(new TextEncoder().encode(x.toHex()));
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* For a software signing key, this might look more like:
|
|
114
|
+
*
|
|
115
|
+
* ```typescript
|
|
116
|
+
* (x) => nacl.sign.detached(new TextEncoder().encode(x.toHex()), sk);
|
|
117
|
+
* ``
|
|
118
|
+
*
|
|
119
|
+
* where `nacl` is the tweetnacl library.
|
|
120
|
+
*/
|
|
121
|
+
public static new({
|
|
122
|
+
nord,
|
|
123
|
+
signFn,
|
|
124
|
+
}: Readonly<{
|
|
125
|
+
nord: Nord;
|
|
126
|
+
signFn: (m: Uint8Array) => Promise<Uint8Array>;
|
|
127
|
+
}>): NordAdmin {
|
|
82
128
|
return new NordAdmin({
|
|
83
|
-
nord
|
|
84
|
-
|
|
85
|
-
walletSignFn: user.walletSignFn,
|
|
86
|
-
sessionSignFn: user.sessionSignFn,
|
|
87
|
-
transactionSignFn: user.transactionSignFn,
|
|
88
|
-
connection: user.connection,
|
|
89
|
-
sessionId: user.sessionId,
|
|
90
|
-
sessionPubKey: new Uint8Array(user.sessionPubKey),
|
|
91
|
-
publicKey: user.publicKey,
|
|
92
|
-
signFn: adminSignFn,
|
|
129
|
+
nord,
|
|
130
|
+
signFn,
|
|
93
131
|
});
|
|
94
132
|
}
|
|
95
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Submit an action and append the admin signature before sending it to Nord.
|
|
136
|
+
*
|
|
137
|
+
* @param kind - Action payload describing the admin request
|
|
138
|
+
* @throws {NordError} If signing or submission fails
|
|
139
|
+
*/
|
|
96
140
|
private async submitAction(
|
|
97
141
|
kind: proto.Action["kind"],
|
|
98
142
|
): Promise<proto.Receipt> {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
143
|
+
const timestamp = await this.nord.getTimestamp();
|
|
144
|
+
const action = createAction(timestamp, 0, kind);
|
|
145
|
+
return sendAction(
|
|
146
|
+
this.nord.webServerUrl,
|
|
147
|
+
async (xs: Uint8Array) => {
|
|
148
|
+
const signature = await this.signFn(xs);
|
|
149
|
+
if (signature.length !== 64) {
|
|
150
|
+
throw new NordError("invalid signature length; must be 64 bytes");
|
|
151
|
+
}
|
|
152
|
+
return Uint8Array.from([...xs, ...signature]);
|
|
153
|
+
},
|
|
154
|
+
action,
|
|
155
|
+
);
|
|
112
156
|
}
|
|
113
157
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Register a new token that can be listed on Nord.
|
|
160
|
+
*
|
|
161
|
+
* @param params - Token configuration values
|
|
162
|
+
* @returns Action identifier and resulting token metadata
|
|
163
|
+
* @throws {NordError} If the action submission fails
|
|
164
|
+
*/
|
|
165
|
+
async createToken({
|
|
166
|
+
tokenDecimals,
|
|
167
|
+
weightBps,
|
|
168
|
+
viewSymbol,
|
|
169
|
+
oracleSymbol,
|
|
170
|
+
mintAddr,
|
|
171
|
+
}: CreateTokenParams): Promise<
|
|
172
|
+
{ actionId: bigint } & proto.Receipt_InsertTokenResult
|
|
173
|
+
> {
|
|
118
174
|
const receipt = await this.submitAction({
|
|
119
175
|
case: "createToken",
|
|
120
176
|
value: create(proto.Action_CreateTokenSchema, {
|
|
121
|
-
tokenDecimals
|
|
122
|
-
weightBps
|
|
123
|
-
viewSymbol
|
|
124
|
-
oracleSymbol
|
|
125
|
-
solAddr:
|
|
177
|
+
tokenDecimals,
|
|
178
|
+
weightBps,
|
|
179
|
+
viewSymbol,
|
|
180
|
+
oracleSymbol,
|
|
181
|
+
solAddr: mintAddr.toBytes(),
|
|
126
182
|
}),
|
|
127
183
|
});
|
|
128
|
-
|
|
184
|
+
expectReceiptKind(receipt, "insertTokenResult", "create token");
|
|
129
185
|
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
130
186
|
}
|
|
131
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Open a new market with the provided trading parameters.
|
|
190
|
+
*
|
|
191
|
+
* @param params - Market configuration to apply
|
|
192
|
+
* @returns Action identifier and resulting market metadata
|
|
193
|
+
* @throws {NordError} If the action submission fails
|
|
194
|
+
*/
|
|
132
195
|
async createMarket(
|
|
133
196
|
params: CreateMarketParams,
|
|
134
197
|
): Promise<{ actionId: bigint } & proto.Receipt_InsertMarketResult> {
|
|
@@ -146,21 +209,47 @@ export class NordAdmin extends NordClient {
|
|
|
146
209
|
baseTokenId: params.baseTokenId,
|
|
147
210
|
}),
|
|
148
211
|
});
|
|
149
|
-
|
|
212
|
+
expectReceiptKind(receipt, "insertMarketResult", "create market");
|
|
150
213
|
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
151
214
|
}
|
|
152
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Update the Pyth guardian set used for verifying Wormhole messages.
|
|
218
|
+
*
|
|
219
|
+
* Each address must decode from a 20-byte hex string (with or without a
|
|
220
|
+
* leading `0x` prefix). The engine validates the supplied guardian set index
|
|
221
|
+
* before applying the update.
|
|
222
|
+
*
|
|
223
|
+
* @param params - Guardian set index and guardian addresses
|
|
224
|
+
* @returns Action identifier and guardian update receipt
|
|
225
|
+
* @throws {NordError} If the action submission fails
|
|
226
|
+
*/
|
|
153
227
|
async pythSetWormholeGuardians(
|
|
154
228
|
params: PythSetWormholeGuardiansParams,
|
|
155
229
|
): Promise<{ actionId: bigint } & proto.Receipt_UpdateGuardianSetResult> {
|
|
230
|
+
const addresses = params.addresses.map((address) => {
|
|
231
|
+
try {
|
|
232
|
+
const decoded = decodeHex(address);
|
|
233
|
+
if (decoded.length !== 20) {
|
|
234
|
+
throw new Error("guardian address must be 20 bytes");
|
|
235
|
+
}
|
|
236
|
+
return decoded;
|
|
237
|
+
} catch (e) {
|
|
238
|
+
throw new NordError(
|
|
239
|
+
"invalid guardian address; must be a 20 byte hex address",
|
|
240
|
+
{ cause: e },
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
156
245
|
const receipt = await this.submitAction({
|
|
157
246
|
case: "pythSetWormholeGuardians",
|
|
158
247
|
value: create(proto.Action_PythSetWormholeGuardiansSchema, {
|
|
159
248
|
guardianSetIndex: params.guardianSetIndex,
|
|
160
|
-
addresses
|
|
249
|
+
addresses,
|
|
161
250
|
}),
|
|
162
251
|
});
|
|
163
|
-
|
|
252
|
+
expectReceiptKind(
|
|
164
253
|
receipt,
|
|
165
254
|
"updateGuardianSetResult",
|
|
166
255
|
"update wormhole guardians",
|
|
@@ -168,42 +257,80 @@ export class NordAdmin extends NordClient {
|
|
|
168
257
|
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
169
258
|
}
|
|
170
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Link an oracle symbol to a specific Pyth price feed.
|
|
262
|
+
*
|
|
263
|
+
* The price feed identifier must decode to 32 bytes (with or without a
|
|
264
|
+
* leading `0x` prefix). Use this call to create or update the mapping used
|
|
265
|
+
* by the oracle integration.
|
|
266
|
+
*
|
|
267
|
+
* @param params - Oracle symbol and price feed identifier
|
|
268
|
+
* @returns Action identifier and symbol feed receipt
|
|
269
|
+
* @throws {NordError} If the action submission fails
|
|
270
|
+
*/
|
|
171
271
|
async pythSetSymbolFeed(
|
|
172
272
|
params: PythSetSymbolFeedParams,
|
|
173
273
|
): Promise<{ actionId: bigint } & proto.Receipt_OracleSymbolFeedResult> {
|
|
274
|
+
let priceFeedId: Uint8Array;
|
|
275
|
+
try {
|
|
276
|
+
priceFeedId = decodeHex(params.priceFeedId);
|
|
277
|
+
if (priceFeedId.length !== 32) {
|
|
278
|
+
throw new Error("price feed id must be 32 bytes");
|
|
279
|
+
}
|
|
280
|
+
} catch (e) {
|
|
281
|
+
throw new NordError("invalid price feed id; must be a 32 byte hex id", {
|
|
282
|
+
cause: e,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
174
286
|
const receipt = await this.submitAction({
|
|
175
287
|
case: "pythSetSymbolFeed",
|
|
176
288
|
value: create(proto.Action_PythSetSymbolFeedSchema, {
|
|
177
289
|
oracleSymbol: params.oracleSymbol,
|
|
178
|
-
priceFeedId
|
|
290
|
+
priceFeedId,
|
|
179
291
|
}),
|
|
180
292
|
});
|
|
181
|
-
|
|
182
|
-
receipt,
|
|
183
|
-
"oracleSymbolFeedResult",
|
|
184
|
-
"set symbol feed",
|
|
185
|
-
);
|
|
293
|
+
expectReceiptKind(receipt, "oracleSymbolFeedResult", "set symbol feed");
|
|
186
294
|
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
187
295
|
}
|
|
188
296
|
|
|
297
|
+
/**
|
|
298
|
+
* Pause all trading activity on the exchange.
|
|
299
|
+
*
|
|
300
|
+
* @returns Action identifier confirming the pause
|
|
301
|
+
* @throws {NordError} If the action submission fails
|
|
302
|
+
*/
|
|
189
303
|
async pause(): Promise<{ actionId: bigint }> {
|
|
190
304
|
const receipt = await this.submitAction({
|
|
191
305
|
case: "pause",
|
|
192
306
|
value: create(proto.Action_PauseSchema, {}),
|
|
193
307
|
});
|
|
194
|
-
|
|
308
|
+
expectReceiptKind(receipt, "paused", "pause");
|
|
195
309
|
return { actionId: receipt.actionId };
|
|
196
310
|
}
|
|
197
311
|
|
|
312
|
+
/**
|
|
313
|
+
* Resume trading activity after a pause.
|
|
314
|
+
*
|
|
315
|
+
* @returns Action identifier confirming the unpause
|
|
316
|
+
* @throws {NordError} If the action submission fails
|
|
317
|
+
*/
|
|
198
318
|
async unpause(): Promise<{ actionId: bigint }> {
|
|
199
319
|
const receipt = await this.submitAction({
|
|
200
320
|
case: "unpause",
|
|
201
321
|
value: create(proto.Action_UnpauseSchema, {}),
|
|
202
322
|
});
|
|
203
|
-
|
|
323
|
+
expectReceiptKind(receipt, "unpaused", "unpause");
|
|
204
324
|
return { actionId: receipt.actionId };
|
|
205
325
|
}
|
|
206
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Freeze an individual market, preventing new trades and orders.
|
|
329
|
+
*
|
|
330
|
+
* @param params - Target market identifier
|
|
331
|
+
* @returns Action identifier and freeze receipt
|
|
332
|
+
* @throws {NordError} If the action submission fails
|
|
333
|
+
*/
|
|
207
334
|
async freezeMarket(
|
|
208
335
|
params: FreezeMarketParams,
|
|
209
336
|
): Promise<{ actionId: bigint } & proto.Receipt_MarketFreezeUpdated> {
|
|
@@ -213,10 +340,17 @@ export class NordAdmin extends NordClient {
|
|
|
213
340
|
marketId: params.marketId,
|
|
214
341
|
}),
|
|
215
342
|
});
|
|
216
|
-
|
|
343
|
+
expectReceiptKind(receipt, "marketFreezeUpdated", "freeze market");
|
|
217
344
|
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
218
345
|
}
|
|
219
346
|
|
|
347
|
+
/**
|
|
348
|
+
* Unfreeze a market that was previously halted.
|
|
349
|
+
*
|
|
350
|
+
* @param params - Target market identifier
|
|
351
|
+
* @returns Action identifier and freeze receipt
|
|
352
|
+
* @throws {NordError} If the action submission fails
|
|
353
|
+
*/
|
|
220
354
|
async unfreezeMarket(
|
|
221
355
|
params: UnfreezeMarketParams,
|
|
222
356
|
): Promise<{ actionId: bigint } & proto.Receipt_MarketFreezeUpdated> {
|
|
@@ -226,7 +360,82 @@ export class NordAdmin extends NordClient {
|
|
|
226
360
|
marketId: params.marketId,
|
|
227
361
|
}),
|
|
228
362
|
});
|
|
229
|
-
|
|
363
|
+
expectReceiptKind(receipt, "marketFreezeUpdated", "unfreeze market");
|
|
364
|
+
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Append a new fee tier to the account bracket configuration.
|
|
369
|
+
*
|
|
370
|
+
* - The engine supports at most 16 tiers (ids 0–15). Tier 0 is reserved for
|
|
371
|
+
* the default Nord fees; use `updateFeeTier` if you need to change it.
|
|
372
|
+
* - The first appended tier receives id 1, and subsequent tiers increment the id.
|
|
373
|
+
*
|
|
374
|
+
* @param params - Fee tier configuration to insert
|
|
375
|
+
* @returns Action identifier and fee tier addition receipt
|
|
376
|
+
* @throws {NordError} If the action submission fails or the new tier exceeds the maximum range (0-15).
|
|
377
|
+
*/
|
|
378
|
+
async addFeeTier(
|
|
379
|
+
params: AddFeeTierParams,
|
|
380
|
+
): Promise<{ actionId: bigint } & proto.Receipt_FeeTierAdded> {
|
|
381
|
+
const receipt = await this.submitAction({
|
|
382
|
+
case: "addFeeTier",
|
|
383
|
+
value: create(proto.Action_AddFeeTierSchema, {
|
|
384
|
+
config: create(proto.FeeTierConfigSchema, params.config),
|
|
385
|
+
}),
|
|
386
|
+
});
|
|
387
|
+
expectReceiptKind(receipt, "feeTierAdded", "add fee tier");
|
|
388
|
+
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Update an existing fee tier with new maker/taker rates.
|
|
393
|
+
*
|
|
394
|
+
* Tier identifiers must already exist; attempting to update a missing tier
|
|
395
|
+
* causes the action to fail.
|
|
396
|
+
*
|
|
397
|
+
* @param params - Fee tier identifier and updated configuration
|
|
398
|
+
* @returns Action identifier and fee tier update receipt
|
|
399
|
+
* @throws {NordError} If the action submission fails or the tier ID exceeds the configured range.
|
|
400
|
+
*/
|
|
401
|
+
async updateFeeTier(
|
|
402
|
+
params: UpdateFeeTierParams,
|
|
403
|
+
): Promise<{ actionId: bigint } & proto.Receipt_FeeTierUpdated> {
|
|
404
|
+
const receipt = await this.submitAction({
|
|
405
|
+
case: "updateFeeTier",
|
|
406
|
+
value: create(proto.Action_UpdateFeeTierSchema, {
|
|
407
|
+
id: params.tierId,
|
|
408
|
+
config: create(proto.FeeTierConfigSchema, params.config),
|
|
409
|
+
}),
|
|
410
|
+
});
|
|
411
|
+
expectReceiptKind(receipt, "feeTierUpdated", "update fee tier");
|
|
412
|
+
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Assign a fee tier to one or more accounts.
|
|
417
|
+
*
|
|
418
|
+
* The tier id must be within the configured range (0–15). Every account starts
|
|
419
|
+
* on tier 0; assigning it to another tier requires that tier to exist already.
|
|
420
|
+
* Invalid account ids or tier ids cause the action to fail.
|
|
421
|
+
*
|
|
422
|
+
* @param accounts - Account IDs to update
|
|
423
|
+
* @param tierId - Target fee tier identifier
|
|
424
|
+
* @returns Action identifier and accounts-tier receipt
|
|
425
|
+
* @throws {NordError} If the tier id exceeds the configured range or an account id is invalid.
|
|
426
|
+
*/
|
|
427
|
+
async updateAccountsTier(
|
|
428
|
+
accounts: number[],
|
|
429
|
+
tierId: number,
|
|
430
|
+
): Promise<{ actionId: bigint } & proto.Receipt_AccountsTierUpdated> {
|
|
431
|
+
const receipt = await this.submitAction({
|
|
432
|
+
case: "updateAccountsTier",
|
|
433
|
+
value: create(proto.Action_UpdateAccountsTierSchema, {
|
|
434
|
+
accounts,
|
|
435
|
+
tierId,
|
|
436
|
+
}),
|
|
437
|
+
});
|
|
438
|
+
expectReceiptKind(receipt, "accountsTierUpdated", "update accounts tier");
|
|
230
439
|
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
231
440
|
}
|
|
232
441
|
}
|
|
@@ -2,15 +2,8 @@ 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 { createAction, sendAction } from "../api/actions";
|
|
5
|
-
import { NordError } from "../utils/NordError";
|
|
6
5
|
import { Nord } from "./Nord";
|
|
7
6
|
|
|
8
|
-
type ReceiptKind = NonNullable<proto.Receipt["kind"]>;
|
|
9
|
-
type ExtractReceiptKind<K extends ReceiptKind["case"]> = Extract<
|
|
10
|
-
ReceiptKind,
|
|
11
|
-
{ case: K }
|
|
12
|
-
>;
|
|
13
|
-
|
|
14
7
|
export interface NordClientParams {
|
|
15
8
|
nord: Nord;
|
|
16
9
|
address: PublicKey;
|
|
@@ -83,23 +76,4 @@ export abstract class NordClient {
|
|
|
83
76
|
getSolanaPublicKey(): PublicKey {
|
|
84
77
|
return this.address;
|
|
85
78
|
}
|
|
86
|
-
|
|
87
|
-
protected expectReceiptKind<K extends ReceiptKind["case"]>(
|
|
88
|
-
receipt: proto.Receipt,
|
|
89
|
-
expected: K,
|
|
90
|
-
action: string,
|
|
91
|
-
): asserts receipt is proto.Receipt & { kind: ExtractReceiptKind<K> } {
|
|
92
|
-
if (receipt.kind?.case !== expected) {
|
|
93
|
-
const label = this.formatReceiptError(receipt);
|
|
94
|
-
throw new NordError(`Failed to ${action}: ${label}`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
protected formatReceiptError(receipt: proto.Receipt): string {
|
|
99
|
-
if (receipt.kind?.case === "err") {
|
|
100
|
-
const err = receipt.kind.value;
|
|
101
|
-
return proto.Error[err] ?? err.toString();
|
|
102
|
-
}
|
|
103
|
-
return receipt.kind?.case ?? "unknown";
|
|
104
|
-
}
|
|
105
79
|
}
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
createSession,
|
|
40
40
|
revokeSession,
|
|
41
41
|
atomic,
|
|
42
|
+
expectReceiptKind,
|
|
42
43
|
AtomicSubaction,
|
|
43
44
|
} from "../api/actions";
|
|
44
45
|
import { NordError } from "../utils/NordError";
|
|
@@ -737,7 +738,7 @@ export class NordUser extends NordClient {
|
|
|
737
738
|
amount: scaledAmount,
|
|
738
739
|
}),
|
|
739
740
|
});
|
|
740
|
-
|
|
741
|
+
expectReceiptKind(receipt, "withdrawResult", "withdraw");
|
|
741
742
|
return { actionId: receipt.actionId };
|
|
742
743
|
} catch (error) {
|
|
743
744
|
throw new NordError(
|
|
@@ -800,7 +801,7 @@ export class NordUser extends NordClient {
|
|
|
800
801
|
: BigInt(params.clientOrderId),
|
|
801
802
|
}),
|
|
802
803
|
});
|
|
803
|
-
|
|
804
|
+
expectReceiptKind(receipt, "placeOrderResult", "place order");
|
|
804
805
|
const result = receipt.kind.value;
|
|
805
806
|
return {
|
|
806
807
|
actionId: receipt.actionId,
|
|
@@ -840,7 +841,7 @@ export class NordUser extends NordClient {
|
|
|
840
841
|
senderAccountId: accountId,
|
|
841
842
|
}),
|
|
842
843
|
});
|
|
843
|
-
|
|
844
|
+
expectReceiptKind(receipt, "cancelOrderResult", "cancel order");
|
|
844
845
|
return {
|
|
845
846
|
actionId: receipt.actionId,
|
|
846
847
|
orderId: receipt.kind.value.orderId,
|
|
@@ -900,7 +901,7 @@ export class NordUser extends NordClient {
|
|
|
900
901
|
accountId: params.accountId,
|
|
901
902
|
}),
|
|
902
903
|
});
|
|
903
|
-
|
|
904
|
+
expectReceiptKind(receipt, "triggerAdded", "add trigger");
|
|
904
905
|
return { actionId: receipt.actionId };
|
|
905
906
|
} catch (error) {
|
|
906
907
|
throw new NordError("Failed to add trigger", { cause: error });
|
|
@@ -939,7 +940,7 @@ export class NordUser extends NordClient {
|
|
|
939
940
|
accountId: params.accountId,
|
|
940
941
|
}),
|
|
941
942
|
});
|
|
942
|
-
|
|
943
|
+
expectReceiptKind(receipt, "triggerRemoved", "remove trigger");
|
|
943
944
|
return { actionId: receipt.actionId };
|
|
944
945
|
} catch (error) {
|
|
945
946
|
throw new NordError("Failed to remove trigger", { cause: error });
|
|
@@ -972,7 +973,7 @@ export class NordUser extends NordClient {
|
|
|
972
973
|
amount,
|
|
973
974
|
}),
|
|
974
975
|
});
|
|
975
|
-
|
|
976
|
+
expectReceiptKind(receipt, "transferred", "transfer tokens");
|
|
976
977
|
} catch (error) {
|
|
977
978
|
throw new NordError("Failed to transfer tokens", { cause: error });
|
|
978
979
|
}
|
package/src/nord/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -96,6 +96,12 @@ export type AccountTriggerInfo = components["schemas"]["AccountTriggerInfo"];
|
|
|
96
96
|
export type TriggerHistoryPage =
|
|
97
97
|
components["schemas"]["PageResult_for_uint64_and_HistoryTriggerInfo"];
|
|
98
98
|
export type HistoryTriggerQuery = components["schemas"]["AccountTriggersQuery"];
|
|
99
|
+
export type FeeTierConfig = components["schemas"]["FeeTierConfig"];
|
|
100
|
+
export type FeeTierId = components["schemas"]["FeeTierId"];
|
|
101
|
+
export type TokenStats = components["schemas"]["TokenStats"];
|
|
102
|
+
export type AccountFeeTier = components["schemas"]["AccountFeeTier"];
|
|
103
|
+
export type AccountFeeTierPage =
|
|
104
|
+
components["schemas"]["PageResult_for_uint32_and_AccountFeeTier"];
|
|
99
105
|
|
|
100
106
|
/**
|
|
101
107
|
* Configuration options for the Nord client
|
package/src/utils.ts
CHANGED
|
@@ -233,6 +233,11 @@ export function checkPubKeyLength(keyType: KeyType, len: number): void {
|
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
+
export function decodeHex(value: string): Uint8Array {
|
|
237
|
+
const hex = value.startsWith("0x") ? value.slice(2) : value;
|
|
238
|
+
return Uint8Array.from(Buffer.from(hex, "hex"));
|
|
239
|
+
}
|
|
240
|
+
|
|
236
241
|
export function findMarket(markets: Market[], marketId: number): Market {
|
|
237
242
|
if (marketId < 0 || markets.length - 1 < marketId) {
|
|
238
243
|
throw new Error(`The market with marketId=${marketId} not found`);
|