@n1xyz/nord-ts 0.1.3 → 0.1.4
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/README.md +2 -2
- package/dist/gen/nord_pb.d.ts +113 -0
- package/dist/gen/nord_pb.js +21 -6
- package/dist/gen/openapi.d.ts +51 -2
- package/dist/nord/api/actions.d.ts +2 -0
- package/dist/nord/api/actions.js +2 -0
- package/dist/nord/client/Nord.d.ts +23 -8
- package/dist/nord/client/Nord.js +58 -8
- package/dist/nord/client/NordAdmin.d.ts +70 -0
- package/dist/nord/client/NordAdmin.js +187 -0
- package/dist/nord/client/NordClient.d.ts +42 -0
- package/dist/nord/client/NordClient.js +93 -0
- package/dist/nord/client/NordUser.d.ts +6 -50
- package/dist/nord/client/NordUser.js +162 -133
- package/dist/nord/index.d.ts +4 -0
- package/dist/nord/index.js +5 -1
- package/dist/types.d.ts +8 -5
- package/package.json +2 -2
- package/src/gen/nord_pb.ts +128 -4
- package/src/gen/openapi.ts +51 -2
- package/src/nord/api/actions.ts +2 -3
- package/src/nord/client/Nord.ts +75 -15
- package/src/nord/client/NordAdmin.ts +232 -0
- package/src/nord/client/NordClient.ts +105 -0
- package/src/nord/client/NordUser.ts +175 -229
- package/src/nord/index.ts +12 -0
- package/src/types.ts +9 -5
- package/src/nord/api/triggers.ts +0 -57
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import * as proto from "../../gen/nord_pb";
|
|
2
|
+
import { create } from "@bufbuild/protobuf";
|
|
3
|
+
import { checkPubKeyLength } from "../../utils";
|
|
4
|
+
import { KeyType } from "../../types";
|
|
5
|
+
import { NordError } from "../utils/NordError";
|
|
6
|
+
import { NordClient } from "./NordClient";
|
|
7
|
+
import type { NordClientParams } from "./NordClient";
|
|
8
|
+
import type { NordUser } from "./NordUser";
|
|
9
|
+
|
|
10
|
+
export interface CreateTokenParams {
|
|
11
|
+
tokenDecimals: number;
|
|
12
|
+
weightBps: number;
|
|
13
|
+
viewSymbol: string;
|
|
14
|
+
oracleSymbol: string;
|
|
15
|
+
solAddr: Uint8Array;
|
|
16
|
+
}
|
|
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
|
+
export interface PythSetWormholeGuardiansParams {
|
|
31
|
+
guardianSetIndex: number;
|
|
32
|
+
addresses: Uint8Array[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface PythSetSymbolFeedParams {
|
|
36
|
+
oracleSymbol: string;
|
|
37
|
+
priceFeedId: Uint8Array;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface FreezeMarketParams {
|
|
41
|
+
marketId: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface UnfreezeMarketParams {
|
|
45
|
+
marketId: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface NordAdminParams extends NordClientParams {
|
|
49
|
+
signFn: (message: Uint8Array) => Promise<Uint8Array>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class NordAdmin extends NordClient {
|
|
53
|
+
private readonly signFn: (message: Uint8Array) => Promise<Uint8Array>;
|
|
54
|
+
|
|
55
|
+
constructor(params: NordAdminParams) {
|
|
56
|
+
const { signFn: adminSignFn, ...clientParams } = params;
|
|
57
|
+
super(clientParams);
|
|
58
|
+
this.signFn = adminSignFn;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
clone(): NordAdmin {
|
|
62
|
+
const copy = new NordAdmin({
|
|
63
|
+
nord: this.nord,
|
|
64
|
+
address: this.address,
|
|
65
|
+
walletSignFn: this.walletSignFn,
|
|
66
|
+
sessionSignFn: this.sessionSignFn,
|
|
67
|
+
transactionSignFn: this.transactionSignFn,
|
|
68
|
+
connection: this.connection,
|
|
69
|
+
sessionId: this.sessionId,
|
|
70
|
+
sessionPubKey: new Uint8Array(this.sessionPubKey),
|
|
71
|
+
publicKey: this.publicKey,
|
|
72
|
+
signFn: this.signFn,
|
|
73
|
+
});
|
|
74
|
+
this.cloneClientState(copy);
|
|
75
|
+
return copy;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static fromUser(
|
|
79
|
+
user: NordUser,
|
|
80
|
+
adminSignFn: (message: Uint8Array) => Promise<Uint8Array>,
|
|
81
|
+
): NordAdmin {
|
|
82
|
+
return new NordAdmin({
|
|
83
|
+
nord: user.nord,
|
|
84
|
+
address: user.address,
|
|
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,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private async submitAction(
|
|
97
|
+
kind: proto.Action["kind"],
|
|
98
|
+
): Promise<proto.Receipt> {
|
|
99
|
+
try {
|
|
100
|
+
return await this.submitSignedAction(kind, async (message) => {
|
|
101
|
+
const signature = await this.signFn(message);
|
|
102
|
+
const signed = new Uint8Array(message.length + signature.length);
|
|
103
|
+
signed.set(message);
|
|
104
|
+
signed.set(signature, message.length);
|
|
105
|
+
return signed;
|
|
106
|
+
});
|
|
107
|
+
} catch (error) {
|
|
108
|
+
throw new NordError(`Admin action ${kind.case} failed`, {
|
|
109
|
+
cause: error,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async createToken(
|
|
115
|
+
params: CreateTokenParams,
|
|
116
|
+
): Promise<{ actionId: bigint } & proto.Receipt_InsertTokenResult> {
|
|
117
|
+
checkPubKeyLength(KeyType.Ed25519, params.solAddr.length);
|
|
118
|
+
const receipt = await this.submitAction({
|
|
119
|
+
case: "createToken",
|
|
120
|
+
value: create(proto.Action_CreateTokenSchema, {
|
|
121
|
+
tokenDecimals: params.tokenDecimals,
|
|
122
|
+
weightBps: params.weightBps,
|
|
123
|
+
viewSymbol: params.viewSymbol,
|
|
124
|
+
oracleSymbol: params.oracleSymbol,
|
|
125
|
+
solAddr: params.solAddr,
|
|
126
|
+
}),
|
|
127
|
+
});
|
|
128
|
+
this.expectReceiptKind(receipt, "insertTokenResult", "create token");
|
|
129
|
+
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async createMarket(
|
|
133
|
+
params: CreateMarketParams,
|
|
134
|
+
): Promise<{ actionId: bigint } & proto.Receipt_InsertMarketResult> {
|
|
135
|
+
const receipt = await this.submitAction({
|
|
136
|
+
case: "createMarket",
|
|
137
|
+
value: create(proto.Action_CreateMarketSchema, {
|
|
138
|
+
sizeDecimals: params.sizeDecimals,
|
|
139
|
+
priceDecimals: params.priceDecimals,
|
|
140
|
+
imfBps: params.imfBps,
|
|
141
|
+
cmfBps: params.cmfBps,
|
|
142
|
+
mmfBps: params.mmfBps,
|
|
143
|
+
marketType: params.marketType,
|
|
144
|
+
viewSymbol: params.viewSymbol,
|
|
145
|
+
oracleSymbol: params.oracleSymbol,
|
|
146
|
+
baseTokenId: params.baseTokenId,
|
|
147
|
+
}),
|
|
148
|
+
});
|
|
149
|
+
this.expectReceiptKind(receipt, "insertMarketResult", "create market");
|
|
150
|
+
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async pythSetWormholeGuardians(
|
|
154
|
+
params: PythSetWormholeGuardiansParams,
|
|
155
|
+
): Promise<{ actionId: bigint } & proto.Receipt_UpdateGuardianSetResult> {
|
|
156
|
+
const receipt = await this.submitAction({
|
|
157
|
+
case: "pythSetWormholeGuardians",
|
|
158
|
+
value: create(proto.Action_PythSetWormholeGuardiansSchema, {
|
|
159
|
+
guardianSetIndex: params.guardianSetIndex,
|
|
160
|
+
addresses: params.addresses,
|
|
161
|
+
}),
|
|
162
|
+
});
|
|
163
|
+
this.expectReceiptKind(
|
|
164
|
+
receipt,
|
|
165
|
+
"updateGuardianSetResult",
|
|
166
|
+
"update wormhole guardians",
|
|
167
|
+
);
|
|
168
|
+
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async pythSetSymbolFeed(
|
|
172
|
+
params: PythSetSymbolFeedParams,
|
|
173
|
+
): Promise<{ actionId: bigint } & proto.Receipt_OracleSymbolFeedResult> {
|
|
174
|
+
const receipt = await this.submitAction({
|
|
175
|
+
case: "pythSetSymbolFeed",
|
|
176
|
+
value: create(proto.Action_PythSetSymbolFeedSchema, {
|
|
177
|
+
oracleSymbol: params.oracleSymbol,
|
|
178
|
+
priceFeedId: params.priceFeedId,
|
|
179
|
+
}),
|
|
180
|
+
});
|
|
181
|
+
this.expectReceiptKind(
|
|
182
|
+
receipt,
|
|
183
|
+
"oracleSymbolFeedResult",
|
|
184
|
+
"set symbol feed",
|
|
185
|
+
);
|
|
186
|
+
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async pause(): Promise<{ actionId: bigint }> {
|
|
190
|
+
const receipt = await this.submitAction({
|
|
191
|
+
case: "pause",
|
|
192
|
+
value: create(proto.Action_PauseSchema, {}),
|
|
193
|
+
});
|
|
194
|
+
this.expectReceiptKind(receipt, "paused", "pause");
|
|
195
|
+
return { actionId: receipt.actionId };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async unpause(): Promise<{ actionId: bigint }> {
|
|
199
|
+
const receipt = await this.submitAction({
|
|
200
|
+
case: "unpause",
|
|
201
|
+
value: create(proto.Action_UnpauseSchema, {}),
|
|
202
|
+
});
|
|
203
|
+
this.expectReceiptKind(receipt, "unpaused", "unpause");
|
|
204
|
+
return { actionId: receipt.actionId };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async freezeMarket(
|
|
208
|
+
params: FreezeMarketParams,
|
|
209
|
+
): Promise<{ actionId: bigint } & proto.Receipt_MarketFreezeUpdated> {
|
|
210
|
+
const receipt = await this.submitAction({
|
|
211
|
+
case: "freezeMarket",
|
|
212
|
+
value: create(proto.Action_FreezeMarketSchema, {
|
|
213
|
+
marketId: params.marketId,
|
|
214
|
+
}),
|
|
215
|
+
});
|
|
216
|
+
this.expectReceiptKind(receipt, "marketFreezeUpdated", "freeze market");
|
|
217
|
+
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async unfreezeMarket(
|
|
221
|
+
params: UnfreezeMarketParams,
|
|
222
|
+
): Promise<{ actionId: bigint } & proto.Receipt_MarketFreezeUpdated> {
|
|
223
|
+
const receipt = await this.submitAction({
|
|
224
|
+
case: "unfreezeMarket",
|
|
225
|
+
value: create(proto.Action_UnfreezeMarketSchema, {
|
|
226
|
+
marketId: params.marketId,
|
|
227
|
+
}),
|
|
228
|
+
});
|
|
229
|
+
this.expectReceiptKind(receipt, "marketFreezeUpdated", "unfreeze market");
|
|
230
|
+
return { actionId: receipt.actionId, ...receipt.kind.value };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Connection, PublicKey } from "@solana/web3.js";
|
|
2
|
+
import type { Transaction } from "@solana/web3.js";
|
|
3
|
+
import * as proto from "../../gen/nord_pb";
|
|
4
|
+
import { createAction, sendAction } from "../api/actions";
|
|
5
|
+
import { NordError } from "../utils/NordError";
|
|
6
|
+
import { Nord } from "./Nord";
|
|
7
|
+
|
|
8
|
+
type ReceiptKind = NonNullable<proto.Receipt["kind"]>;
|
|
9
|
+
type ExtractReceiptKind<K extends ReceiptKind["case"]> = Extract<
|
|
10
|
+
ReceiptKind,
|
|
11
|
+
{ case: K }
|
|
12
|
+
>;
|
|
13
|
+
|
|
14
|
+
export interface NordClientParams {
|
|
15
|
+
nord: Nord;
|
|
16
|
+
address: PublicKey;
|
|
17
|
+
walletSignFn: (message: Uint8Array | string) => Promise<Uint8Array>;
|
|
18
|
+
sessionSignFn: (message: Uint8Array) => Promise<Uint8Array>;
|
|
19
|
+
transactionSignFn: <T extends Transaction>(tx: T) => Promise<T>;
|
|
20
|
+
connection?: Connection;
|
|
21
|
+
sessionId?: bigint;
|
|
22
|
+
sessionPubKey: Uint8Array;
|
|
23
|
+
publicKey: PublicKey;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export abstract class NordClient {
|
|
27
|
+
public readonly nord: Nord;
|
|
28
|
+
public readonly address: PublicKey;
|
|
29
|
+
public readonly walletSignFn: (
|
|
30
|
+
message: Uint8Array | string,
|
|
31
|
+
) => Promise<Uint8Array>;
|
|
32
|
+
public readonly sessionSignFn: (message: Uint8Array) => Promise<Uint8Array>;
|
|
33
|
+
public readonly transactionSignFn: <T extends Transaction>(
|
|
34
|
+
tx: T,
|
|
35
|
+
) => Promise<T>;
|
|
36
|
+
public connection: Connection;
|
|
37
|
+
public sessionId?: bigint;
|
|
38
|
+
public sessionPubKey: Uint8Array;
|
|
39
|
+
public publicKey: PublicKey;
|
|
40
|
+
public lastTs = 0;
|
|
41
|
+
|
|
42
|
+
protected actionNonce = 0;
|
|
43
|
+
|
|
44
|
+
protected constructor(params: NordClientParams) {
|
|
45
|
+
this.nord = params.nord;
|
|
46
|
+
this.address = params.address;
|
|
47
|
+
this.walletSignFn = params.walletSignFn;
|
|
48
|
+
this.sessionSignFn = params.sessionSignFn;
|
|
49
|
+
this.transactionSignFn = params.transactionSignFn;
|
|
50
|
+
this.connection =
|
|
51
|
+
params.connection ??
|
|
52
|
+
new Connection(params.nord.solanaUrl, {
|
|
53
|
+
commitment: "confirmed",
|
|
54
|
+
});
|
|
55
|
+
this.sessionId = params.sessionId;
|
|
56
|
+
this.sessionPubKey = new Uint8Array(params.sessionPubKey);
|
|
57
|
+
this.publicKey = params.publicKey;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
protected async submitSignedAction(
|
|
61
|
+
kind: proto.Action["kind"],
|
|
62
|
+
makeSignedMessage: (message: Uint8Array) => Promise<Uint8Array>,
|
|
63
|
+
): Promise<proto.Receipt> {
|
|
64
|
+
const nonce = this.nextActionNonce();
|
|
65
|
+
const currentTimestamp = await this.nord.getTimestamp();
|
|
66
|
+
const action = createAction(currentTimestamp, nonce, kind);
|
|
67
|
+
return sendAction(this.nord.webServerUrl, makeSignedMessage, action);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
protected nextActionNonce(): number {
|
|
71
|
+
return ++this.actionNonce;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
protected cloneClientState(target: NordClient): void {
|
|
75
|
+
target.connection = this.connection;
|
|
76
|
+
target.sessionId = this.sessionId;
|
|
77
|
+
target.sessionPubKey = new Uint8Array(this.sessionPubKey);
|
|
78
|
+
target.publicKey = this.publicKey;
|
|
79
|
+
target.lastTs = this.lastTs;
|
|
80
|
+
target.actionNonce = this.actionNonce;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
getSolanaPublicKey(): PublicKey {
|
|
84
|
+
return this.address;
|
|
85
|
+
}
|
|
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
|
+
}
|