@n1xyz/nord-ts 0.0.16 → 0.0.17
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/bridge/client.js +45 -6
- package/dist/gen/nord.d.ts +48 -4
- package/dist/gen/nord.js +633 -33
- package/dist/idl/bridge.d.ts +569 -0
- package/dist/idl/bridge.js +8 -0
- package/dist/idl/bridge.json +75 -62
- package/dist/idl/index.d.ts +71 -49
- package/dist/index.d.ts +1 -3
- package/dist/index.js +6 -13
- package/dist/nord/api/actions.d.ts +7 -2
- package/dist/nord/api/actions.js +7 -1
- package/dist/nord/api/core.d.ts +1 -1
- package/dist/nord/api/core.js +3 -3
- package/dist/nord/api/market.js +1 -3
- package/dist/nord/api/queries.js +2 -2
- package/dist/nord/client/Nord.d.ts +9 -14
- package/dist/nord/client/Nord.js +27 -38
- package/dist/nord/client/NordUser.d.ts +7 -23
- package/dist/nord/client/NordUser.js +66 -143
- package/dist/nord/utils/NordError.js +5 -2
- package/dist/types.d.ts +34 -50
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +14 -0
- package/package.json +18 -18
- package/protoc-generate.sh +0 -0
- package/src/idl/bridge.json +75 -62
- package/src/index.ts +9 -12
- package/src/nord/api/actions.ts +14 -3
- package/src/nord/api/core.ts +4 -2
- package/src/nord/api/market.ts +1 -4
- package/src/nord/api/queries.ts +2 -2
- package/src/nord/client/Nord.ts +45 -50
- package/src/nord/client/NordUser.ts +89 -169
- package/src/nord/utils/NordError.ts +6 -2
- package/src/types.ts +34 -49
- package/src/utils.ts +18 -0
- package/codebase.md +0 -18886
- package/docs/.nojekyll +0 -1
- package/docs/assets/hierarchy.js +0 -1
- package/docs/assets/highlight.css +0 -92
- package/docs/assets/icons.js +0 -18
- package/docs/assets/icons.svg +0 -1
- package/docs/assets/main.js +0 -60
- package/docs/assets/navigation.js +0 -1
- package/docs/assets/search.js +0 -1
- package/docs/assets/style.css +0 -1611
- package/docs/classes/Nord.html +0 -189
- package/docs/classes/NordError.html +0 -24
- package/docs/classes/NordUser.html +0 -115
- package/docs/classes/NordWebSocketClient.html +0 -330
- package/docs/classes/SolanaBridgeClient.html +0 -91
- package/docs/classes/Subscriber.html +0 -10
- package/docs/enums/FillMode.html +0 -5
- package/docs/enums/KeyType.html +0 -4
- package/docs/enums/MetricPeriod.html +0 -9
- package/docs/enums/PdaSeedType.html +0 -11
- package/docs/enums/PeakTpsPeriodUnit.html +0 -15
- package/docs/enums/Side.html +0 -3
- package/docs/enums/WebSocketMessageType.html +0 -7
- package/docs/functions/actionQueryRollman.html +0 -6
- package/docs/functions/actionsQueryRollman.html +0 -6
- package/docs/functions/aggregateMetrics-1.html +0 -7
- package/docs/functions/assert.html +0 -1
- package/docs/functions/bigIntToProtoU128.html +0 -4
- package/docs/functions/bridgeToBN.html +0 -5
- package/docs/functions/bufferToHex.html +0 -4
- package/docs/functions/cancelOrder.html +0 -1
- package/docs/functions/checkPubKeyLength.html +0 -1
- package/docs/functions/checkedFetch.html +0 -6
- package/docs/functions/createSession.html +0 -1
- package/docs/functions/decodeLengthDelimited.html +0 -11
- package/docs/functions/encodeLengthDelimited.html +0 -6
- package/docs/functions/fillModeToProtoFillMode.html +0 -5
- package/docs/functions/findMarket.html +0 -1
- package/docs/functions/findPda.html +0 -6
- package/docs/functions/findToken.html +0 -1
- package/docs/functions/fromBN.html +0 -5
- package/docs/functions/getAccount.html +0 -6
- package/docs/functions/getActionNonce.html +0 -5
- package/docs/functions/getCurrentTps.html +0 -6
- package/docs/functions/getInfo.html +0 -5
- package/docs/functions/getLastActionId.html +0 -5
- package/docs/functions/getMedianLatency.html +0 -6
- package/docs/functions/getOrderbook.html +0 -6
- package/docs/functions/getPeakTps.html +0 -6
- package/docs/functions/getTimestamp.html +0 -5
- package/docs/functions/getTotalTransactions.html +0 -5
- package/docs/functions/getTrades.html +0 -6
- package/docs/functions/getUserAccountIds.html +0 -6
- package/docs/functions/hexToBuffer.html +0 -4
- package/docs/functions/initWebSocketClient.html +0 -12
- package/docs/functions/keypairFromPrivateKey.html +0 -4
- package/docs/functions/makeSigningFunction.html +0 -4
- package/docs/functions/makeWalletSignFn.html +0 -6
- package/docs/functions/marketsStats.html +0 -5
- package/docs/functions/optExpect.html +0 -5
- package/docs/functions/optMap.html +0 -5
- package/docs/functions/optUnwrap.html +0 -2
- package/docs/functions/panic.html +0 -1
- package/docs/functions/placeOrder.html +0 -1
- package/docs/functions/queryAction.html +0 -6
- package/docs/functions/queryPrometheus.html +0 -6
- package/docs/functions/queryRecentActions.html +0 -7
- package/docs/functions/revokeSession.html +0 -1
- package/docs/functions/shortenPublicKey.html +0 -5
- package/docs/functions/signAction.html +0 -6
- package/docs/functions/toBN.html +0 -5
- package/docs/functions/toScaledU128.html +0 -8
- package/docs/functions/toScaledU64.html +0 -8
- package/docs/functions/transfer.html +0 -1
- package/docs/functions/withdraw.html +0 -1
- package/docs/hierarchy.html +0 -1
- package/docs/index.html +0 -40
- package/docs/interfaces/Account.html +0 -8
- package/docs/interfaces/ActionInfo.html +0 -8
- package/docs/interfaces/ActionNonceResponse.html +0 -3
- package/docs/interfaces/ActionQuery.html +0 -4
- package/docs/interfaces/ActionResponse.html +0 -8
- package/docs/interfaces/ActionsExtendedInfo.html +0 -10
- package/docs/interfaces/ActionsQuery.html +0 -5
- package/docs/interfaces/ActionsResponse.html +0 -6
- package/docs/interfaces/AggregateMetrics.html +0 -12
- package/docs/interfaces/BlockFacts.html +0 -10
- package/docs/interfaces/BlockQuery.html +0 -6
- package/docs/interfaces/BlockResponse.html +0 -6
- package/docs/interfaces/BlockSummary.html +0 -8
- package/docs/interfaces/BlockSummaryResponse.html +0 -6
- package/docs/interfaces/DeltaEvent.html +0 -6
- package/docs/interfaces/DepositSplParams.html +0 -8
- package/docs/interfaces/Info.html +0 -3
- package/docs/interfaces/Market.html +0 -8
- package/docs/interfaces/MarketStats.html +0 -7
- package/docs/interfaces/MarketsStatsResponse.html +0 -2
- package/docs/interfaces/NordConfig.html +0 -24
- package/docs/interfaces/NordWebSocketClientEvents.html +0 -4
- package/docs/interfaces/NordWebSocketEvents.html +0 -8
- package/docs/interfaces/Order.html +0 -6
- package/docs/interfaces/OrderInfo.html +0 -6
- package/docs/interfaces/OrderbookEntry.html +0 -4
- package/docs/interfaces/OrderbookQuery.html +0 -6
- package/docs/interfaces/OrderbookResponse.html +0 -6
- package/docs/interfaces/OrderbookSubscription.html +0 -159
- package/docs/interfaces/PerpMarketStats.html +0 -5
- package/docs/interfaces/RollmanActionExtendedInfo.html +0 -4
- package/docs/interfaces/RollmanActionInfo.html +0 -4
- package/docs/interfaces/RollmanActionResponse.html +0 -4
- package/docs/interfaces/RollmanActionsResponse.html +0 -2
- package/docs/interfaces/RollmanBlockResponse.html +0 -3
- package/docs/interfaces/SPLTokenInfo.html +0 -10
- package/docs/interfaces/SolanaBridgeConfig.html +0 -12
- package/docs/interfaces/StateFacts.html +0 -10
- package/docs/interfaces/SubscriberConfig.html +0 -3
- package/docs/interfaces/TimestampResponse.html +0 -3
- package/docs/interfaces/Token.html +0 -5
- package/docs/interfaces/TokenInfo.html +0 -6
- package/docs/interfaces/Trade.html +0 -5
- package/docs/interfaces/TradeSubscription.html +0 -159
- package/docs/interfaces/Trades.html +0 -5
- package/docs/interfaces/TradesQuery.html +0 -6
- package/docs/interfaces/TradesResponse.html +0 -7
- package/docs/interfaces/TransferParams.html +0 -8
- package/docs/interfaces/UserAccountIdsQuery.html +0 -3
- package/docs/interfaces/UserAccountIdsResponse.html +0 -3
- package/docs/interfaces/WebSocketAccountUpdate.html +0 -6
- package/docs/interfaces/WebSocketDeltaUpdate.html +0 -9
- package/docs/interfaces/WebSocketSubscription.html +0 -4
- package/docs/interfaces/WebSocketTradeUpdate.html +0 -6
- package/docs/interfaces/WithdrawalClaim.html +0 -14
- package/docs/interfaces/WithdrawalParams.html +0 -8
- package/docs/modules.html +0 -1
- package/docs/types/BigIntValue.html +0 -2
- package/docs/types/SubscriptionPattern.html +0 -4
- package/docs/types/SubscriptionType.html +0 -2
- package/docs/types/WebSocketMessage.html +0 -1
- package/docs/variables/DEBUG_KEYS.html +0 -1
- package/docs/variables/DEFAULT_FUNDING_AMOUNTS.html +0 -1
- package/docs/variables/DEV_TOKEN_INFOS.html +0 -1
- package/docs/variables/DEV_URL.html +0 -1
- package/docs/variables/MAX_BUFFER_LEN.html +0 -1
- package/docs/variables/SESSION_TTL.html +0 -1
- package/docs/variables/WEBSERVER_DEV_URL.html +0 -1
- package/docs/variables/ZERO_DECIMAL.html +0 -1
- package/docs/variables/_private.html +0 -2
- package/idl-generate.sh +0 -4
- package/src/bridge/client.ts +0 -498
- package/src/bridge/const.ts +0 -53
- package/src/bridge/index.ts +0 -6
- package/src/bridge/types.ts +0 -129
- package/src/bridge/utils.ts +0 -140
- package/src/gen/common.ts +0 -297
- package/src/gen/nord.ts +0 -6716
- package/src/idl/index.ts +0 -2
package/src/nord/client/Nord.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { EventEmitter } from "events";
|
|
2
|
-
import { Connection, PublicKey } from "@solana/web3.js";
|
|
3
2
|
import {
|
|
4
3
|
Account,
|
|
5
4
|
ActionQuery,
|
|
@@ -22,6 +21,7 @@ import {
|
|
|
22
21
|
UserAccountIdsQuery,
|
|
23
22
|
UserAccountIdsResponse,
|
|
24
23
|
} from "../../types";
|
|
24
|
+
import { ProtonClient } from "@n1xyz/proton";
|
|
25
25
|
import { NordWebSocketClient } from "../../websocket/index";
|
|
26
26
|
import * as core from "../api/core";
|
|
27
27
|
import * as market from "../api/market";
|
|
@@ -29,6 +29,7 @@ import * as metrics from "../api/metrics";
|
|
|
29
29
|
import * as queries from "../api/queries";
|
|
30
30
|
import { OrderbookSubscription, TradeSubscription } from "../models/Subscriber";
|
|
31
31
|
import { NordError } from "../utils/NordError";
|
|
32
|
+
import { PublicKey, Connection } from "@solana/web3.js";
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* User subscription interface
|
|
@@ -57,10 +58,7 @@ export class Nord {
|
|
|
57
58
|
public readonly webServerUrl: string;
|
|
58
59
|
|
|
59
60
|
/** Bridge verification key */
|
|
60
|
-
public readonly bridgeVk:
|
|
61
|
-
|
|
62
|
-
/** Optional Solana program ID (will be derived from bridgeVk) */
|
|
63
|
-
private _solanaProgramId!: string;
|
|
61
|
+
public readonly bridgeVk: PublicKey;
|
|
64
62
|
|
|
65
63
|
/** Solana RPC URL */
|
|
66
64
|
public readonly solanaUrl: string;
|
|
@@ -74,6 +72,9 @@ export class Nord {
|
|
|
74
72
|
/** Map of symbol to market_id */
|
|
75
73
|
private symbolToMarketId: Map<string, number> = new Map();
|
|
76
74
|
|
|
75
|
+
/** Proton client for bridge and indexd operations */
|
|
76
|
+
public protonClient: ProtonClient;
|
|
77
|
+
|
|
77
78
|
/**
|
|
78
79
|
* Create a new Nord client
|
|
79
80
|
*
|
|
@@ -83,22 +84,21 @@ export class Nord {
|
|
|
83
84
|
* @param config.solanaUrl - Solana cluster URL
|
|
84
85
|
* @throws {Error} If required configuration is missing
|
|
85
86
|
*/
|
|
86
|
-
constructor(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.
|
|
100
|
-
this.
|
|
101
|
-
this.solanaUrl = config.solanaUrl;
|
|
87
|
+
private constructor({
|
|
88
|
+
bridgeVk,
|
|
89
|
+
solanaUrl,
|
|
90
|
+
webServerUrl,
|
|
91
|
+
protonClient,
|
|
92
|
+
}: Readonly<{
|
|
93
|
+
bridgeVk: PublicKey;
|
|
94
|
+
solanaUrl: string;
|
|
95
|
+
webServerUrl: string;
|
|
96
|
+
protonClient: ProtonClient;
|
|
97
|
+
}>) {
|
|
98
|
+
this.webServerUrl = webServerUrl;
|
|
99
|
+
this.bridgeVk = bridgeVk;
|
|
100
|
+
this.solanaUrl = solanaUrl;
|
|
101
|
+
this.protonClient = protonClient;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/**
|
|
@@ -173,13 +173,13 @@ export class Nord {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
/**
|
|
176
|
-
* Get the
|
|
176
|
+
* Get the last event nonce from the Nord server
|
|
177
177
|
*
|
|
178
178
|
* @returns Next action nonce
|
|
179
179
|
* @throws {NordError} If the request fails
|
|
180
180
|
*/
|
|
181
181
|
async getActionNonce(): Promise<number> {
|
|
182
|
-
return core.
|
|
182
|
+
return core.getLastEventNonce(this.webServerUrl);
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
/**
|
|
@@ -213,44 +213,39 @@ export class Nord {
|
|
|
213
213
|
* @returns Initialized Nord client
|
|
214
214
|
* @throws {NordError} If initialization fails
|
|
215
215
|
*/
|
|
216
|
-
public static async initNord(
|
|
217
|
-
|
|
216
|
+
public static async initNord({
|
|
217
|
+
bridgeVk: bridgeVk_,
|
|
218
|
+
solanaUrl,
|
|
219
|
+
webServerUrl,
|
|
220
|
+
}: Readonly<NordConfig>): Promise<Nord> {
|
|
221
|
+
// TODO: we should parametrize the connectionn not have it done here.
|
|
222
|
+
// this is a dogshit api, only here to be compatible with the shitty
|
|
223
|
+
// vibecoded code and not break zero one team's workflow.
|
|
224
|
+
const connection = new Connection(solanaUrl, { commitment: "confirmed" });
|
|
225
|
+
const bridgeVk = new PublicKey(bridgeVk_);
|
|
226
|
+
const protonClient = await ProtonClient.init({
|
|
227
|
+
protonUrl: webServerUrl,
|
|
228
|
+
bridgeVk,
|
|
229
|
+
solConn: connection,
|
|
230
|
+
});
|
|
231
|
+
const nord = new Nord({
|
|
232
|
+
bridgeVk,
|
|
233
|
+
protonClient,
|
|
234
|
+
solanaUrl,
|
|
235
|
+
webServerUrl,
|
|
236
|
+
});
|
|
218
237
|
await nord.init();
|
|
219
238
|
return nord;
|
|
220
239
|
}
|
|
221
240
|
|
|
222
241
|
/**
|
|
223
|
-
* Initialize the Nord client
|
|
242
|
+
* Initialize the Nord client
|
|
224
243
|
* @private
|
|
225
244
|
*/
|
|
226
245
|
private async init(): Promise<void> {
|
|
227
|
-
const connection = new Connection(this.solanaUrl);
|
|
228
|
-
const bridgeVkPubkey = new PublicKey(this.bridgeVk);
|
|
229
|
-
|
|
230
|
-
const bridgeAccount = await connection.getAccountInfo(bridgeVkPubkey);
|
|
231
|
-
if (!bridgeAccount) {
|
|
232
|
-
throw new NordError(`Bridge account ${this.bridgeVk} not found`);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
this._solanaProgramId = bridgeAccount.owner.toString();
|
|
236
246
|
await this.fetchNordInfo();
|
|
237
247
|
}
|
|
238
248
|
|
|
239
|
-
/**
|
|
240
|
-
* Get the Solana program ID derived from bridge VK
|
|
241
|
-
*
|
|
242
|
-
* @returns Program ID string
|
|
243
|
-
* @throws {NordError} If program ID hasn't been initialized
|
|
244
|
-
*/
|
|
245
|
-
public getSolanaProgramId(): string {
|
|
246
|
-
if (!this._solanaProgramId) {
|
|
247
|
-
throw new NordError(
|
|
248
|
-
"Solana program ID not initialized. Have you called Nord.initNord()?",
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
return this._solanaProgramId;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
249
|
/**
|
|
255
250
|
* Get market statistics
|
|
256
251
|
*
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import * as anchor from "@coral-xyz/anchor";
|
|
2
1
|
import {
|
|
3
2
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
4
3
|
getAssociatedTokenAddress,
|
|
4
|
+
TOKEN_PROGRAM_ID,
|
|
5
5
|
TOKEN_2022_PROGRAM_ID,
|
|
6
6
|
} from "@solana/spl-token";
|
|
7
|
-
import { Connection,
|
|
7
|
+
import { Connection, PublicKey, Transaction } from "@solana/web3.js";
|
|
8
8
|
import Decimal from "decimal.js";
|
|
9
9
|
import * as ed from "@noble/ed25519";
|
|
10
10
|
import { sha512 } from "@noble/hashes/sha512";
|
|
11
11
|
ed.etc.sha512Sync = sha512;
|
|
12
|
-
import {
|
|
13
|
-
import { SPLTokenInfo } from "../../bridge/types";
|
|
14
|
-
import { keypairFromPrivateKey } from "../../bridge/utils";
|
|
12
|
+
import { SPLTokenInfo, DepositSplParams } from "@n1xyz/proton";
|
|
15
13
|
import { FillMode, Order, Side } from "../../types";
|
|
16
14
|
import {
|
|
17
15
|
BigIntValue,
|
|
@@ -20,6 +18,7 @@ import {
|
|
|
20
18
|
findToken,
|
|
21
19
|
optExpect,
|
|
22
20
|
toBN as utilsToBN,
|
|
21
|
+
keypairFromPrivateKey,
|
|
23
22
|
} from "../../utils";
|
|
24
23
|
import {
|
|
25
24
|
cancelOrder,
|
|
@@ -121,7 +120,7 @@ export class NordUser {
|
|
|
121
120
|
public readonly nord: Nord;
|
|
122
121
|
|
|
123
122
|
/** User's blockchain address */
|
|
124
|
-
public readonly address:
|
|
123
|
+
public readonly address: PublicKey;
|
|
125
124
|
|
|
126
125
|
/** Function to sign messages with the user's wallet */
|
|
127
126
|
public readonly walletSignFn: (
|
|
@@ -191,10 +190,6 @@ export class NordUser {
|
|
|
191
190
|
/** Last nonce used */
|
|
192
191
|
public lastNonce = 0;
|
|
193
192
|
|
|
194
|
-
// Solana-specific properties
|
|
195
|
-
/** Solana bridge client */
|
|
196
|
-
public bridgeClient?: SolanaBridgeClient;
|
|
197
|
-
|
|
198
193
|
/** Solana connection */
|
|
199
194
|
public connection: Connection;
|
|
200
195
|
|
|
@@ -207,46 +202,48 @@ export class NordUser {
|
|
|
207
202
|
* @param params - Parameters for creating a NordUser
|
|
208
203
|
* @throws {NordError} If required parameters are missing
|
|
209
204
|
*/
|
|
210
|
-
constructor(
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
205
|
+
constructor({
|
|
206
|
+
address,
|
|
207
|
+
nord,
|
|
208
|
+
publicKey,
|
|
209
|
+
sessionPubKey,
|
|
210
|
+
sessionSignFn,
|
|
211
|
+
transactionSignFn,
|
|
212
|
+
walletSignFn,
|
|
213
|
+
connection,
|
|
214
|
+
sessionId,
|
|
215
|
+
}: NordUserParams) {
|
|
216
|
+
if (!walletSignFn) {
|
|
218
217
|
throw new NordError("Wallet sign function is required");
|
|
219
218
|
}
|
|
220
|
-
if (!
|
|
219
|
+
if (!sessionSignFn) {
|
|
221
220
|
throw new NordError("Session sign function is required");
|
|
222
221
|
}
|
|
223
|
-
if (!
|
|
222
|
+
if (!sessionPubKey) {
|
|
224
223
|
throw new NordError("Session public key is required");
|
|
225
224
|
}
|
|
226
225
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
this.
|
|
226
|
+
try {
|
|
227
|
+
this.address = new PublicKey(address);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
throw new NordError("Invalid Solana address", { cause: error });
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this.nord = nord;
|
|
233
|
+
this.walletSignFn = walletSignFn;
|
|
234
|
+
this.sessionSignFn = sessionSignFn;
|
|
235
|
+
this.transactionSignFn = transactionSignFn;
|
|
236
|
+
this.sessionPubKey = sessionPubKey;
|
|
237
|
+
this.publicKey = publicKey;
|
|
234
238
|
this.connection =
|
|
235
|
-
|
|
236
|
-
new Connection(
|
|
239
|
+
connection ||
|
|
240
|
+
new Connection(nord.solanaUrl, {
|
|
237
241
|
commitment: "confirmed",
|
|
238
242
|
});
|
|
239
243
|
|
|
240
244
|
// Set sessionId if provided
|
|
241
|
-
if (
|
|
242
|
-
this.sessionId =
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Initialize bridge client if needed
|
|
246
|
-
try {
|
|
247
|
-
this.initBridgeClient();
|
|
248
|
-
} catch (error) {
|
|
249
|
-
console.warn("Failed to initialize bridge client:", error);
|
|
245
|
+
if (sessionId !== undefined) {
|
|
246
|
+
this.sessionId = sessionId;
|
|
250
247
|
}
|
|
251
248
|
|
|
252
249
|
// Convert tokens from info endpoint to SPLTokenInfo
|
|
@@ -268,7 +265,7 @@ export class NordUser {
|
|
|
268
265
|
clone(): NordUser {
|
|
269
266
|
const cloned = new NordUser({
|
|
270
267
|
nord: this.nord,
|
|
271
|
-
address: this.address,
|
|
268
|
+
address: this.address.toBase58(),
|
|
272
269
|
walletSignFn: this.walletSignFn,
|
|
273
270
|
sessionSignFn: this.sessionSignFn,
|
|
274
271
|
transactionSignFn: this.transactionSignFn,
|
|
@@ -292,56 +289,6 @@ export class NordUser {
|
|
|
292
289
|
return cloned;
|
|
293
290
|
}
|
|
294
291
|
|
|
295
|
-
/**
|
|
296
|
-
* Initialize the Solana bridge client
|
|
297
|
-
*
|
|
298
|
-
* @private
|
|
299
|
-
* @throws {NordError} If required parameters are missing
|
|
300
|
-
*/
|
|
301
|
-
private initBridgeClient(): void {
|
|
302
|
-
if (
|
|
303
|
-
!this.getSolanaPublicKey() ||
|
|
304
|
-
!this.connection ||
|
|
305
|
-
!this.nord.getSolanaProgramId()
|
|
306
|
-
) {
|
|
307
|
-
throw new NordError(
|
|
308
|
-
"Solana public key, connection, and program ID are required to initialize bridge client",
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Create an Anchor wallet that uses walletSignFn for signing
|
|
313
|
-
const wallet: anchor.Wallet = {
|
|
314
|
-
publicKey: this.getSolanaPublicKey(),
|
|
315
|
-
signTransaction: async (tx: any) => {
|
|
316
|
-
return await this.transactionSignFn(tx);
|
|
317
|
-
},
|
|
318
|
-
signAllTransactions: async (txs: any[]) => {
|
|
319
|
-
return Promise.all(
|
|
320
|
-
txs.map(async (tx) => {
|
|
321
|
-
return await this.transactionSignFn(tx);
|
|
322
|
-
}),
|
|
323
|
-
);
|
|
324
|
-
},
|
|
325
|
-
// Create a keypair-like object with just the public key
|
|
326
|
-
payer: {
|
|
327
|
-
publicKey: this.getSolanaPublicKey(),
|
|
328
|
-
secretKey: new Uint8Array(64), // Dummy secret key to satisfy the type
|
|
329
|
-
} as Keypair,
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
// Initialize the bridge client
|
|
333
|
-
this.bridgeClient = new SolanaBridgeClient(
|
|
334
|
-
{
|
|
335
|
-
rpcUrl: this.connection.rpcEndpoint,
|
|
336
|
-
programId: this.nord.getSolanaProgramId(),
|
|
337
|
-
commitment: "confirmed",
|
|
338
|
-
tokenInfos: this.splTokenInfos,
|
|
339
|
-
bridgeVk: this.nord.bridgeVk,
|
|
340
|
-
},
|
|
341
|
-
wallet,
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
292
|
/**
|
|
346
293
|
* Create a NordUser from a private key
|
|
347
294
|
*
|
|
@@ -391,9 +338,9 @@ export class NordUser {
|
|
|
391
338
|
// Create a transaction signing function
|
|
392
339
|
const transactionSignFn = async (transaction: any): Promise<any> => {
|
|
393
340
|
// This is a basic implementation - actual implementation would depend on the transaction type
|
|
394
|
-
if (transaction.
|
|
341
|
+
if (transaction.sign) {
|
|
395
342
|
// Solana transaction
|
|
396
|
-
transaction.sign(
|
|
343
|
+
transaction.sign(keypair);
|
|
397
344
|
return transaction;
|
|
398
345
|
}
|
|
399
346
|
|
|
@@ -433,13 +380,31 @@ export class NordUser {
|
|
|
433
380
|
}
|
|
434
381
|
|
|
435
382
|
try {
|
|
436
|
-
|
|
383
|
+
// Get the token program ID from the mint account
|
|
384
|
+
const mintAccount = await this.connection.getAccountInfo(mint);
|
|
385
|
+
if (!mintAccount) {
|
|
386
|
+
throw new NordError("Mint account not found");
|
|
387
|
+
}
|
|
388
|
+
const tokenProgramId = mintAccount.owner;
|
|
389
|
+
|
|
390
|
+
// Validate that the mint is owned by a supported SPL token program
|
|
391
|
+
if (
|
|
392
|
+
!tokenProgramId.equals(TOKEN_PROGRAM_ID) &&
|
|
393
|
+
!tokenProgramId.equals(TOKEN_2022_PROGRAM_ID)
|
|
394
|
+
) {
|
|
395
|
+
throw new NordError(
|
|
396
|
+
"Mint Account is not owned by a supported SPL token program",
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const associatedTokenAddress = await getAssociatedTokenAddress(
|
|
437
401
|
mint,
|
|
438
402
|
this.getSolanaPublicKey(),
|
|
439
403
|
false,
|
|
440
|
-
|
|
404
|
+
tokenProgramId,
|
|
441
405
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
442
406
|
);
|
|
407
|
+
return associatedTokenAddress;
|
|
443
408
|
} catch (error) {
|
|
444
409
|
throw new NordError("Failed to get associated token account", {
|
|
445
410
|
cause: error,
|
|
@@ -456,12 +421,6 @@ export class NordUser {
|
|
|
456
421
|
* @throws {NordError} If required parameters are missing or operation fails
|
|
457
422
|
*/
|
|
458
423
|
async depositSpl(amount: number, tokenId: number): Promise<string> {
|
|
459
|
-
if (!this.bridgeClient || !this.getSolanaPublicKey() || !this.connection) {
|
|
460
|
-
throw new NordError(
|
|
461
|
-
"Bridge client, Solana public key, and connection are required for deposit",
|
|
462
|
-
);
|
|
463
|
-
}
|
|
464
|
-
|
|
465
424
|
try {
|
|
466
425
|
// Find the token info
|
|
467
426
|
const tokenInfo = this.splTokenInfos.find((t) => t.tokenId === tokenId);
|
|
@@ -472,82 +431,43 @@ export class NordUser {
|
|
|
472
431
|
const mint = new PublicKey(tokenInfo.mint);
|
|
473
432
|
// Get the user's token account
|
|
474
433
|
const fromAccount = await this.getAssociatedTokenAccount(mint);
|
|
434
|
+
|
|
475
435
|
// Convert amount to BN with proper decimals
|
|
476
436
|
const amountBN = utilsToBN(amount, tokenInfo.precision);
|
|
477
437
|
|
|
478
|
-
//
|
|
479
|
-
|
|
438
|
+
// Create deposit parameters
|
|
439
|
+
const depositParams: DepositSplParams = {
|
|
480
440
|
amount: amountBN,
|
|
481
441
|
mint,
|
|
482
442
|
fromAccount,
|
|
483
|
-
}
|
|
484
|
-
} catch (error) {
|
|
485
|
-
throw new NordError(
|
|
486
|
-
`Failed to deposit ${amount} of token ID ${tokenId}`,
|
|
487
|
-
{ cause: error },
|
|
488
|
-
);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
443
|
+
};
|
|
491
444
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
* @throws {NordError} If required parameters are missing or operation fails
|
|
498
|
-
*/
|
|
499
|
-
async withdrawSpl(claim: any): Promise<string> {
|
|
500
|
-
if (!this.bridgeClient || !this.getSolanaPublicKey() || !this.connection) {
|
|
501
|
-
throw new NordError(
|
|
502
|
-
"Bridge client, Solana public key, and connection are required for withdrawal",
|
|
445
|
+
// Build the deposit transaction using proton client
|
|
446
|
+
const depositTx = await this.nord.protonClient.buildDepositTx(
|
|
447
|
+
depositParams,
|
|
448
|
+
this.getSolanaPublicKey(),
|
|
449
|
+
this.connection,
|
|
503
450
|
);
|
|
504
|
-
}
|
|
505
451
|
|
|
506
|
-
|
|
507
|
-
// Find the token info
|
|
508
|
-
const tokenInfo = this.splTokenInfos.find(
|
|
509
|
-
(t) => t.tokenId === claim.tokenId,
|
|
510
|
-
);
|
|
511
|
-
if (!tokenInfo) {
|
|
512
|
-
throw new NordError(`Token with ID ${claim.tokenId} not found`);
|
|
513
|
-
}
|
|
452
|
+
const { blockhash } = await this.connection.getLatestBlockhash();
|
|
514
453
|
|
|
515
|
-
|
|
454
|
+
depositTx.recentBlockhash = blockhash;
|
|
455
|
+
depositTx.feePayer = this.getSolanaPublicKey();
|
|
516
456
|
|
|
517
|
-
|
|
518
|
-
const toAccount = await this.getAssociatedTokenAccount(mint);
|
|
457
|
+
const signedTx = await this.transactionSignFn(depositTx);
|
|
519
458
|
|
|
520
|
-
//
|
|
521
|
-
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
authority,
|
|
525
|
-
true,
|
|
526
|
-
TOKEN_2022_PROGRAM_ID,
|
|
459
|
+
// TODO: should use `VersionedTransaction` and remove any for `transactionSignFn`,
|
|
460
|
+
// this is incredibly annoying to debug and i could've saved 30 mins.
|
|
461
|
+
const signature = await this.connection.sendRawTransaction(
|
|
462
|
+
signedTx.serialize(),
|
|
527
463
|
);
|
|
528
464
|
|
|
529
|
-
|
|
530
|
-
const transactionSigner = {
|
|
531
|
-
publicKey: this.getSolanaPublicKey(),
|
|
532
|
-
secretKey: new Uint8Array(64), // Dummy secret key, not actually used
|
|
533
|
-
sign: async (tx: Transaction) => {
|
|
534
|
-
const message = tx.serializeMessage();
|
|
535
|
-
await this.walletSignFn(message);
|
|
536
|
-
return tx;
|
|
537
|
-
},
|
|
538
|
-
};
|
|
539
|
-
|
|
540
|
-
// Withdraw tokens
|
|
541
|
-
return await this.bridgeClient.withdraw(
|
|
542
|
-
{
|
|
543
|
-
claim,
|
|
544
|
-
fromAccount,
|
|
545
|
-
toAccount,
|
|
546
|
-
},
|
|
547
|
-
transactionSigner as unknown as Keypair, // Type cast to satisfy the API
|
|
548
|
-
);
|
|
465
|
+
return signature;
|
|
549
466
|
} catch (error) {
|
|
550
|
-
throw new NordError(
|
|
467
|
+
throw new NordError(
|
|
468
|
+
`Failed to deposit ${amount} of token ID ${tokenId}`,
|
|
469
|
+
{ cause: error },
|
|
470
|
+
);
|
|
551
471
|
}
|
|
552
472
|
}
|
|
553
473
|
|
|
@@ -747,10 +667,13 @@ export class NordUser {
|
|
|
747
667
|
* @param amount - Amount to withdraw
|
|
748
668
|
* @throws {NordError} If the operation fails
|
|
749
669
|
*/
|
|
750
|
-
async withdraw(
|
|
670
|
+
async withdraw(
|
|
671
|
+
tokenId: number,
|
|
672
|
+
amount: number,
|
|
673
|
+
): Promise<{ actionId: bigint }> {
|
|
751
674
|
try {
|
|
752
675
|
this.checkSessionValidity();
|
|
753
|
-
await withdraw(
|
|
676
|
+
const { actionId } = await withdraw(
|
|
754
677
|
this.nord.webServerUrl,
|
|
755
678
|
this.sessionSignFn,
|
|
756
679
|
await this.nord.getTimestamp(),
|
|
@@ -762,6 +685,7 @@ export class NordUser {
|
|
|
762
685
|
amount,
|
|
763
686
|
},
|
|
764
687
|
);
|
|
688
|
+
return { actionId };
|
|
765
689
|
} catch (error) {
|
|
766
690
|
throw new NordError(
|
|
767
691
|
`Failed to withdraw ${amount} of token ID ${tokenId}`,
|
|
@@ -813,7 +737,7 @@ export class NordUser {
|
|
|
813
737
|
* Cancel an order
|
|
814
738
|
*
|
|
815
739
|
* @param orderId - Order ID to cancel
|
|
816
|
-
* @param
|
|
740
|
+
* @param providedAccountId - Account ID that placed the order
|
|
817
741
|
* @returns Action ID if successful
|
|
818
742
|
* @throws {NordError} If the operation fails
|
|
819
743
|
*/
|
|
@@ -989,7 +913,7 @@ export class NordUser {
|
|
|
989
913
|
try {
|
|
990
914
|
const tokenBalance = await this.retryWithBackoff(
|
|
991
915
|
() =>
|
|
992
|
-
this.connection
|
|
916
|
+
this.connection.getTokenAccountBalance(
|
|
993
917
|
associatedTokenAddress,
|
|
994
918
|
),
|
|
995
919
|
maxRetries,
|
|
@@ -1035,10 +959,6 @@ export class NordUser {
|
|
|
1035
959
|
* @returns The Solana public key
|
|
1036
960
|
*/
|
|
1037
961
|
getSolanaPublicKey(): PublicKey {
|
|
1038
|
-
|
|
1039
|
-
return new PublicKey(this.address);
|
|
1040
|
-
} catch (error) {
|
|
1041
|
-
throw new NordError("Invalid Solana address", { cause: error });
|
|
1042
|
-
}
|
|
962
|
+
return this.address;
|
|
1043
963
|
}
|
|
1044
964
|
}
|
|
@@ -60,11 +60,15 @@ export class NordError extends Error {
|
|
|
60
60
|
let result = `${this.name}: ${this.message}`;
|
|
61
61
|
|
|
62
62
|
if (this.statusCode) {
|
|
63
|
-
result += `
|
|
63
|
+
result += ` \nstatus: ${this.statusCode}`;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
if (this.details && Object.keys(this.details).length > 0) {
|
|
67
|
-
result +=
|
|
67
|
+
result += ` \ndetails: ${JSON.stringify(this.details, null, 2)}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (this.cause) {
|
|
71
|
+
result += ` \ncause: ${this.cause.toString()}`;
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
return result;
|